PageSourceSearch

https://topserve.ca/polyfills.js

js topserve.ca collected 2026-10-08 12:07:07 UTC 1,498,547 bytes, 39,000 lines download raw bytes

1"use strict";
2(self["webpackChunkclean_ui"] = self["webpackChunkclean_ui"] || []).push([["polyfills"],{
3
4/***/ 24050:
5/*!**************************!*\
6  !*** ./src/polyfills.ts ***!
7  \**************************/
8/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
9
10__webpack_require__.r(__webpack_exports__);
11/* harmony import */ var _angular_localize_init__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/localize/init */ 1643);
12/* harmony import */ var zone_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! zone.js */ 74124);
13/* harmony import */ var zone_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(zone_js__WEBPACK_IMPORTED_MODULE_1__);
14/***************************************************************************************************
15 * Load `$localize` onto the global scope - used if i18n tags appear in Angular templates.
16 */
17
18/**
19 * This file includes polyfills needed by Angular and is loaded before the app.
20 * You can add your own extra polyfills to this file.
21 *
22 * This file is divided into 2 sections:
23 *   1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
24 *   2. Application imports. Files imported after ZoneJS that should be loaded before your main
25 *      file.
26 *
27 * The current setup is for so-called "evergreen" browsers; the last versions of browsers that
28 * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
29 * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
30 *
31 * Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html
32 */
33/***************************************************************************************************
34 * BROWSER POLYFILLS
35 */
36/** IE9, IE10 and IE11 requires all of the following polyfills. **/
37// import 'core-js/es6/symbol';
38// import 'core-js/es6/object';
39// import 'core-js/es6/function';
40// import 'core-js/es6/parse-int';
41// import 'core-js/es6/parse-float';
42// import 'core-js/es6/number';
43// import 'core-js/es6/math';
44// import 'core-js/es6/string';
45// import 'core-js/es6/date';
46// import 'core-js/es6/array';
47// import 'core-js/es6/regexp';
48// import 'core-js/es6/map';
49// import 'core-js/es6/set';
50/** Evergreen browsers require these. **/
51window.global = window;
52/***************************************************************************************************
53 * Zone JS is required by Angular itself.
54 */
55 // Included with Angular CLI.
56/***************************************************************************************************
57 * APPLICATION IMPORTS
58 */
59/**
60 * Date, currency, decimal and percent pipes.
61 * Needed for: All but Chrome, Firefox, Edge, IE11 and Safari 10
62 */
63// import 'intl';  // Run `npm install --save intl`.
64
65/***/ }),
66
67/***/ 74124:
68/*!***********************************************!*\
69  !*** ./node_modules/zone.js/fesm2015/zone.js ***!
70  \***********************************************/
71/***/ (() => {
72
73
74
75/**
76 * @license Angular v<unknown>
77 * (c) 2010-2024 Google LLC. https://angular.io/
78 * License: MIT
79 */
80const global = globalThis;
81// __Zone_symbol_prefix global can be used to override the default zone
82// symbol prefix with a custom one if needed.
83function __symbol__(name) {
84  const symbolPrefix = global['__Zone_symbol_prefix'] || '__zone_symbol__';
85  return symbolPrefix + name;
86}
87function initZone() {
88  const performance = global['performance'];
89  function mark(name) {
90    performance && performance['mark'] && performance['mark'](name);
91  }
92  function performanceMeasure(name, label) {
93    performance && performance['measure'] && performance['measure'](name, label);
94  }
95  mark('Zone');
96  class ZoneImpl {
97    // tslint:disable-next-line:require-internal-with-underscore
98    static #_ = this.__symbol__ = __symbol__;
99    static assertZonePatched() {
100      if (global['Promise'] !== patches['ZoneAwarePromise']) {
101        throw new Error('Zone.js has detected that ZoneAwarePromise `(window|global).Promise` ' + 'has been overwritten.\n' + 'Most likely cause is that a Promise polyfill has been loaded ' + 'after Zone.js (Polyfilling Promise api is not necessary when zone.js is loaded. ' + 'If you must load one, do so before loading zone.js.)');
102      }
103    }
104    static get root() {
105      let zone = ZoneImpl.current;
106      while (zone.parent) {
107        zone = zone.parent;
108      }
109      return zone;
110    }
111    static get current() {
112      return _currentZoneFrame.zone;
113    }
114    static get currentTask() {
115      return _currentTask;
116    }
117    // tslint:disable-next-line:require-internal-with-underscore
118    static __load_patch(name, fn, ignoreDuplicate = false) {
119      if (patches.hasOwnProperty(name)) {
120        // `checkDuplicate` option is defined from global variable
121        // so it works for all modules.
122        // `ignoreDuplicate` can work for the specified module
123        const checkDuplicate = global[__symbol__('forceDuplicateZoneCheck')] === true;
124        if (!ignoreDuplicate && checkDuplicate) {
125          throw Error('Already loaded patch: ' + name);
126        }
127      } else if (!global['__Zone_disable_' + name]) {
128        const perfName = 'Zone:' + name;
129        mark(perfName);
130        patches[name] = fn(global, ZoneImpl, _api);
131        performanceMeasure(perfName, perfName);
132      }
133    }
134    get parent() {
135      return this._parent;
136    }
137    get name() {
138      return this._name;
139    }
140    constructor(parent, zoneSpec) {
141      this._parent = parent;
142      this._name = zoneSpec ? zoneSpec.name || 'unnamed' : '<root>';
143      this._properties = zoneSpec && zoneSpec.properties || {};
144      this._zoneDelegate = new _ZoneDelegate(this, this._parent && this._parent._zoneDelegate, zoneSpec);
145    }
146    get(key) {
147      const zone = this.getZoneWith(key);
148      if (zone) return zone._properties[key];
149    }
150    getZoneWith(key) {
151      let current = this;
152      while (current) {
153        if (current._properties.hasOwnProperty(key)) {
154          return current;
155        }
156        current = current._parent;
157      }
158      return null;
159    }
160    fork(zoneSpec) {
161      if (!zoneSpec) throw new Error('ZoneSpec required!');
162      return this._zoneDelegate.fork(this, zoneSpec);
163    }
164    wrap(callback, source) {
165      if (typeof callback !== 'function') {
166        throw new Error('Expecting function got: ' + callback);
167      }
168      const _callback = this._zoneDelegate.intercept(this, callback, source);
169      const zone = this;
170      return function () {
171        return zone.runGuarded(_callback, this, arguments, source);
172      };
173    }
174    run(callback, applyThis, applyArgs, source) {
175      _currentZoneFrame = {
176        parent: _currentZoneFrame,
177        zone: this
178      };
179      try {
180        return this._zoneDelegate.invoke(this, callback, applyThis, applyArgs, source);
181      } finally {
182        _currentZoneFrame = _currentZoneFrame.parent;
183      }
184    }
185    runGuarded(callback, applyThis = null, applyArgs, source) {
186      _currentZoneFrame = {
187        parent: _currentZoneFrame,
188        zone: this
189      };
190      try {
191        try {
192          return this._zoneDelegate.invoke(this, callback, applyThis, applyArgs, source);
193        } catch (error) {
194          if (this._zoneDelegate.handleError(this, error)) {
195            throw error;
196          }
197        }
198      } finally {
199        _currentZoneFrame = _currentZoneFrame.parent;
200      }
201    }
202    runTask(task, applyThis, applyArgs) {
203      if (task.zone != this) {
204        throw new Error('A task can only be run in the zone of creation! (Creation: ' + (task.zone || NO_ZONE).name + '; Execution: ' + this.name + ')');
205      }
206      // https://github.com/angular/zone.js/issues/778, sometimes eventTask
207      // will run in notScheduled(canceled) state, we should not try to
208      // run such kind of task but just return
209      if (task.state === notScheduled && (task.type === eventTask || task.type === macroTask)) {
210        return;
211      }
212      const reEntryGuard = task.state != running;
213      reEntryGuard && task._transitionTo(running, scheduled);
214      task.runCount++;
215      const previousTask = _currentTask;
216      _currentTask = task;
217      _currentZoneFrame = {
218        parent: _currentZoneFrame,
219        zone: this
220      };
221      try {
222        if (task.type == macroTask && task.data && !task.data.isPeriodic) {
223          task.cancelFn = undefined;
224        }
225        try {
226          return this._zoneDelegate.invokeTask(this, task, applyThis, applyArgs);
227        } catch (error) {
228          if (this._zoneDelegate.handleError(this, error)) {
229            throw error;
230          }
231        }
232      } finally {
233        // if the task's state is notScheduled or unknown, then it has already been cancelled
234        // we should not reset the state to scheduled
235        if (task.state !== notScheduled && task.state !== unknown) {
236          if (task.type == eventTask || task.data && task.data.isPeriodic) {
237            reEntryGuard && task._transitionTo(scheduled, running);
238          } else {
239            task.runCount = 0;
240            this._updateTaskCount(task, -1);
241            reEntryGuard && task._transitionTo(notScheduled, running, notScheduled);
242          }
243        }
244        _currentZoneFrame = _currentZoneFrame.parent;
245        _currentTask = previousTask;
246      }
247    }
248    scheduleTask(task) {
249      if (task.zone && task.zone !== this) {
250        // check if the task was rescheduled, the newZone
251        // should not be the children of the original zone
252        let newZone = this;
253        while (newZone) {
254          if (newZone === task.zone) {
255            throw Error(`can not reschedule task to ${this.name} which is descendants of the original zone ${task.zone.name}`);
256          }
257          newZone = newZone.parent;
258        }
259      }
260      task._transitionTo(scheduling, notScheduled);
261      const zoneDelegates = [];
262      task._zoneDelegates = zoneDelegates;
263      task._zone = this;
vendor: 16,542 bytes, lines 264-662
264      try {
265        task = this._zoneDelegate.scheduleTask(this, task);
266      } catch (err) {
267        // should set task's state to unknown when scheduleTask throw error
268        // because the err may from reschedule, so the fromState maybe notScheduled
269        task._transitionTo(unknown, scheduling, notScheduled);
270        // TODO: @JiaLiPassion, should we check the result from handleError?
271        this._zoneDelegate.handleError(this, err);
272        throw err;
273      }
274      if (task._zoneDelegates === zoneDelegates) {
275        // we have to check because internally the delegate can reschedule the task.
276        this._updateTaskCount(task, 1);
277      }
278      if (task.state == scheduling) {
279        task._transitionTo(scheduled, scheduling);
280      }
281      return task;
282    }
283    scheduleMicroTask(source, callback, data, customSchedule) {
284      return this.scheduleTask(new ZoneTask(microTask, source, callback, data, customSchedule, undefined));
285    }
286    scheduleMacroTask(source, callback, data, customSchedule, customCancel) {
287      return this.scheduleTask(new ZoneTask(macroTask, source, callback, data, customSchedule, customCancel));
288    }
289    scheduleEventTask(source, callback, data, customSchedule, customCancel) {
290      return this.scheduleTask(new ZoneTask(eventTask, source, callback, data, customSchedule, customCancel));
291    }
292    cancelTask(task) {
293      if (task.zone != this) throw new Error('A task can only be cancelled in the zone of creation! (Creation: ' + (task.zone || NO_ZONE).name + '; Execution: ' + this.name + ')');
294      if (task.state !== scheduled && task.state !== running) {
295        return;
296      }
297      task._transitionTo(canceling, scheduled, running);
298      try {
299        this._zoneDelegate.cancelTask(this, task);
300      } catch (err) {
301        // if error occurs when cancelTask, transit the state to unknown
302        task._transitionTo(unknown, canceling);
303        this._zoneDelegate.handleError(this, err);
304        throw err;
305      }
306      this._updateTaskCount(task, -1);
307      task._transitionTo(notScheduled, canceling);
308      task.runCount = 0;
309      return task;
310    }
311    _updateTaskCount(task, count) {
312      const zoneDelegates = task._zoneDelegates;
313      if (count == -1) {
314        task._zoneDelegates = null;
315      }
316      for (let i = 0; i < zoneDelegates.length; i++) {
317        zoneDelegates[i]._updateTaskCount(task.type, count);
318      }
319    }
320  }
321  const DELEGATE_ZS = {
322    name: '',
323    onHasTask: (delegate, _, target, hasTaskState) => delegate.hasTask(target, hasTaskState),
324    onScheduleTask: (delegate, _, target, task) => delegate.scheduleTask(target, task),
325    onInvokeTask: (delegate, _, target, task, applyThis, applyArgs) => delegate.invokeTask(target, task, applyThis, applyArgs),
326    onCancelTask: (delegate, _, target, task) => delegate.cancelTask(target, task)
327  };
328  class _ZoneDelegate {
329    get zone() {
330      return this._zone;
331    }
332    constructor(zone, parentDelegate, zoneSpec) {
333      this._taskCounts = {
334        'microTask': 0,
335        'macroTask': 0,
336        'eventTask': 0
337      };
338      this._zone = zone;
339      this._parentDelegate = parentDelegate;
340      this._forkZS = zoneSpec && (zoneSpec && zoneSpec.onFork ? zoneSpec : parentDelegate._forkZS);
341      this._forkDlgt = zoneSpec && (zoneSpec.onFork ? parentDelegate : parentDelegate._forkDlgt);
342      this._forkCurrZone = zoneSpec && (zoneSpec.onFork ? this._zone : parentDelegate._forkCurrZone);
343      this._interceptZS = zoneSpec && (zoneSpec.onIntercept ? zoneSpec : parentDelegate._interceptZS);
344      this._interceptDlgt = zoneSpec && (zoneSpec.onIntercept ? parentDelegate : parentDelegate._interceptDlgt);
345      this._interceptCurrZone = zoneSpec && (zoneSpec.onIntercept ? this._zone : parentDelegate._interceptCurrZone);
346      this._invokeZS = zoneSpec && (zoneSpec.onInvoke ? zoneSpec : parentDelegate._invokeZS);
347      this._invokeDlgt = zoneSpec && (zoneSpec.onInvoke ? parentDelegate : parentDelegate._invokeDlgt);
348      this._invokeCurrZone = zoneSpec && (zoneSpec.onInvoke ? this._zone : parentDelegate._invokeCurrZone);
349      this._handleErrorZS = zoneSpec && (zoneSpec.onHandleError ? zoneSpec : parentDelegate._handleErrorZS);
350      this._handleErrorDlgt = zoneSpec && (zoneSpec.onHandleError ? parentDelegate : parentDelegate._handleErrorDlgt);
351      this._handleErrorCurrZone = zoneSpec && (zoneSpec.onHandleError ? this._zone : parentDelegate._handleErrorCurrZone);
352      this._scheduleTaskZS = zoneSpec && (zoneSpec.onScheduleTask ? zoneSpec : parentDelegate._scheduleTaskZS);
353      this._scheduleTaskDlgt = zoneSpec && (zoneSpec.onScheduleTask ? parentDelegate : parentDelegate._scheduleTaskDlgt);
354      this._scheduleTaskCurrZone = zoneSpec && (zoneSpec.onScheduleTask ? this._zone : parentDelegate._scheduleTaskCurrZone);
355      this._invokeTaskZS = zoneSpec && (zoneSpec.onInvokeTask ? zoneSpec : parentDelegate._invokeTaskZS);
356      this._invokeTaskDlgt = zoneSpec && (zoneSpec.onInvokeTask ? parentDelegate : parentDelegate._invokeTaskDlgt);
357      this._invokeTaskCurrZone = zoneSpec && (zoneSpec.onInvokeTask ? this._zone : parentDelegate._invokeTaskCurrZone);
358      this._cancelTaskZS = zoneSpec && (zoneSpec.onCancelTask ? zoneSpec : parentDelegate._cancelTaskZS);
359      this._cancelTaskDlgt = zoneSpec && (zoneSpec.onCancelTask ? parentDelegate : parentDelegate._cancelTaskDlgt);
360      this._cancelTaskCurrZone = zoneSpec && (zoneSpec.onCancelTask ? this._zone : parentDelegate._cancelTaskCurrZone);
361      this._hasTaskZS = null;
362      this._hasTaskDlgt = null;
363      this._hasTaskDlgtOwner = null;
364      this._hasTaskCurrZone = null;
365      const zoneSpecHasTask = zoneSpec && zoneSpec.onHasTask;
366      const parentHasTask = parentDelegate && parentDelegate._hasTaskZS;
367      if (zoneSpecHasTask || parentHasTask) {
368        // If we need to report hasTask, than this ZS needs to do ref counting on tasks. In such
369        // a case all task related interceptors must go through this ZD. We can't short circuit it.
370        this._hasTaskZS = zoneSpecHasTask ? zoneSpec : DELEGATE_ZS;
371        this._hasTaskDlgt = parentDelegate;
372        this._hasTaskDlgtOwner = this;
373        this._hasTaskCurrZone = this._zone;
374        if (!zoneSpec.onScheduleTask) {
375          this._scheduleTaskZS = DELEGATE_ZS;
376          this._scheduleTaskDlgt = parentDelegate;
377          this._scheduleTaskCurrZone = this._zone;
378        }
379        if (!zoneSpec.onInvokeTask) {
380          this._invokeTaskZS = DELEGATE_ZS;
381          this._invokeTaskDlgt = parentDelegate;
382          this._invokeTaskCurrZone = this._zone;
383        }
384        if (!zoneSpec.onCancelTask) {
385          this._cancelTaskZS = DELEGATE_ZS;
386          this._cancelTaskDlgt = parentDelegate;
387          this._cancelTaskCurrZone = this._zone;
388        }
389      }
390    }
391    fork(targetZone, zoneSpec) {
392      return this._forkZS ? this._forkZS.onFork(this._forkDlgt, this.zone, targetZone, zoneSpec) : new ZoneImpl(targetZone, zoneSpec);
393    }
394    intercept(targetZone, callback, source) {
395      return this._interceptZS ? this._interceptZS.onIntercept(this._interceptDlgt, this._interceptCurrZone, targetZone, callback, source) : callback;
396    }
397    invoke(targetZone, callback, applyThis, applyArgs, source) {
398      return this._invokeZS ? this._invokeZS.onInvoke(this._invokeDlgt, this._invokeCurrZone, targetZone, callback, applyThis, applyArgs, source) : callback.apply(applyThis, applyArgs);
399    }
400    handleError(targetZone, error) {
401      return this._handleErrorZS ? this._handleErrorZS.onHandleError(this._handleErrorDlgt, this._handleErrorCurrZone, targetZone, error) : true;
402    }
403    scheduleTask(targetZone, task) {
404      let returnTask = task;
405      if (this._scheduleTaskZS) {
406        if (this._hasTaskZS) {
407          returnTask._zoneDelegates.push(this._hasTaskDlgtOwner);
408        }
409        returnTask = this._scheduleTaskZS.onScheduleTask(this._scheduleTaskDlgt, this._scheduleTaskCurrZone, targetZone, task);
410        if (!returnTask) returnTask = task;
411      } else {
412        if (task.scheduleFn) {
413          task.scheduleFn(task);
414        } else if (task.type == microTask) {
415          scheduleMicroTask(task);
416        } else {
417          throw new Error('Task is missing scheduleFn.');
418        }
419      }
420      return returnTask;
421    }
422    invokeTask(targetZone, task, applyThis, applyArgs) {
423      return this._invokeTaskZS ? this._invokeTaskZS.onInvokeTask(this._invokeTaskDlgt, this._invokeTaskCurrZone, targetZone, task, applyThis, applyArgs) : task.callback.apply(applyThis, applyArgs);
424    }
425    cancelTask(targetZone, task) {
426      let value;
427      if (this._cancelTaskZS) {
428        value = this._cancelTaskZS.onCancelTask(this._cancelTaskDlgt, this._cancelTaskCurrZone, targetZone, task);
429      } else {
430        if (!task.cancelFn) {
431          throw Error('Task is not cancelable');
432        }
433        value = task.cancelFn(task);
434      }
435      return value;
436    }
437    hasTask(targetZone, isEmpty) {
438      // hasTask should not throw error so other ZoneDelegate
439      // can still trigger hasTask callback
440      try {
441        this._hasTaskZS && this._hasTaskZS.onHasTask(this._hasTaskDlgt, this._hasTaskCurrZone, targetZone, isEmpty);
442      } catch (err) {
443        this.handleError(targetZone, err);
444      }
445    }
446    // tslint:disable-next-line:require-internal-with-underscore
447    _updateTaskCount(type, count) {
448      const counts = this._taskCounts;
449      const prev = counts[type];
450      const next = counts[type] = prev + count;
451      if (next < 0) {
452        throw new Error('More tasks executed then were scheduled.');
453      }
454      if (prev == 0 || next == 0) {
455        const isEmpty = {
456          microTask: counts['microTask'] > 0,
457          macroTask: counts['macroTask'] > 0,
458          eventTask: counts['eventTask'] > 0,
459          change: type
460        };
461        this.hasTask(this._zone, isEmpty);
462      }
463    }
464  }
465  class ZoneTask {
466    constructor(type, source, callback, options, scheduleFn, cancelFn) {
467      // tslint:disable-next-line:require-internal-with-underscore
468      this._zone = null;
469      this.runCount = 0;
470      // tslint:disable-next-line:require-internal-with-underscore
471      this._zoneDelegates = null;
472      // tslint:disable-next-line:require-internal-with-underscore
473      this._state = 'notScheduled';
474      this.type = type;
475      this.source = source;
476      this.data = options;
477      this.scheduleFn = scheduleFn;
478      this.cancelFn = cancelFn;
479      if (!callback) {
480        throw new Error('callback is not defined');
481      }
482      this.callback = callback;
483      const self = this;
484      // TODO: @JiaLiPassion options should have interface
485      if (type === eventTask && options && options.useG) {
486        this.invoke = ZoneTask.invokeTask;
487      } else {
488        this.invoke = function () {
489          return ZoneTask.invokeTask.call(global, self, this, arguments);
490        };
491      }
492    }
493    static invokeTask(task, target, args) {
494      if (!task) {
495        task = this;
496      }
497      _numberOfNestedTaskFrames++;
498      try {
499        task.runCount++;
500        return task.zone.runTask(task, target, args);
501      } finally {
502        if (_numberOfNestedTaskFrames == 1) {
503          drainMicroTaskQueue();
504        }
505        _numberOfNestedTaskFrames--;
506      }
507    }
508    get zone() {
509      return this._zone;
510    }
511    get state() {
512      return this._state;
513    }
514    cancelScheduleRequest() {
515      this._transitionTo(notScheduled, scheduling);
516    }
517    // tslint:disable-next-line:require-internal-with-underscore
518    _transitionTo(toState, fromState1, fromState2) {
519      if (this._state === fromState1 || this._state === fromState2) {
520        this._state = toState;
521        if (toState == notScheduled) {
522          this._zoneDelegates = null;
523        }
524      } else {
525        throw new Error(`${this.type} '${this.source}': can not transition to '${toState}', expecting state '${fromState1}'${fromState2 ? " or '" + fromState2 + "'" : ''}, was '${this._state}'.`);
526      }
527    }
528    toString() {
529      if (this.data && typeof this.data.handleId !== 'undefined') {
530        return this.data.handleId.toString();
531      } else {
532        return Object.prototype.toString.call(this);
533      }
534    }
535    // add toJSON method to prevent cyclic error when
536    // call JSON.stringify(zoneTask)
537    toJSON() {
538      return {
539        type: this.type,
540        state: this.state,
541        source: this.source,
542        zone: this.zone.name,
543        runCount: this.runCount
544      };
545    }
546  }
547  //////////////////////////////////////////////////////
548  //////////////////////////////////////////////////////
549  ///  MICROTASK QUEUE
550  //////////////////////////////////////////////////////
551  //////////////////////////////////////////////////////
552  const symbolSetTimeout = __symbol__('setTimeout');
553  const symbolPromise = __symbol__('Promise');
554  const symbolThen = __symbol__('then');
555  let _microTaskQueue = [];
556  let _isDrainingMicrotaskQueue = false;
557  let nativeMicroTaskQueuePromise;
558  function nativeScheduleMicroTask(func) {
559    if (!nativeMicroTaskQueuePromise) {
560      if (global[symbolPromise]) {
561        nativeMicroTaskQueuePromise = global[symbolPromise].resolve(0);
562      }
563    }
564    if (nativeMicroTaskQueuePromise) {
565      let nativeThen = nativeMicroTaskQueuePromise[symbolThen];
566      if (!nativeThen) {
567        // native Promise is not patchable, we need to use `then` directly
568        // issue 1078
569        nativeThen = nativeMicroTaskQueuePromise['then'];
570      }
571      nativeThen.call(nativeMicroTaskQueuePromise, func);
572    } else {
573      global[symbolSetTimeout](func, 0);
574    }
575  }
576  function scheduleMicroTask(task) {
577    // if we are not running in any task, and there has not been anything scheduled
578    // we must bootstrap the initial task creation by manually scheduling the drain
579    if (_numberOfNestedTaskFrames === 0 && _microTaskQueue.length === 0) {
580      // We are not running in Task, so we need to kickstart the microtask queue.
581      nativeScheduleMicroTask(drainMicroTaskQueue);
582    }
583    task && _microTaskQueue.push(task);
584  }
585  function drainMicroTaskQueue() {
586    if (!_isDrainingMicrotaskQueue) {
587      _isDrainingMicrotaskQueue = true;
588      while (_microTaskQueue.length) {
589        const queue = _microTaskQueue;
590        _microTaskQueue = [];
591        for (let i = 0; i < queue.length; i++) {
592          const task = queue[i];
593          try {
594            task.zone.runTask(task, null, null);
595          } catch (error) {
596            _api.onUnhandledError(error);
597          }
598        }
599      }
600      _api.microtaskDrainDone();
601      _isDrainingMicrotaskQueue = false;
602    }
603  }
604  //////////////////////////////////////////////////////
605  //////////////////////////////////////////////////////
606  ///  BOOTSTRAP
607  //////////////////////////////////////////////////////
608  //////////////////////////////////////////////////////
609  const NO_ZONE = {
610    name: 'NO ZONE'
611  };
612  const notScheduled = 'notScheduled',
613    scheduling = 'scheduling',
614    scheduled = 'scheduled',
615    running = 'running',
616    canceling = 'canceling',
617    unknown = 'unknown';
618  const microTask = 'microTask',
619    macroTask = 'macroTask',
620    eventTask = 'eventTask';
621  const patches = {};
622  const _api = {
623    symbol: __symbol__,
624    currentZoneFrame: () => _currentZoneFrame,
625    onUnhandledError: noop,
626    microtaskDrainDone: noop,
627    scheduleMicroTask: scheduleMicroTask,
628    showUncaughtError: () => !ZoneImpl[__symbol__('ignoreConsoleErrorUncaughtError')],
629    patchEventTarget: () => [],
630    patchOnProperties: noop,
631    patchMethod: () => noop,
632    bindArguments: () => [],
633    patchThen: () => noop,
634    patchMacroTask: () => noop,
635    patchEventPrototype: () => noop,
636    isIEOrEdge: () => false,
637    getGlobalObjects: () => undefined,
638    ObjectDefineProperty: () => noop,
639    ObjectGetOwnPropertyDescriptor: () => undefined,
640    ObjectCreate: () => undefined,
641    ArraySlice: () => [],
642    patchClass: () => noop,
643    wrapWithCurrentZone: () => noop,
644    filterProperties: () => [],
645    attachOriginToPatched: () => noop,
646    _redefineProperty: () => noop,
647    patchCallbacks: () => noop,
648    nativeScheduleMicroTask: nativeScheduleMicroTask
649  };
650  let _currentZoneFrame = {
651    parent: null,
652    zone: new ZoneImpl(null, null)
653  };
654  let _currentTask = null;
655  let _numberOfNestedTaskFrames = 0;
656  function noop() {}
657  performanceMeasure('Zone', 'Zone');
658  return ZoneImpl;
659}
660function loadZone() {
661  // if global['Zone'] already exists (maybe zone.js was already loaded or
662  // some other lib also registered a global object named Zone), we may 
662need
663  // to throw an error, but sometimes user may not want this error.
664  // For example,
665  // we have two web pages, page1 includes zone.js, page2 doesn't.
666  // and the 1st time user load page1 and page2, everything work fine,
667  // but when user load page2 again, error occurs because global['Zone'] already exists.
668  // so we add a flag to let user choose whether to throw this error or not.
669  // By default, if existing Zone is from zone.js, we will not throw the error.
670  const global = globalThis;
671  const checkDuplicate = global[__symbol__('forceDuplicateZoneCheck')] === true;
672  if (global['Zone'] && (checkDuplicate || typeof global['Zone'].__symbol__ !== 'function')) {
673    throw new Error('Zone already loaded.');
674  }
675  // Initialize global `Zone` constant.
676  global['Zone'] ??= initZone();
677  return global['Zone'];
678}
679
680/**
681 * Suppress closure compiler errors about unknown 'Zone' variable
682 * @fileoverview
683 * @suppress {undefinedVars,globalThis,missingRequire}
684 */
685// issue #989, to reduce bundle size, use short name
686/** Object.getOwnPropertyDescriptor */
687const ObjectGetOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
688/** Object.defineProperty */
689const ObjectDefineProperty = Object.defineProperty;
690/** Object.getPrototypeOf */
691const ObjectGetPrototypeOf = Object.getPrototypeOf;
692/** Object.create */
693const ObjectCreate = Object.create;
694/** Array.prototype.slice */
695const ArraySlice = Array.prototype.slice;
696/** addEventListener string const */
697const ADD_EVENT_LISTENER_STR = 'addEventListener';
698/** removeEventListener string const */
699const REMOVE_EVENT_LISTENER_STR = 'removeEventListener';
700/** zoneSymbol addEventListener */
701const ZONE_SYMBOL_ADD_EVENT_LISTENER = __symbol__(ADD_EVENT_LISTENER_STR);
702/** zoneSymbol removeEventListener */
703const ZONE_SYMBOL_REMOVE_EVENT_LISTENER = __symbol__(REMOVE_EVENT_LISTENER_STR);
704/** true string const */
705const TRUE_STR = 'true';
706/** false string const */
707const FALSE_STR = 'false';
708/** Zone symbol prefix string const. */
709const ZONE_SYMBOL_PREFIX = __symbol__('');
710function wrapWithCurrentZone(callback, source) {
711  return Zone.current.wrap(callback, source);
712}
713function scheduleMacroTaskWithCurrentZone(source, callback, data, customSchedule, customCancel) {
714  return Zone.current.scheduleMacroTask(source, callback, data, customSchedule, customCancel);
715}
716const zoneSymbol = __symbol__;
717const isWindowExists = typeof window !== 'undefined';
718const internalWindow = isWindowExists ? window : undefined;
719const _global = isWindowExists && internalWindow || globalThis;
720const REMOVE_ATTRIBUTE = 'removeAttribute';
721function bindArguments(args, source) {
722  for (let i = args.length - 1; i >= 0; i--) {
723    if (typeof args[i] === 'function') {
724      args[i] = wrapWithCurrentZone(args[i], source + '_' + i);
725    }
726  }
727  return args;
728}
729function patchPrototype(prototype, fnNames) {
730  const source = prototype.constructor['name'];
731  for (let i = 0; i < fnNames.length; i++) {
732    const name = fnNames[i];
733    const delegate = prototype[name];
734    if (delegate) {
735      const prototypeDesc = ObjectGetOwnPropertyDescriptor(prototype, name);
736      if (!isPropertyWritable(prototypeDesc)) {
737        continue;
738      }
739      prototype[name] = (delegate => {
740        const patched = function () {
741          return delegate.apply(this, bindArguments(arguments, source + '.' + name));
742        };
743        attachOriginToPatched(patched, delegate);
744        return patched;
745      })(delegate);
746    }
747  }
748}
749function isPropertyWritable(propertyDesc) {
750  if (!propertyDesc) {
751    return true;
752  }
753  if (propertyDesc.writable === false) {
754    return false;
755  }
756  return !(typeof propertyDesc.get === 'function' && typeof propertyDesc.set === 'undefined');
757}
758const isWebWorker = typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope;
759// Make sure to access `process` through `_global` so that WebPack does not accidentally browserify
760// this code.
761const isNode = !('nw' in _global) && typeof _global.process !== 'undefined' && _global.process.toString() === '[object process]';
762const isBrowser = !isNode && !isWebWorker && !!(isWindowExists && internalWindow['HTMLElement']);
763// we are in electron of nw, so we are both browser and nodejs
764// Make sure to access `process` through `_global` so that WebPack does not accidentally browserify
765// this code.
766const isMix = typeof _global.process !== 'undefined' && _global.process.toString() === '[object process]' && !isWebWorker && !!(isWindowExists && internalWindow['HTMLElement']);
767const zoneSymbolEventNames$1 = {};
768const wrapFn = function (event) {
769  // https://github.com/angular/zone.js/issues/911, in IE, sometimes
770  // event will be undefined, so we need to use window.event
771  event = event || _global.event;
772  if (!event) {
773    return;
774  }
775  let eventNameSymbol = zoneSymbolEventNames$1[event.type];
776  if (!eventNameSymbol) {
777    eventNameSymbol = zoneSymbolEventNames$1[event.type] = zoneSymbol('ON_PROPERTY' + event.type);
778  }
779  const target = this || event.target || _global;
780  const listener = target[eventNameSymbol];
781  let result;
782  if (isBrowser && target === internalWindow && event.type === 'error') {
783    // window.onerror have different signature
784    // https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onerror#window.onerror
785    // and onerror callback will prevent default when callback return true
786    const errorEvent = event;
787    result = listener && listener.call(this, errorEvent.message, errorEvent.filename, errorEvent.lineno, errorEvent.colno, errorEvent.error);
788    if (result === true) {
789      event.preventDefault();
790    }
791  } else {
792    result = listener && listener.apply(this, arguments);
793    if (result != undefined && !result) {
794      event.preventDefault();
795    }
796  }
797  return result;
798};
799function patchProperty(obj, prop, prototype) {
800  let desc = ObjectGetOwnPropertyDescriptor(obj, prop);
801  if (!desc && prototype) {
802    // when patch window object, use prototype to check prop exist or not
vendor: 36,293 bytes, lines 803-1702
803    const prototypeDesc = ObjectGetOwnPropertyDescriptor(prototype, prop);
804    if (prototypeDesc) {
805      desc = {
806        enumerable: true,
807        configurable: true
808      };
809    }
810  }
811  // if the descriptor not exists or is not configurable
812  // just return
813  if (!desc || !desc.configurable) {
814    return;
815  }
816  const onPropPatchedSymbol = zoneSymbol('on' + prop + 'patched');
817  if (obj.hasOwnProperty(onPropPatchedSymbol) && obj[onPropPatchedSymbol]) {
818    return;
819  }
820  // A property descriptor cannot have getter/setter and be writable
821  // deleting the writable and value properties avoids this error:
822  //
823  // TypeError: property descriptors must not specify a value or be writable when a
824  // getter or setter has been specified
825  delete desc.writable;
826  delete desc.value;
827  const originalDescGet = desc.get;
828  const originalDescSet = desc.set;
829  // slice(2) cuz 'onclick' -> 'click', etc
830  const eventName = prop.slice(2);
831  let eventNameSymbol = zoneSymbolEventNames$1[eventName];
832  if (!eventNameSymbol) {
833    eventNameSymbol = zoneSymbolEventNames$1[eventName] = zoneSymbol('ON_PROPERTY' + eventName);
834  }
835  desc.set = function (newValue) {
836    // in some of windows's onproperty callback, this is undefined
837    // so we need to check it
838    let target = this;
839    if (!target && obj === _global) {
840      target = _global;
841    }
842    if (!target) {
843      return;
844    }
845    const previousValue = target[eventNameSymbol];
846    if (typeof previousValue === 'function') {
847      target.removeEventListener(eventName, wrapFn);
848    }
849    // issue #978, when onload handler was added before loading zone.js
850    // we should remove it with originalDescSet
851    originalDescSet && originalDescSet.call(target, null);
852    target[eventNameSymbol] = newValue;
853    if (typeof newValue === 'function') {
854      target.addEventListener(eventName, wrapFn, false);
855    }
856  };
857  // The getter would return undefined for unassigned properties but the default value of an
858  // unassigned property is null
859  desc.get = function () {
860    // in some of windows's onproperty callback, this is undefined
861    // so we need to check it
862    let target = this;
863    if (!target && obj === _global) {
864      target = _global;
865    }
866    if (!target) {
867      return null;
868    }
869    const listener = target[eventNameSymbol];
870    if (listener) {
871      return listener;
872    } else if (originalDescGet) {
873      // result will be null when use inline event attribute,
874      // such as <button onclick="func();">OK</button>
875      // because the onclick function is internal raw uncompiled handler
876      // the onclick will be evaluated when first time event was triggered or
877      // the property is accessed, https://github.com/angular/zone.js/issues/525
878      // so we should use original native get to retrieve the handler
879      let value = originalDescGet.call(this);
880      if (value) {
881        desc.set.call(this, value);
882        if (typeof target[REMOVE_ATTRIBUTE] === 'function') {
883          target.removeAttribute(prop);
884        }
885        return value;
886      }
887    }
888    return null;
889  };
890  ObjectDefineProperty(obj, prop, desc);
891  obj[onPropPatchedSymbol] = true;
892}
893function patchOnProperties(obj, properties, prototype) {
894  if (properties) {
895    for (let i = 0; i < properties.length; i++) {
896      patchProperty(obj, 'on' + properties[i], prototype);
897    }
898  } else {
899    const onProperties = [];
900    for (const prop in obj) {
901      if (prop.slice(0, 2) == 'on') {
902        onProperties.push(prop);
903      }
904    }
905    for (let j = 0; j < onProperties.length; j++) {
906      patchProperty(obj, onProperties[j], prototype);
907    }
908  }
909}
910const originalInstanceKey = zoneSymbol('originalInstance');
911// wrap some native API on `window`
912function patchClass(className) {
913  const OriginalClass = _global[className];
914  if (!OriginalClass) return;
915  // keep original class in global
916  _global[zoneSymbol(className)] = OriginalClass;
917  _global[className] = function () {
918    const a = bindArguments(arguments, className);
919    switch (a.length) {
920      case 0:
921        this[originalInstanceKey] = new OriginalClass();
922        break;
923      case 1:
924        this[originalInstanceKey] = new OriginalClass(a[0]);
925        break;
926      case 2:
927        this[originalInstanceKey] = new OriginalClass(a[0], a[1]);
928        break;
929      case 3:
930        this[originalInstanceKey] = new OriginalClass(a[0], a[1], a[2]);
931        break;
932      case 4:
933        this[originalInstanceKey] = new OriginalClass(a[0], a[1], a[2], a[3]);
934        break;
935      default:
936        throw new Error('Arg list too long.');
937    }
938  };
939  // attach original delegate to patched function
940  attachOriginToPatched(_global[className], OriginalClass);
941  const instance = new OriginalClass(function () {});
942  let prop;
943  for (prop in instance) {
944    // https://bugs.webkit.org/show_bug.cgi?id=44721
945    if (className === 'XMLHttpRequest' && prop === 'responseBlob') continue;
946    (function (prop) {
947      if (typeof instance[prop] === 'function') {
948        _global[className].prototype[prop] = function () {
949          return this[originalInstanceKey][prop].apply(this[originalInstanceKey], arguments);
950        };
951      } else {
952        ObjectDefineProperty(_global[className].prototype, prop, {
953          set: function (fn) {
954            if (typeof fn === 'function') {
955              this[originalInstanceKey][prop] = wrapWithCurrentZone(fn, className + '.' + prop);
956              // keep callback in wrapped function so we can
957              // use it in Function.prototype.toString to return
958              // the native one.
959              attachOriginToPatched(this[originalInstanceKey][prop], fn);
960            } else {
961              this[originalInstanceKey][prop] = fn;
962            }
963          },
964          get: function () {
965            return this[originalInstanceKey][prop];
966          }
967        });
968      }
969    })(prop);
970  }
971  for (prop in OriginalClass) {
972    if (prop !== 'prototype' && OriginalClass.hasOwnProperty(prop)) {
973      _global[className][prop] = OriginalClass[prop];
974    }
975  }
976}
977function patchMethod(target, name, patchFn) {
978  let proto = target;
979  while (proto && !proto.hasOwnProperty(name)) {
980    proto = ObjectGetPrototypeOf(proto);
981  }
982  if (!proto && target[name]) {
983    // somehow we did not find it, but we can see it. This happens on IE for Window properties.
984    proto = target;
985  }
986  const delegateName = zoneSymbol(name);
987  let delegate = null;
988  if (proto && (!(delegate = proto[delegateName]) || !proto.hasOwnProperty(delegateName))) {
989    delegate = proto[delegateName] = proto[name];
990    // check whether proto[name] is writable
991    // some property is readonly in safari, such as HtmlCanvasElement.prototype.toBlob
992    const desc = proto && ObjectGetOwnPropertyDescriptor(proto, name);
993    if (isPropertyWritable(desc)) {
994      const patchDelegate = patchFn(delegate, delegateName, name);
995      proto[name] = function () {
996        return patchDelegate(this, arguments);
997      };
998      attachOriginToPatched(proto[name], delegate);
999    }
1000  }
1001  return delegate;
1002}
1003// TODO: @JiaLiPassion, support cancel task later if necessary
1004function patchMacroTask(obj, funcName, metaCreator) {
1005  let setNative = null;
1006  function scheduleTask(task) {
1007    const data = task.data;
1008    data.args[data.cbIdx] = function () {
1009      task.invoke.apply(this, arguments);
1010    };
1011    setNative.apply(data.target, data.args);
1012    return task;
1013  }
1014  setNative = patchMethod(obj, funcName, delegate => function (self, args) {
1015    const meta = metaCreator(self, args);
1016    if (meta.cbIdx >= 0 && typeof args[meta.cbIdx] === 'function') {
1017      return scheduleMacroTaskWithCurrentZone(meta.name, args[meta.cbIdx], meta, scheduleTask);
1018    } else {
1019      // cause an error by calling it directly.
1020      return delegate.apply(self, args);
1021    }
1022  });
1023}
1024function attachOriginToPatched(patched, original) {
1025  patched[zoneSymbol('OriginalDelegate')] = original;
1026}
1027let isDetectedIEOrEdge = false;
1028let ieOrEdge = false;
1029function isIE() {
1030  try {
1031    const ua = internalWindow.navigator.userAgent;
1032    if (ua.indexOf('MSIE ') !== -1 || ua.indexOf('Trident/') !== -1) {
1033      return true;
1034    }
1035  } catch (error) {}
1036  return false;
1037}
1038function isIEOrEdge() {
1039  if (isDetectedIEOrEdge) {
1040    return ieOrEdge;
1041  }
1042  isDetectedIEOrEdge = true;
1043  try {
1044    const ua = internalWindow.navigator.userAgent;
1045    if (ua.indexOf('MSIE ') !== -1 || ua.indexOf('Trident/') !== -1 || ua.indexOf('Edge/') !== -1) {
1046      ieOrEdge = true;
1047    }
1048  } catch (error) {}
1049  return ieOrEdge;
1050}
1051
1052/**
1053 * @fileoverview
1054 * @suppress {missingRequire}
1055 */
1056let passiveSupported = false;
1057if (typeof window !== 'undefined') {
1058  try {
1059    const options = Object.defineProperty({}, 'passive', {
1060      get: function () {
1061        passiveSupported = true;
1062      }
1063    });
1064    // Note: We pass the `options` object as the event handler too. This is not compatible with the
1065    // signature of `addEventListener` or `removeEventListener` but enables us to remove the handler
1066    // without an actual handler.
1067    window.addEventListener('test', options, options);
1068    window.removeEventListener('test', options, options);
1069  } catch (err) {
1070    passiveSupported = false;
1071  }
1072}
1073// an identifier to tell ZoneTask do not create a new invoke closure
1074const OPTIMIZED_ZONE_EVENT_TASK_DATA = {
1075  useG: true
1076};
1077const zoneSymbolEventNames = {};
1078const globalSources = {};
1079const EVENT_NAME_SYMBOL_REGX = new RegExp('^' + ZONE_SYMBOL_PREFIX + '(\\w+)(true|false)$');
1080const IMMEDIATE_PROPAGATION_SYMBOL = zoneSymbol('propagationStopped');
1081function prepareEventNames(eventName, eventNameToString) {
1082  const falseEventName = (eventNameToString ? eventNameToString(eventName) : eventName) + FALSE_STR;
1083  const trueEventName = (eventNameToString ? eventNameToString(eventName) : eventName) + TRUE_STR;
1084  const symbol = ZONE_SYMBOL_PREFIX + falseEventName;
1085  const symbolCapture = ZONE_SYMBOL_PREFIX + trueEventName;
1086  zoneSymbolEventNames[eventName] = {};
1087  zoneSymbolEventNames[eventName][FALSE_STR] = symbol;
1088  zoneSymbolEventNames[eventName][TRUE_STR] = symbolCapture;
1089}
1090function patchEventTarget(_global, api, apis, patchOptions) {
1091  const ADD_EVENT_LISTENER = patchOptions && patchOptions.add || ADD_EVENT_LISTENER_STR;
1092  const REMOVE_EVENT_LISTENER = patchOptions && patchOptions.rm || REMOVE_EVENT_LISTENER_STR;
1093  const LISTENERS_EVENT_LISTENER = patchOptions && patchOptions.listeners || 'eventListeners';
1094  const REMOVE_ALL_LISTENERS_EVENT_LISTENER = patchOptions && patchOptions.rmAll || 'removeAllListeners';
1095  const zoneSymbolAddEventListener = zoneSymbol(ADD_EVENT_LISTENER);
1096  const ADD_EVENT_LISTENER_SOURCE = '.' + ADD_EVENT_LISTENER + ':';
1097  const PREPEND_EVENT_LISTENER = 'prependListener';
1098  const PREPEND_EVENT_LISTENER_SOURCE = '.' + PREPEND_EVENT_LISTENER + ':';
1099  const invokeTask = function (task, target, event) {
1100    // for better performance, check isRemoved which is set
1101    // by removeEventListener
1102    if (task.isRemoved) {
1103      return;
1104    }
1105    const delegate = task.callback;
1106    if (typeof delegate === 'object' && delegate.handleEvent) {
1107      // create the bind version of handleEvent when invoke
1108      task.callback = event => delegate.handleEvent(event);
1109      task.originalDelegate = delegate;
1110    }
1111    // invoke static task.invoke
1112    // need to try/catch error here, otherwise, the error in one event listener
1113    // will break the executions of the other event listeners. Also error will
1114    // not remove the event listener when `once` options is true.
1115    let error;
1116    try {
1117      task.invoke(task, target, [event]);
1118    } catch (err) {
1119      error = err;
1120    }
1121    const options = task.options;
1122    if (options && typeof options === 'object' && options.once) {
1123      // if options.once is true, after invoke once remove listener here
1124      // only browser need to do this, nodejs eventEmitter will cal removeListener
1125      // inside EventEmitter.once
1126      const delegate = task.originalDelegate ? task.originalDelegate : task.callback;
1127      target[REMOVE_EVENT_LISTENER].call(target, event.type, delegate, options);
1128    }
1129    return error;
1130  };
1131  function globalCallback(context, event, isCapture) {
1132    // https://github.com/angular/zone.js/issues/911, in IE, sometimes
1133    // event will be undefined, so we need to use window.event
1134    event = event || _global.event;
1135    if (!event) {
1136      return;
1137    }
1138    // event.target is needed for Samsung TV and SourceBuffer
1139    // || global is needed https://github.com/angular/zone.js/issues/190
1140    const target = context || event.target || _global;
1141    const tasks = target[zoneSymbolEventNames[event.type][isCapture ? TRUE_STR : FALSE_STR]];
1142    if (tasks) {
1143      const errors = [];
1144      // invoke all tasks which attached to current target with given event.type and capture = false
1145      // for performance concern, if task.length === 1, just invoke
1146      if (tasks.length === 1) {
1147        const err = invokeTask(tasks[0], target, event);
1148        err && errors.push(err);
1149      } else {
1150        // https://github.com/angular/zone.js/issues/836
1151        // copy the tasks array before invoke, to avoid
1152        // the callback will remove itself or other listener
1153        const copyTasks = tasks.slice();
1154        for (let i = 0; i < copyTasks.length; i++) {
1155          if (event && event[IMMEDIATE_PROPAGATION_SYMBOL] === true) {
1156            break;
1157          }
1158          const err = invokeTask(copyTasks[i], target, event);
1159          err && errors.push(err);
1160        }
1161      }
1162      // Since there is only one error, we don't need to schedule microTask
1163      // to throw the error.
1164      if (errors.length === 1) {
1165        throw errors[0];
1166      } else {
1167        for (let i = 0; i < errors.length; i++) {
1168          const err = errors[i];
1169          api.nativeScheduleMicroTask(() => {
1170            throw err;
1171          });
1172        }
1173      }
1174    }
1175  }
1176  // global shared zoneAwareCallback to handle all event callback with capture = false
1177  const globalZoneAwareCallback = function (event) {
1178    return globalCallback(this, event, false);
1179  };
1180  // global shared zoneAwareCallback to handle all event callback with capture = true
1181  const globalZoneAwareCaptureCallback = function (event) {
1182    return globalCallback(this, event, true);
1183  };
1184  function patchEventTargetMethods(obj, patchOptions) {
1185    if (!obj) {
1186      return false;
1187    }
1188    let useGlobalCallback = true;
1189    if (patchOptions && patchOptions.useG !== undefined) {
1190      useGlobalCallback = patchOptions.useG;
1191    }
1192    const validateHandler = patchOptions && patchOptions.vh;
1193    let checkDuplicate = true;
1194    if (patchOptions && patchOptions.chkDup !== undefined) {
1195      checkDuplicate = patchOptions.chkDup;
1196    }
1197    let returnTarget = false;
1198    if (patchOptions && patchOptions.rt !== undefined) {
1199      returnTarget = patchOptions.rt;
1200    }
1201    let proto = obj;
1202    while (proto && !proto.hasOwnProperty(ADD_EVENT_LISTENER)) {
1203      proto = ObjectGetPrototypeOf(proto);
1204    }
1205    if (!proto && obj[ADD_EVENT_LISTENER]) {
1206      // somehow we did not find it, but we can see it. This happens on IE for Window properties.
1207      proto = obj;
1208    }
1209    if (!proto) {
1210      return false;
1211    }
1212    if (proto[zoneSymbolAddEventListener]) {
1213      return false;
1214    }
1215    const eventNameToString = patchOptions && patchOptions.eventNameToString;
1216    // a shared global taskData to pass data for scheduleEventTask
1217    // so we do not need to create a new object just for pass some data
1218    const taskData = {};
1219    const nativeAddEventListener = proto[zoneSymbolAddEventListener] = proto[ADD_EVENT_LISTENER];
1220    const nativeRemoveEventListener = proto[zoneSymbol(REMOVE_EVENT_LISTENER)] = proto[REMOVE_EVENT_LISTENER];
1221    const nativeListeners = proto[zoneSymbol(LISTENERS_EVENT_LISTENER)] = proto[LISTENERS_EVENT_LISTENER];
1222    const nativeRemoveAllListeners = proto[zoneSymbol(REMOVE_ALL_LISTENERS_EVENT_LISTENER)] = proto[REMOVE_ALL_LISTENERS_EVENT_LISTENER];
1223    let nativePrependEventListener;
1224    if (patchOptions && patchOptions.prepend) {
1225      nativePrependEventListener = proto[zoneSymbol(patchOptions.prepend)] = proto[patchOptions.prepend];
1226    }
1227    /**
1228     * This util function will build an option object with passive option
1229     * to handle all possible input from the user.
1230     */
1231    function buildEventListenerOptions(options, passive) {
1232      if (!passiveSupported && typeof options === 'object' && options) {
1233        // doesn't support passive but user want to pass an object as options.
1234        // this will not work on some old browser, so we just pass a boolean
1235        // as useCapture parameter
1236        return !!options.capture;
1237      }
1238      if (!passiveSupported || !passive) {
1239        return options;
1240      }
1241      if (typeof options === 'boolean') {
1242        return {
1243          capture: options,
1244          passive: true
1245        };
1246      }
1247      if (!options) {
1248        return {
1249          passive: true
1250        };
1251      }
1252      if (typeof options === 'object' && options.passive !== false) {
1253        return {
1254          ...options,
1255          passive: true
1256        };
1257      }
1258      return options;
1259    }
1260    const customScheduleGlobal = function (task) {
1261      // if there is already a task for the eventName + capture,
1262      // just return, because we use the shared globalZoneAwareCallback here.
1263      if (taskData.isExisting) {
1264        return;
1265      }
1266      return nativeAddEventListener.call(taskData.target, taskData.eventName, taskData.capture ? globalZoneAwareCaptureCallback : globalZoneAwareCallback, taskData.options);
1267    };
1268    const customCancelGlobal = function (task) {
1269      // if task is not marked as isRemoved, this call is directly
1270      // from Zone.prototype.cancelTask, we should remove the task
1271      // from tasksList of target first
1272      if (!task.isRemoved) {
1273        const symbolEventNames = zoneSymbolEventNames[task.eventName];
1274        let symbolEventName;
1275        if (symbolEventNames) {
1276          symbolEventName = symbolEventNames[task.capture ? TRUE_STR : FALSE_STR];
1277        }
1278        const existingTasks = symbolEventName && task.target[symbolEventName];
1279        if (existingTasks) {
1280          for (let i = 0; i < existingTasks.length; i++) {
1281            const existingTask = existingTasks[i];
1282            if (existingTask === task) {
1283              existingTasks.splice(i, 1);
1284              // set isRemoved to data for faster invokeTask check
1285              task.isRemoved = true;
1286              if (existingTasks.length === 0) {
1287                // all tasks for the eventName + capture have gone,
1288                // remove globalZoneAwareCallback and remove the task cache from target
1289                task.allRemoved = true;
1290                task.target[symbolEventName] = null;
1291              }
1292              break;
1293            }
1294          }
1295        }
1296      }
1297      // if all tasks for the eventName + capture have gone,
1298      // we will really remove the global event callback,
1299      // if not, return
1300      if (!task.allRemoved) {
1301        return;
1302      }
1303      return nativeRemoveEventListener.call(task.target, task.eventName, task.capture ? globalZoneAwareCaptureCallback : globalZoneAwareCallback, task.options);
1304    };
1305    const customScheduleNonGlobal = function (task) {
1306      return nativeAddEventListener.call(taskData.target, taskData.eventName, task.invoke, taskData.options);
1307    };
1308    const customSchedulePrepend = function (task) {
1309      return nativePrependEventListener.call(taskData.target, taskData.eventName, task.invoke, taskData.options);
1310    };
1311    const customCancelNonGlobal = function (task) {
1312      return nativeRemoveEventListener.call(task.target, task.eventName, task.invoke, task.options);
1313    };
1314    const customSchedule = useGlobalCallback ? customScheduleGlobal : customScheduleNonGlobal;
1315    const customCancel = useGlobalCallback ? customCancelGlobal : customCancelNonGlobal;
1316    const compareTaskCallbackVsDelegate = function (task, delegate) {
1317      const typeOfDelegate = typeof delegate;
1318      return typeOfDelegate === 'function' && task.callback === delegate || typeOfDelegate === 'object' && task.originalDelegate === delegate;
1319    };
1320    const compare = patchOptions && patchOptions.diff ? patchOptions.diff : compareTaskCallbackVsDelegate;
1321    const unpatchedEvents = Zone[zoneSymbol('UNPATCHED_EVENTS')];
1322    const passiveEvents = _global[zoneSymbol('PASSIVE_EVENTS')];
1323    const makeAddListener = function (nativeListener, addSource, customScheduleFn, customCancelFn, returnTarget = false, prepend = false) {
1324      return function () {
1325        const target = this || _global;
1326        let eventName = arguments[0];
1327        if (patchOptions && patchOptions.transferEventName) {
1328          eventName = patchOptions.transferEventName(eventName);
1329        }
1330        let delegate = arguments[1];
1331        if (!delegate) {
1332          return nativeListener.apply(this, arguments);
1333        }
1334        if (isNode && eventName === 'uncaughtException') {
1335          // don't patch uncaughtException of nodejs to prevent endless loop
1336          return nativeListener.apply(this, arguments);
1337        }
1338        // don't create the bind delegate function for handleEvent
1339        // case here to improve addEventListener performance
1340        // we will create the bind delegate when invoke
1341        let isHandleEvent = false;
1342        if (typeof delegate !== 'function') {
1343          if (!delegate.handleEvent) {
1344            return nativeListener.apply(this, arguments);
1345          }
1346          isHandleEvent = true;
1347        }
1348        if (validateHandler && !validateHandler(nativeListener, delegate, target, arguments)) {
1349          return;
1350        }
1351        const passive = passiveSupported && !!passiveEvents && passiveEvents.indexOf(eventName) !== -1;
1352        const options = buildEventListenerOptions(arguments[2], passive);
1353        const signal = options?.signal;
1354        if (signal?.aborted) {
1355          // the signal is an aborted one, just return without attaching the event listener.
1356          return;
1357        }
1358        if (unpatchedEvents) {
1359          // check unpatched list
1360          for (let i = 0; i < unpatchedEvents.length; i++) {
1361            if (eventName === unpatchedEvents[i]) {
1362              if (passive) {
1363                return nativeListener.call(target, eventName, delegate, options);
1364              } else {
1365                return nativeListener.apply(this, arguments);
1366              }
1367            }
1368          }
1369        }
1370        const capture = !options ? false : typeof options === 'boolean' ? true : options.capture;
1371        const once = options && typeof options === 'object' ? options.once : false;
1372        const zone = Zone.current;
1373        let symbolEventNames = zoneSymbolEventNames[eventName];
1374        if (!symbolEventNames) {
1375          prepareEventNames(eventName, eventNameToString);
1376          symbolEventNames = zoneSymbolEventNames[eventName];
1377        }
1378        const symbolEventName = symbolEventNames[capture ? TRUE_STR : FALSE_STR];
1379        let existingTasks = target[symbolEventName];
1380        let isExisting = false;
1381        if (existingTasks) {
1382          // already have task registered
1383          isExisting = true;
1384          if (checkDuplicate) {
1385            for (let i = 0; i < existingTasks.length; i++) {
1386              if (compare(existingTasks[i], delegate)) {
1387                // same callback, same capture, same event name, just return
1388                return;
1389              }
1390            }
1391          }
1392        } else {
1393          existingTasks = target[symbolEventName] = [];
1394        }
1395        let source;
1396        const constructorName = target.constructor['name'];
1397        const targetSource = globalSources[constructorName];
1398        if (targetSource) {
1399          source = targetSource[eventName];
1400        }
1401        if (!source) {
1402          source = constructorName + addSource + (eventNameToString ? eventNameToString(eventName) : eventName);
1403        }
1404        // do not create a new object as task.data to pass those things
1405        // just use the global shared one
1406        taskData.options = options;
1407        if (once) {
1408          // if addEventListener with once options, we don't pass it to
1409          // native addEventListener, instead we keep the once setting
1410          // and handle ourselves.
1411          taskData.options.once = false;
1412        }
1413        taskData.target = target;
1414        taskData.capture = capture;
1415        taskData.eventName = eventName;
1416        taskData.isExisting = isExisting;
1417        const data = useGlobalCallback ? OPTIMIZED_ZONE_EVENT_TASK_DATA : undefined;
1418        // keep taskData into data to allow onScheduleEventTask to access the task information
1419        if (data) {
1420          data.taskData = taskData;
1421        }
1422        if (signal) {
1423          // if addEventListener with signal options, we don't pass it to
1424          // native addEventListener, instead we keep the signal setting
1425          // and handle ourselves.
1426          taskData.options.signal = undefined;
1427        }
1428        const task = zone.scheduleEventTask(source, delegate, data, customScheduleFn, customCancelFn);
1429        if (signal) {
1430          // after task is scheduled, we need to store the signal back to task.options
1431          taskData.options.signal = signal;
1432          // Wrapping `task` in a weak reference would not prevent memory leaks. Weak references are
1433          // primarily used for preventing strong references cycles. `onAbort` is always reachable
1434          // as it's an event listener, so its closure retains a strong reference to the `task`.
1435          const onAbort = () => task.zone.cancelTask(task);
1436          nativeListener.call(signal, 'abort', onAbort, {
1437            once: true
1438          });
1439          // We need to remove the `abort` listener when the event listener is going to be removed,
1440          // as it creates a closure that captures `task`. This closure retains a reference to the
1441          // `task` object even after it goes out of scope, preventing `task` from being garbage
1442          // collected.
1443          if (data) {
1444            data.removeAbortListener = () => signal.removeEventListener('abort', onAbort);
1445          }
1446        }
1447        // should clear taskData.target to avoid memory leak
1448        // issue, https://github.com/angular/angular/issues/20442
1449        taskData.target = null;
1450        // need to clear up taskData because it is a global object
1451        if (data) {
1452          data.taskData = null;
1453        }
1454        // have to save those information to task in case
1455        // application may call task.zone.cancelTask() directly
1456        if (once) {
1457          options.once = true;
1458        }
1459        if (!(!passiveSupported && typeof task.options === 'boolean')) {
1460          // if not support passive, and we pass an option object
1461          // to addEventListener, we should save the options to task
1462          task.options = options;
1463        }
1464        task.target = target;
1465        task.capture = capture;
1466        task.eventName = eventName;
1467        if (isHandleEvent) {
1468          // save original delegate for compare to check duplicate
1469          task.originalDelegate = delegate;
1470        }
1471        if (!prepend) {
1472          existingTasks.push(task);
1473        } else {
1474          existingTasks.unshift(task);
1475        }
1476        if (returnTarget) {
1477          return target;
1478        }
1479      };
1480    };
1481    proto[ADD_EVENT_LISTENER] = makeAddListener(nativeAddEventListener, ADD_EVENT_LISTENER_SOURCE, customSchedule, customCancel, returnTarget);
1482    if (nativePrependEventListener) {
1483      proto[PREPEND_EVENT_LISTENER] = makeAddListener(nativePrependEventListener, PREPEND_EVENT_LISTENER_SOURCE, customSchedulePrepend, customCancel, returnTarget, true);
1484    }
1485    proto[REMOVE_EVENT_LISTENER] = function () {
1486      const target = this || _global;
1487      let eventName = arguments[0];
1488      if (patchOptions && patchOptions.transferEventName) {
1489        eventName = patchOptions.transferEventName(eventName);
1490      }
1491      const options = arguments[2];
1492      const capture = !options ? false : typeof options === 'boolean' ? true : options.capture;
1493      const delegate = arguments[1];
1494      if (!delegate) {
1495        return nativeRemoveEventListener.apply(this, arguments);
1496      }
1497      if (validateHandler && !validateHandler(nativeRemoveEventListener, delegate, target, arguments)) {
1498        return;
1499      }
1500      const symbolEventNames = zoneSymbolEventNames[eventName];
1501      let symbolEventName;
1502      if (symbolEventNames) {
1503        symbolEventName = symbolEventNames[capture ? TRUE_STR : FALSE_STR];
1504      }
1505      const existingTasks = symbolEventName && target[symbolEventName];
1506      if (existingTasks) {
1507        for (let i = 0; i < existingTasks.length; i++) {
1508          const existingTask = existingTasks[i];
1509          if (compare(existingTask, delegate)) {
1510            existingTasks.splice(i, 1);
1511            // set isRemoved to data for faster invokeTask check
1512            existingTask.isRemoved = true;
1513            if (existingTasks.length === 0) {
1514              // all tasks for the eventName + capture have gone,
1515              // remove globalZoneAwareCallback and remove the task cache from target
1516              existingTask.allRemoved = true;
1517              target[symbolEventName] = null;
1518              // in the target, we have an event listener which is added by on_property
1519              // such as target.onclick = function() {}, so we need to clear this internal
1520              // property too if all delegates with capture=false were removed
1521              // https:// github.com/angular/angular/issues/31643
1522              // https://github.com/angular/angular/issues/54581
1523              if (!capture && typeof eventName === 'string') {
1524                const onPropertySymbol = ZONE_SYMBOL_PREFIX + 'ON_PROPERTY' + eventName;
1525                target[onPropertySymbol] = null;
1526              }
1527            }
1528            // Note that `removeAllListeners` would ultimately call `removeEventListener`,
1529            // so we're safe to remove the abort listener only once here.
1530            const taskData = existingTask.data;
1531            if (taskData?.removeAbortListener) {
1532              taskData.removeAbortListener();
1533              taskData.removeAbortListener = null;
1534            }
1535            existingTask.zone.cancelTask(existingTask);
1536            if (returnTarget) {
1537              return target;
1538            }
1539            return;
1540          }
1541        }
1542      }
1543      // issue 930, didn't find the event name or callback
1544      // from zone kept existingTasks, the callback maybe
1545      // added outside of zone, we need to call native removeEventListener
1546      // to try to remove it.
1547      return nativeRemoveEventListener.apply(this, arguments);
1548    };
1549    proto[LISTENERS_EVENT_LISTENER] = function () {
1550      const target = this || _global;
1551      let eventName = arguments[0];
1552      if (patchOptions && patchOptions.transferEventName) {
1553        eventName = patchOptions.transferEventName(eventName);
1554      }
1555      const listeners = [];
1556      const tasks = findEventTasks(target, eventNameToString ? eventNameToString(eventName) : eventName);
1557      for (let i = 0; i < tasks.length; i++) {
1558        const task = tasks[i];
1559        let delegate = task.originalDelegate ? task.originalDelegate : task.callback;
1560        listeners.push(delegate);
1561      }
1562      return listeners;
1563    };
1564    proto[REMOVE_ALL_LISTENERS_EVENT_LISTENER] = function () {
1565      const target = this || _global;
1566      let eventName = arguments[0];
1567      if (!eventName) {
1568        const keys = Object.keys(target);
1569        for (let i = 0; i < keys.length; i++) {
1570          const prop = keys[i];
1571          const match = EVENT_NAME_SYMBOL_REGX.exec(prop);
1572          let evtName = match && match[1];
1573          // in nodejs EventEmitter, removeListener event is
1574          // used for monitoring the removeListener call,
1575          // so just keep removeListener eventListener until
1576          // all other eventListeners are removed
1577          if (evtName && evtName !== 'removeListener') {
1578            this[REMOVE_ALL_LISTENERS_EVENT_LISTENER].call(this, evtName);
1579          }
1580        }
1581        // remove removeListener listener finally
1582        this[REMOVE_ALL_LISTENERS_EVENT_LISTENER].call(this, 'removeListener');
1583      } else {
1584        if (patchOptions && patchOptions.transferEventName) {
1585          eventName = patchOptions.transferEventName(eventName);
1586        }
1587        const symbolEventNames = zoneSymbolEventNames[eventName];
1588        if (symbolEventNames) {
1589          const symbolEventName = symbolEventNames[FALSE_STR];
1590          const symbolCaptureEventName = symbolEventNames[TRUE_STR];
1591          const tasks = target[symbolEventName];
1592          const captureTasks = target[symbolCaptureEventName];
1593          if (tasks) {
1594            const removeTasks = tasks.slice();
1595            for (let i = 0; i < removeTasks.length; i++) {
1596              const task = removeTasks[i];
1597              let delegate = task.originalDelegate ? task.originalDelegate : task.callback;
1598              this[REMOVE_EVENT_LISTENER].call(this, eventName, delegate, task.options);
1599            }
1600          }
1601          if (captureTasks) {
1602            const removeTasks = captureTasks.slice();
1603            for (let i = 0; i < removeTasks.length; i++) {
1604              const task = removeTasks[i];
1605              let delegate = task.originalDelegate ? task.originalDelegate : task.callback;
1606              this[REMOVE_EVENT_LISTENER].call(this, eventName, delegate, task.options);
1607            }
1608          }
1609        }
1610      }
1611      if (returnTarget) {
1612        return this;
1613      }
1614    };
1615    // for native toString patch
1616    attachOriginToPatched(proto[ADD_EVENT_LISTENER], nativeAddEventListener);
1617    attachOriginToPatched(proto[REMOVE_EVENT_LISTENER], nativeRemoveEventListener);
1618    if (nativeRemoveAllListeners) {
1619      attachOriginToPatched(proto[REMOVE_ALL_LISTENERS_EVENT_LISTENER], nativeRemoveAllListeners);
1620    }
1621    if (nativeListeners) {
1622      attachOriginToPatched(proto[LISTENERS_EVENT_LISTENER], nativeListeners);
1623    }
1624    return true;
1625  }
1626  let results = [];
1627  for (let i = 0; i < apis.length; i++) {
1628    results[i] = patchEventTargetMethods(apis[i], patchOptions);
1629  }
1630  return results;
1631}
1632function findEventTasks(target, eventName) {
1633  if (!eventName) {
1634    const foundTasks = [];
1635    for (let prop in target) {
1636      const match = EVENT_NAME_SYMBOL_REGX.exec(prop);
1637      let evtName = match && match[1];
1638      if (evtName && (!eventName || evtName === eventName)) {
1639        const tasks = target[prop];
1640        if (tasks) {
1641          for (let i = 0; i < tasks.length; i++) {
1642            foundTasks.push(tasks[i]);
1643          }
1644        }
1645      }
1646    }
1647    return foundTasks;
1648  }
1649  let symbolEventName = zoneSymbolEventNames[eventName];
1650  if (!symbolEventName) {
1651    prepareEventNames(eventName);
1652    symbolEventName = zoneSymbolEventNames[eventName];
1653  }
1654  const captureFalseTasks = target[symbolEventName[FALSE_STR]];
1655  const captureTrueTasks = target[symbolEventName[TRUE_STR]];
1656  if (!captureFalseTasks) {
1657    return captureTrueTasks ? captureTrueTasks.slice() : [];
1658  } else {
1659    return captureTrueTasks ? captureFalseTasks.concat(captureTrueTasks) : captureFalseTasks.slice();
1660  }
1661}
1662function patchEventPrototype(global, api) {
1663  const Event = global['Event'];
1664  if (Event && Event.prototype) {
1665    api.patchMethod(Event.prototype, 'stopImmediatePropagation', delegate => function (self, args) {
1666      self[IMMEDIATE_PROPAGATION_SYMBOL] = true;
1667      // we need to call the native stopImmediatePropagation
1668      // in case in some hybrid application, some part of
1669      // application will be controlled by zone, some are not
1670      delegate && delegate.apply(self, args);
1671    });
1672  }
1673}
1674
1675/**
1676 * @fileoverview
1677 * @suppress {missingRequire}
1678 */
1679function patchQueueMicrotask(global, api) {
1680  api.patchMethod(global, 'queueMicrotask', delegate => {
1681    return function (self, args) {
1682      Zone.current.scheduleMicroTask('queueMicrotask', args[0]);
1683    };
1684  });
1685}
1686
1687/**
1688 * @fileoverview
1689 * @suppress {missingRequire}
1690 */
1691const taskSymbol = zoneSymbol('zoneTask');
1692function patchTimer(window, setName, cancelName, nameSuffix) {
1693  let setNative = null;
1694  let clearNative = null;
1695  setName += nameSuffix;
1696  cancelName += nameSuffix;
1697  const tasksByHandleId = {};
1698  function scheduleTask(task) {
1699    const data = task.data;
1700    data.args[0] = function () {
1701      return task.invoke.apply(this, arguments);
1702    };
1703    data.handleId = setNative.apply(window, data.args);
1704    return task;
1705  }
1706  function clearTask(task) {
1707    return clearNative.call(window, task.data.handleId);
1708  }
1709  setNative = patchMethod(window, setName, delegate => function (self, args) {
1710    if (typeof args[0] === 'function') {
1711      const options = {
1712        isPeriodic: nameSuffix === 'Interval',
1713        delay: nameSuffix === 'Timeout' || nameSuffix === 'Interval' ? args[1] || 0 : undefined,
1714        args: args
1715      };
1716      const callback = args[0];
1717      args[0] = function timer() {
1718        try {
1719          return callback.apply(this, arguments);
1720        } finally {
1721          // issue-934, task will be cancelled
1722          // even it is a periodic task such as
1723          // setInterval
1724          // https://github.com/angular/angular/issues/40387
1725          // Cleanup tasksByHandleId should be handled before scheduleTask
1726          // Since some zoneSpec may intercept and doesn't trigger
1727          // scheduleFn(scheduleTask) provided here.
1728          if (!options.isPeriodic) {
1729            if (typeof options.handleId === 'number') {
1730              // in non-nodejs env, we remove timerId
1731              // from local cache
1732              delete tasksByHandleId[options.handleId];
1733            } else if (options.handleId) {
1734              // Node returns complex objects as handleIds
1735              // we remove task reference from timer object
1736              options.handleId[taskSymbol] = null;
1737            }
1738          }
1739        }
1740      };
1741      const task = scheduleMacroTaskWithCurrentZone(setName, args[0], options, scheduleTask, clearTask);
1742      if (!task) {
1743        return task;
1744      }
1745      // Node.js must additionally support the ref and unref functions.
1746      const handle = task.data.handleId;
1747      if (typeof handle === 'number') {
1748        // for non nodejs env, we save handleId: task
1749        // mapping in local cache for clearTimeout
1750        tasksByHandleId[handle] = task;
1751      } else if (handle) {
1752        // for nodejs env, we save task
1753        // reference in timerId Object for clearTimeout
1754        handle[taskSymbol] = task;
1755      }
1756      // check whether handle is null, because some polyfill or browser
1757      // may return undefined from setTimeout/setInterval/setImmediate/requestAnimationFrame
1758      if (handle && handle.ref && handle.unref && typeof handle.ref === 'function' && typeof handle.unref === 'function') {
1759        task.ref = handle.ref.bind(handle);
1760        task.unref = handle.unref.bind(handle);
1761      }
1762      if (typeof handle === 'number' || handle) {
1763        return handle;
1764      }
1765      return task;
1766    } else {
1767      // cause an error by calling it directly.
1768      return delegate.apply(window, args);
1769    }
1770  });
1771  clearNative = patchMethod(window, cancelName, delegate => function (self, args) {
1772    const id = args[0];
1773    let task;
1774    if (typeof id === 'number') {
1775      // non nodejs env.
1776      task = tasksByHandleId[id];
1777    } else {
1778      // nodejs env.
1779      task = id && id[taskSymbol];
1780      // other environments.
1781      if (!task) {
1782        task = id;
1783      }
1784    }
1785    if (task && typeof task.type === 'string') {
1786      if (task.state !== 'notScheduled' && (task.cancelFn && task.data.isPeriodic || task.runCount === 0)) {
1787        if (typeof id === 'number') {
1788          delete tasksByHandleId[id];
1789        } else if (id) {
1790          id[taskSymbol] = null;
1791        }
1792        // Do not cancel already canceled functions
1793        task.zone.cancelTask(task);
1794      }
1795    } else {
1796      // cause an error by calling it directly.
1797      delegate.apply(window, args);
1798    }
1799  });
1800}
1801function patchCustomElements(_global, api) {
1802  const {
1803    isBrowser,
1804    isMix
1805  } = api.getGlobalObjects();
1806  if (!isBrowser && !isMix || !_global['customElements'] || !('customElements' in _global)) {
1807    return;
1808  }
1809  // https://html.spec.whatwg.org/multipage/custom-elements.html#concept-custom-element-definition-lifecycle-callbacks
1810  const callbacks = ['connectedCallback', 'disconnectedCallback', 'adoptedCallback', 'attributeChangedCallback', 'formAssociatedCallback', 'formDisabledCallback', 'formResetCallback', 'formStateRestoreCallback'];
1811  api.patchCallbacks(api, _global.customElements, 'customElements', 'define', callbacks);
1812}
1813function eventTargetPatch(_global, api) {
vendor: 36,783 bytes, lines 1814-2707
1814  if (Zone[api.symbol('patchEventTarget')]) {
1815    // EventTarget is already patched.
1816    return;
1817  }
1818  const {
1819    eventNames,
1820    zoneSymbolEventNames,
1821    TRUE_STR,
1822    FALSE_STR,
1823    ZONE_SYMBOL_PREFIX
1824  } = api.getGlobalObjects();
1825  //  predefine all __zone_symbol__ + eventName + true/false string
1826  for (let i = 0; i < eventNames.length; i++) {
1827    const eventName = eventNames[i];
1828    const falseEventName = eventName + FALSE_STR;
1829    const trueEventName = eventName + TRUE_STR;
1830    const symbol = ZONE_SYMBOL_PREFIX + falseEventName;
1831    const symbolCapture = ZONE_SYMBOL_PREFIX + trueEventName;
1832    zoneSymbolEventNames[eventName] = {};
1833    zoneSymbolEventNames[eventName][FALSE_STR] = symbol;
1834    zoneSymbolEventNames[eventName][TRUE_STR] = symbolCapture;
1835  }
1836  const EVENT_TARGET = _global['EventTarget'];
1837  if (!EVENT_TARGET || !EVENT_TARGET.prototype) {
1838    return;
1839  }
1840  api.patchEventTarget(_global, api, [EVENT_TARGET && EVENT_TARGET.prototype]);
1841  return true;
1842}
1843function patchEvent(global, api) {
1844  api.patchEventPrototype(global, api);
1845}
1846
1847/**
1848 * @fileoverview
1849 * @suppress {globalThis}
1850 */
1851function filterProperties(target, onProperties, ignoreProperties) {
1852  if (!ignoreProperties || ignoreProperties.length === 0) {
1853    return onProperties;
1854  }
1855  const tip = ignoreProperties.filter(ip => ip.target === target);
1856  if (!tip || tip.length === 0) {
1857    return onProperties;
1858  }
1859  const targetIgnoreProperties = tip[0].ignoreProperties;
1860  return onProperties.filter(op => targetIgnoreProperties.indexOf(op) === -1);
1861}
1862function patchFilteredProperties(target, onProperties, ignoreProperties, prototype) {
1863  // check whether target is available, sometimes target will be undefined
1864  // because different browser or some 3rd party plugin.
1865  if (!target) {
1866    return;
1867  }
1868  const filteredProperties = filterProperties(target, onProperties, ignoreProperties);
1869  patchOnProperties(target, filteredProperties, prototype);
1870}
1871/**
1872 * Get all event name properties which the event name startsWith `on`
1873 * from the target object itself, inherited properties are not considered.
1874 */
1875function getOnEventNames(target) {
1876  return Object.getOwnPropertyNames(target).filter(name => name.startsWith('on') && name.length > 2).map(name => name.substring(2));
1877}
1878function propertyDescriptorPatch(api, _global) {
1879  if (isNode && !isMix) {
1880    return;
1881  }
1882  if (Zone[api.symbol('patchEvents')]) {
1883    // events are already been patched by legacy patch.
1884    return;
1885  }
1886  const ignoreProperties = _global['__Zone_ignore_on_properties'];
1887  // for browsers that we can patch the descriptor:  Chrome & Firefox
1888  let patchTargets = [];
1889  if (isBrowser) {
1890    const internalWindow = window;
1891    patchTargets = patchTargets.concat(['Document', 'SVGElement', 'Element', 'HTMLElement', 'HTMLBodyElement', 'HTMLMediaElement', 'HTMLFrameSetElement', 'HTMLFrameElement', 'HTMLIFrameElement', 'HTMLMarqueeElement', 'Worker']);
1892    const ignoreErrorProperties = isIE() ? [{
1893      target: internalWindow,
1894      ignoreProperties: ['error']
1895    }] : [];
1896    // in IE/Edge, onProp not exist in window object, but in WindowPrototype
1897    // so we need to pass WindowPrototype to check onProp exist or not
1898    patchFilteredProperties(internalWindow, getOnEventNames(internalWindow), ignoreProperties ? ignoreProperties.concat(ignoreErrorProperties) : ignoreProperties, ObjectGetPrototypeOf(internalWindow));
1899  }
1900  patchTargets = patchTargets.concat(['XMLHttpRequest', 'XMLHttpRequestEventTarget', 'IDBIndex', 'IDBRequest', 'IDBOpenDBRequest', 'IDBDatabase', 'IDBTransaction', 'IDBCursor', 'WebSocket']);
1901  for (let i = 0; i < patchTargets.length; i++) {
1902    const target = _global[patchTargets[i]];
1903    target && target.prototype && patchFilteredProperties(target.prototype, getOnEventNames(target.prototype), ignoreProperties);
1904  }
1905}
1906
1907/**
1908 * @fileoverview
1909 * @suppress {missingRequire}
1910 */
1911function patchBrowser(Zone) {
1912  Zone.__load_patch('legacy', global => {
1913    const legacyPatch = global[Zone.__symbol__('legacyPatch')];
1914    if (legacyPatch) {
1915      legacyPatch();
1916    }
1917  });
1918  Zone.__load_patch('timers', global => {
1919    const set = 'set';
1920    const clear = 'clear';
1921    patchTimer(global, set, clear, 'Timeout');
1922    patchTimer(global, set, clear, 'Interval');
1923    patchTimer(global, set, clear, 'Immediate');
1924  });
1925  Zone.__load_patch('requestAnimationFrame', global => {
1926    patchTimer(global, 'request', 'cancel', 'AnimationFrame');
1927    patchTimer(global, 'mozRequest', 'mozCancel', 'AnimationFrame');
1928    patchTimer(global, 'webkitRequest', 'webkitCancel', 'AnimationFrame');
1929  });
1930  Zone.__load_patch('blocking', (global, Zone) => {
1931    const blockingMethods = ['alert', 'prompt', 'confirm'];
1932    for (let i = 0; i < blockingMethods.length; i++) {
1933      const name = blockingMethods[i];
1934      patchMethod(global, name, (delegate, symbol, name) => {
1935        return function (s, args) {
1936          return Zone.current.run(delegate, global, args, name);
1937        };
1938      });
1939    }
1940  });
1941  Zone.__load_patch('EventTarget', (global, Zone, api) => {
1942    patchEvent(global, api);
1943    eventTargetPatch(global, api);
1944    // patch XMLHttpRequestEventTarget's addEventListener/removeEventListener
1945    const XMLHttpRequestEventTarget = global['XMLHttpRequestEventTarget'];
1946    if (XMLHttpRequestEventTarget && XMLHttpRequestEventTarget.prototype) {
1947      api.patchEventTarget(global, api, [XMLHttpRequestEventTarget.prototype]);
1948    }
1949  });
1950  Zone.__load_patch('MutationObserver', (global, Zone, api) => {
1951    patchClass('MutationObserver');
1952    patchClass('WebKitMutationObserver');
1953  });
1954  Zone.__load_patch('IntersectionObserver', (global, Zone, api) => {
1955    patchClass('IntersectionObserver');
1956  });
1957  Zone.__load_patch('FileReader', (global, Zone, api) => {
1958    patchClass('FileReader');
1959  });
1960  Zone.__load_patch('on_property', (global, Zone, api) => {
1961    propertyDescriptorPatch(api, global);
1962  });
1963  Zone.__load_patch('customElements', (global, Zone, api) => {
1964    patchCustomElements(global, api);
1965  });
1966  Zone.__load_patch('XHR', (global, Zone) => {
1967    // Treat XMLHttpRequest as a macrotask.
1968    patchXHR(global);
1969    const XHR_TASK = zoneSymbol('xhrTask');
1970    const XHR_SYNC = zoneSymbol('xhrSync');
1971    const XHR_LISTENER = zoneSymbol('xhrListener');
1972    const XHR_SCHEDULED = zoneSymbol('xhrScheduled');
1973    const XHR_URL = zoneSymbol('xhrURL');
1974    const XHR_ERROR_BEFORE_SCHEDULED = zoneSymbol('xhrErrorBeforeScheduled');
1975    function patchXHR(window) {
1976      const XMLHttpRequest = window['XMLHttpRequest'];
1977      if (!XMLHttpRequest) {
1978        // XMLHttpRequest is not available in service worker
1979        return;
1980      }
1981      const XMLHttpRequestPrototype = XMLHttpRequest.prototype;
1982      function findPendingTask(target) {
1983        return target[XHR_TASK];
1984      }
1985      let oriAddListener = XMLHttpRequestPrototype[ZONE_SYMBOL_ADD_EVENT_LISTENER];
1986      let oriRemoveListener = XMLHttpRequestPrototype[ZONE_SYMBOL_REMOVE_EVENT_LISTENER];
1987      if (!oriAddListener) {
1988        const XMLHttpRequestEventTarget = window['XMLHttpRequestEventTarget'];
1989        if (XMLHttpRequestEventTarget) {
1990          const XMLHttpRequestEventTargetPrototype = XMLHttpRequestEventTarget.prototype;
1991          oriAddListener = XMLHttpRequestEventTargetPrototype[ZONE_SYMBOL_ADD_EVENT_LISTENER];
1992          oriRemoveListener = XMLHttpRequestEventTargetPrototype[ZONE_SYMBOL_REMOVE_EVENT_LISTENER];
1993        }
1994      }
1995      const READY_STATE_CHANGE = 'readystatechange';
1996      const SCHEDULED = 'scheduled';
1997      function scheduleTask(task) {
1998        const data = task.data;
1999        const target = data.target;
2000        target[XHR_SCHEDULED] = false;
2001        target[XHR_ERROR_BEFORE_SCHEDULED] = false;
2002        // remove existing event listener
2003        const listener = target[XHR_LISTENER];
2004        if (!oriAddListener) {
2005          oriAddListener = target[ZONE_SYMBOL_ADD_EVENT_LISTENER];
2006          oriRemoveListener = target[ZONE_SYMBOL_REMOVE_EVENT_LISTENER];
2007        }
2008        if (listener) {
2009          oriRemoveListener.call(target, READY_STATE_CHANGE, listener);
2010        }
2011        const newListener = target[XHR_LISTENER] = () => {
2012          if (target.readyState === target.DONE) {
2013            // sometimes on some browsers XMLHttpRequest will fire onreadystatechange with
2014            // readyState=4 multiple times, so we need to check task state here
2015            if (!data.aborted && target[XHR_SCHEDULED] && task.state === SCHEDULED) {
2016              // check whether the xhr has registered onload listener
2017              // if that is the case, the task should invoke after all
2018              // onload listeners finish.
2019              // Also if the request failed without response (status = 0), the load event handler
2020              // will not be triggered, in that case, we should also invoke the placeholder callback
2021              // to close the XMLHttpRequest::send macroTask.
2022              // https://github.com/angular/angular/issues/38795
2023              const loadTasks = target[Zone.__symbol__('loadfalse')];
2024              if (target.status !== 0 && loadTasks && loadTasks.length > 0) {
2025                const oriInvoke = task.invoke;
2026                task.invoke = function () {
2027                  // need to load the tasks again, because in other
2028                  // load listener, they may remove themselves
2029                  const loadTasks = target[Zone.__symbol__('loadfalse')];
2030                  for (let i = 0; i < loadTasks.length; i++) {
2031                    if (loadTasks[i] === task) {
2032                      loadTasks.splice(i, 1);
2033                    }
2034                  }
2035                  if (!data.aborted && task.state === SCHEDULED) {
2036                    oriInvoke.call(task);
2037                  }
2038                };
2039                loadTasks.push(task);
2040              } else {
2041                task.invoke();
2042              }
2043            } else if (!data.aborted && target[XHR_SCHEDULED] === false) {
2044              // error occurs when xhr.send()
2045              target[XHR_ERROR_BEFORE_SCHEDULED] = true;
2046            }
2047          }
2048        };
2049        oriAddListener.call(target, READY_STATE_CHANGE, newListener);
2050        const storedTask = target[XHR_TASK];
2051        if (!storedTask) {
2052          target[XHR_TASK] = task;
2053        }
2054        sendNative.apply(target, data.args);
2055        target[XHR_SCHEDULED] = true;
2056        return task;
2057      }
2058      function placeholderCallback() {}
2059      function clearTask(task) {
2060        const data = task.data;
2061        // Note - ideally, we would call data.target.removeEventListener here, but it's too late
2062        // to prevent it from firing. So instead, we store info for the event listener.
2063        data.aborted = true;
2064        return abortNative.apply(data.target, data.args);
2065      }
2066      const openNative = patchMethod(XMLHttpRequestPrototype, 'open', () => function (self, args) {
2067        self[XHR_SYNC] = args[2] == false;
2068        self[XHR_URL] = args[1];
2069        return openNative.apply(self, args);
2070      });
2071      const XMLHTTPREQUEST_SOURCE = 'XMLHttpRequest.send';
2072      const fetchTaskAborting = zoneSymbol('fetchTaskAborting');
2073      const fetchTaskScheduling = zoneSymbol('fetchTaskScheduling');
2074      const sendNative = patchMethod(XMLHttpRequestPrototype, 'send', () => function (self, args) {
2075        if (Zone.current[fetchTaskScheduling] === true) {
2076          // a fetch is scheduling, so we are using xhr to polyfill fetch
2077          // and because we already schedule macroTask for fetch, we should
2078          // not schedule a macroTask for xhr again
2079          return sendNative.apply(self, args);
2080        }
2081        if (self[XHR_SYNC]) {
2082          // if the XHR is sync there is no task to schedule, just execute the code.
2083          return sendNative.apply(self, args);
2084        } else {
2085          const options = {
2086            target: self,
2087            url: self[XHR_URL],
2088            isPeriodic: false,
2089            args: args,
2090            aborted: false
2091          };
2092          const task = scheduleMacroTaskWithCurrentZone(XMLHTTPREQUEST_SOURCE, placeholderCallback, options, scheduleTask, clearTask);
2093          if (self && self[XHR_ERROR_BEFORE_SCHEDULED] === true && !options.aborted && task.state === SCHEDULED) {
2094            // xhr request throw error when send
2095            // we should invoke task instead of leaving a scheduled
2096            // pending macroTask
2097            task.invoke();
2098          }
2099        }
2100      });
2101      const abortNative = patchMethod(XMLHttpRequestPrototype, 'abort', () => function (self, args) {
2102        const task = findPendingTask(self);
2103        if (task && typeof task.type == 'string') {
2104          // If the XHR has already completed, do nothing.
2105          // If the XHR has already been aborted, do nothing.
2106          // Fix #569, call abort multiple times before done will cause
2107          // macroTask task count be negative number
2108          if (task.cancelFn == null || task.data && task.data.aborted) {
2109            return;
2110          }
2111          task.zone.cancelTask(task);
2112        } else if (Zone.current[fetchTaskAborting] === true) {
2113          // the abort is called from fetch polyfill, we need to call native abort of XHR.
2114          return abortNative.apply(self, args);
2115        }
2116        // Otherwise, we are trying to abort an XHR which has not yet been sent, so there is no
2117        // task
2118        // to cancel. Do nothing.
2119      });
2120    }
2121  });
2122  Zone.__load_patch('geolocation', global => {
2123    /// GEO_LOCATION
2124    if (global['navigator'] && global['navigator'].geolocation) {
2125      patchPrototype(global['navigator'].geolocation, ['getCurrentPosition', 'watchPosition']);
2126    }
2127  });
2128  Zone.__load_patch('PromiseRejectionEvent', (global, Zone) => {
2129    // handle unhandled promise rejection
2130    function findPromiseRejectionHandler(evtName) {
2131      return function (e) {
2132        const eventTasks = findEventTasks(global, evtName);
2133        eventTasks.forEach(eventTask => {
2134          // windows has added unhandledrejection event listener
2135          // trigger the event listener
2136          const PromiseRejectionEvent = global['PromiseRejectionEvent'];
2137          if (PromiseRejectionEvent) {
2138            const evt = new PromiseRejectionEvent(evtName, {
2139              promise: e.promise,
2140              reason: e.rejection
2141            });
2142            eventTask.invoke(evt);
2143          }
2144        });
2145      };
2146    }
2147    if (global['PromiseRejectionEvent']) {
2148      Zone[zoneSymbol('unhandledPromiseRejectionHandler')] = findPromiseRejectionHandler('unhandledrejection');
2149      Zone[zoneSymbol('rejectionHandledHandler')] = findPromiseRejectionHandler('rejectionhandled');
2150    }
2151  });
2152  Zone.__load_patch('queueMicrotask', (global, Zone, api) => {
2153    patchQueueMicrotask(global, api);
2154  });
2155}
2156function patchPromise(Zone) {
2157  Zone.__load_patch('ZoneAwarePromise', (global, Zone, api) => {
2158    const ObjectGetOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
2159    const ObjectDefineProperty = Object.defineProperty;
2160    function readableObjectToString(obj) {
2161      if (obj && obj.toString === Object.prototype.toString) {
2162        const className = obj.constructor && obj.constructor.name;
2163        return (className ? className : '') + ': ' + JSON.stringify(obj);
2164      }
2165      return obj ? obj.toString() : Object.prototype.toString.call(obj);
2166    }
2167    const __symbol__ = api.symbol;
2168    const _uncaughtPromiseErrors = [];
2169    const isDisableWrappingUncaughtPromiseRejection = global[__symbol__('DISABLE_WRAPPING_UNCAUGHT_PROMISE_REJECTION')] !== false;
2170    const symbolPromise = __symbol__('Promise');
2171    const symbolThen = __symbol__('then');
2172    const creationTrace = '__creationTrace__';
2173    api.onUnhandledError = e => {
2174      if (api.showUncaughtError()) {
2175        const rejection = e && e.rejection;
2176        if (rejection) {
2177          console.error('Unhandled Promise rejection:', rejection instanceof Error ? rejection.message : rejection, '; Zone:', e.zone.name, '; Task:', e.task && e.task.source, '; Value:', rejection, rejection instanceof Error ? rejection.stack : undefined);
2178        } else {
2179          console.error(e);
2180        }
2181      }
2182    };
2183    api.microtaskDrainDone = () => {
2184      while (_uncaughtPromiseErrors.length) {
2185        const uncaughtPromiseError = _uncaughtPromiseErrors.shift();
2186        try {
2187          uncaughtPromiseError.zone.runGuarded(() => {
2188            if (uncaughtPromiseError.throwOriginal) {
2189              throw uncaughtPromiseError.rejection;
2190            }
2191            throw uncaughtPromiseError;
2192          });
2193        } catch (error) {
2194          handleUnhandledRejection(error);
2195        }
2196      }
2197    };
2198    const UNHANDLED_PROMISE_REJECTION_HANDLER_SYMBOL = __symbol__('unhandledPromiseRejectionHandler');
2199    function handleUnhandledRejection(e) {
2200      api.onUnhandledError(e);
2201      try {
2202        const handler = Zone[UNHANDLED_PROMISE_REJECTION_HANDLER_SYMBOL];
2203        if (typeof handler === 'function') {
2204          handler.call(this, e);
2205        }
2206      } catch (err) {}
2207    }
2208    function isThenable(value) {
2209      return value && value.then;
2210    }
2211    function forwardResolution(value) {
2212      return value;
2213    }
2214    function forwardRejection(rejection) {
2215      return ZoneAwarePromise.reject(rejection);
2216    }
2217    const symbolState = __symbol__('state');
2218    const symbolValue = __symbol__('value');
2219    const symbolFinally = __symbol__('finally');
2220    const symbolParentPromiseValue = __symbol__('parentPromiseValue');
2221    const symbolParentPromiseState = __symbol__('parentPromiseState');
2222    const source = 'Promise.then';
2223    const UNRESOLVED = null;
2224    const RESOLVED = true;
2225    const REJECTED = false;
2226    const REJECTED_NO_CATCH = 0;
2227    function makeResolver(promise, state) {
2228      return v => {
2229        try {
2230          resolvePromise(promise, state, v);
2231        } catch (err) {
2232          resolvePromise(promise, false, err);
2233        }
2234        // Do not return value or you will break the Promise spec.
2235      };
2236    }
2237    const once = function () {
2238      let wasCalled = false;
2239      return function wrapper(wrappedFunction) {
2240        return function () {
2241          if (wasCalled) {
2242            return;
2243          }
2244          wasCalled = true;
2245          wrappedFunction.apply(null, arguments);
2246        };
2247      };
2248    };
2249    const TYPE_ERROR = 'Promise resolved with itself';
2250    const CURRENT_TASK_TRACE_SYMBOL = __symbol__('currentTaskTrace');
2251    // Promise Resolution
2252    function resolvePromise(promise, state, value) {
2253      const onceWrapper = once();
2254      if (promise === value) {
2255        throw new TypeError(TYPE_ERROR);
2256      }
2257      if (promise[symbolState] === UNRESOLVED) {
2258        // should only get value.then once based on promise spec.
2259        let then = null;
2260        try {
2261          if (typeof value === 'object' || typeof value === 'function') {
2262            then = value && value.then;
2263          }
2264        } catch (err) {
2265          onceWrapper(() => {
2266            resolvePromise(promise, false, err);
2267          })();
2268          return promise;
2269        }
2270        // if (value instanceof ZoneAwarePromise) {
2271        if (state !== REJECTED && value instanceof ZoneAwarePromise && value.hasOwnProperty(symbolState) && value.hasOwnProperty(symbolValue) && value[symbolState] !== UNRESOLVED) {
2272          clearRejectedNoCatch(value);
2273          resolvePromise(promise, value[symbolState], value[symbolValue]);
2274        } else if (state !== REJECTED && typeof then === 'function') {
2275          try {
2276            then.call(value, onceWrapper(makeResolver(promise, state)), onceWrapper(makeResolver(promise, false)));
2277          } catch (err) {
2278            onceWrapper(() => {
2279              resolvePromise(promise, false, err);
2280            })();
2281          }
2282        } else {
2283          promise[symbolState] = state;
2284          const queue = promise[symbolValue];
2285          promise[symbolValue] = value;
2286          if (promise[symbolFinally] === symbolFinally) {
2287            // the promise is generated by Promise.prototype.finally
2288            if (state === RESOLVED) {
2289              // the state is resolved, should ignore the value
2290              // and use parent promise value
2291              promise[symbolState] = promise[symbolParentPromiseState];
2292              promise[symbolValue] = promise[symbolParentPromiseValue];
2293            }
2294          }
2295          // record task information in value when error occurs, so we can
2296          // do some additional work such as render longStackTrace
2297          if (state === REJECTED && value instanceof Error) {
2298            // check if longStackTraceZone is here
2299            const trace = Zone.currentTask && Zone.currentTask.data && Zone.currentTask.data[creationTrace];
2300            if (trace) {
2301              // only keep the long stack trace into error when in longStackTraceZone
2302              ObjectDefineProperty(value, CURRENT_TASK_TRACE_SYMBOL, {
2303                configurable: true,
2304                enumerable: false,
2305                writable: true,
2306                value: trace
2307              });
2308            }
2309          }
2310          for (let i = 0; i < queue.length;) {
2311            scheduleResolveOrReject(promise, queue[i++], queue[i++], queue[i++], queue[i++]);
2312          }
2313          if (queue.length == 0 && state == REJECTED) {
2314            promise[symbolState] = REJECTED_NO_CATCH;
2315            let uncaughtPromiseError = value;
2316            try {
2317              // Here we throws a new Error to print more readable error log
2318              // and if the value is not an error, zone.js builds an `Error`
2319              // Object here to attach the stack information.
2320              throw new Error('Uncaught (in promise): ' + readableObjectToString(value) + (value && value.stack ? '\n' + value.stack : ''));
2321            } catch (err) {
2322              uncaughtPromiseError = err;
2323            }
2324            if (isDisableWrappingUncaughtPromiseRejection) {
2325              // If disable wrapping uncaught promise reject
2326              // use the value instead of wrapping it.
2327              uncaughtPromiseError.throwOriginal = true;
2328            }
2329            uncaughtPromiseError.rejection = value;
2330            uncaughtPromiseError.promise = promise;
2331            uncaughtPromiseError.zone = Zone.current;
2332            uncaughtPromiseError.task = Zone.currentTask;
2333            _uncaughtPromiseErrors.push(uncaughtPromiseError);
2334            api.scheduleMicroTask(); // to make sure that it is running
2335          }
2336        }
2337      }
2338      // Resolving an already resolved promise is a noop.
2339      return promise;
2340    }
2341    const REJECTION_HANDLED_HANDLER = __symbol__('rejectionHandledHandler');
2342    function clearRejectedNoCatch(promise) {
2343      if (promise[symbolState] === REJECTED_NO_CATCH) {
2344        // if the promise is rejected no catch status
2345        // and queue.length > 0, means there is a error handler
2346        // here to handle the rejected promise, we should trigger
2347        // windows.rejectionhandled eventHandler or nodejs rejectionHandled
2348        // eventHandler
2349        try {
2350          const handler = Zone[REJECTION_HANDLED_HANDLER];
2351          if (handler && typeof handler === 'function') {
2352            handler.call(this, {
2353              rejection: promise[symbolValue],
2354              promise: promise
2355            });
2356          }
2357        } catch (err) {}
2358        promise[symbolState] = REJECTED;
2359        for (let i = 0; i < _uncaughtPromiseErrors.length; i++) {
2360          if (promise === _uncaughtPromiseErrors[i].promise) {
2361            _uncaughtPromiseErrors.splice(i, 1);
2362          }
2363        }
2364      }
2365    }
2366    function scheduleResolveOrReject(promise, zone, chainPromise, onFulfilled, onRejected) {
2367      clearRejectedNoCatch(promise);
2368      const promiseState = promise[symbolState];
2369      const delegate = promiseState ? typeof onFulfilled === 'function' ? onFulfilled : forwardResolution : typeof onRejected === 'function' ? onRejected : forwardRejection;
2370      zone.scheduleMicroTask(source, () => {
2371        try {
2372          const parentPromiseValue = promise[symbolValue];
2373          const isFinallyPromise = !!chainPromise && symbolFinally === chainPromise[symbolFinally];
2374          if (isFinallyPromise) {
2375            // if the promise is generated from finally call, keep parent promise's state and value
2376            chainPromise[symbolParentPromiseValue] = parentPromiseValue;
2377            chainPromise[symbolParentPromiseState] = promiseState;
2378          }
2379          // should not pass value to finally callback
2380          const value = zone.run(delegate, undefined, isFinallyPromise && delegate !== forwardRejection && delegate !== forwardResolution ? [] : [parentPromiseValue]);
2381          resolvePromise(chainPromise, true, value);
2382        } catch (error) {
2383          // if error occurs, should always return this error
2384          resolvePromise(chainPromise, false, error);
2385        }
2386      }, chainPromise);
2387    }
2388    const ZONE_AWARE_PROMISE_TO_STRING = 'function ZoneAwarePromise() { [native code] }';
2389    const noop = function () {};
2390    const AggregateError = global.AggregateError;
2391    class ZoneAwarePromise {
2392      static toString() {
2393        return ZONE_AWARE_PROMISE_TO_STRING;
2394      }
2395      static resolve(value) {
2396        if (value instanceof ZoneAwarePromise) {
2397          return value;
2398        }
2399        return resolvePromise(new this(null), RESOLVED, value);
2400      }
2401      static reject(error) {
2402        return resolvePromise(new this(null), REJECTED, error);
2403      }
2404      static withResolvers() {
2405        const result = {};
2406        result.promise = new ZoneAwarePromise((res, rej) => {
2407          result.resolve = res;
2408          result.reject = rej;
2409        });
2410        return result;
2411      }
2412      static any(values) {
2413        if (!values || typeof values[Symbol.iterator] !== 'function') {
2414          return Promise.reject(new AggregateError([], 'All promises were rejected'));
2415        }
2416        const promises = [];
2417        let count = 0;
2418        try {
2419          for (let v of values) {
2420            count++;
2421            promises.push(ZoneAwarePromise.resolve(v));
2422          }
2423        } catch (err) {
2424          return Promise.reject(new AggregateError([], 'All promises were rejected'));
2425        }
2426        if (count === 0) {
2427          return Promise.reject(new AggregateError([], 'All promises were rejected'));
2428        }
2429        let finished = false;
2430        const errors = [];
2431        return new ZoneAwarePromise((resolve, reject) => {
2432          for (let i = 0; i < promises.length; i++) {
2433            promises[i].then(v => {
2434              if (finished) {
2435                return;
2436              }
2437              finished = true;
2438              resolve(v);
2439            }, err => {
2440              errors.push(err);
2441              count--;
2442              if (count === 0) {
2443                finished = true;
2444                reject(new AggregateError(errors, 'All promises were rejected'));
2445              }
2446            });
2447          }
2448        });
2449      }
2450      static race(values) {
2451        let resolve;
2452        let reject;
2453        let promise = new this((res, rej) => {
2454          resolve = res;
2455          reject = rej;
2456        });
2457        function onResolve(value) {
2458          resolve(value);
2459        }
2460        function onReject(error) {
2461          reject(error);
2462        }
2463        for (let value of values) {
2464          if (!isThenable(value)) {
2465            value = this.resolve(value);
2466          }
2467          value.then(onResolve, onReject);
2468        }
2469        return promise;
2470      }
2471      static all(values) {
2472        return ZoneAwarePromise.allWithCallback(values);
2473      }
2474      static allSettled(values) {
2475        const P = this && this.prototype instanceof ZoneAwarePromise ? this : ZoneAwarePromise;
2476        return P.allWithCallback(values, {
2477          thenCallback: value => ({
2478            status: 'fulfilled',
2479            value
2480          }),
2481          errorCallback: err => ({
2482            status: 'rejected',
2483            reason: err
2484          })
2485        });
2486      }
2487      static allWithCallback(values, callback) {
2488        let resolve;
2489        let reject;
2490        let promise = new this((res, rej) => {
2491          resolve = res;
2492          reject = rej;
2493        });
2494        // Start at 2 to prevent prematurely resolving if .then is called immediately.
2495        let unresolvedCount = 2;
2496        let valueIndex = 0;
2497        const resolvedValues = [];
2498        for (let value of values) {
2499          if (!isThenable(value)) {
2500            value = this.resolve(value);
2501          }
2502          const curValueIndex = valueIndex;
2503          try {
2504            value.then(value => {
2505              resolvedValues[curValueIndex] = callback ? callback.thenCallback(value) : value;
2506              unresolvedCount--;
2507              if (unresolvedCount === 0) {
2508                resolve(resolvedValues);
2509              }
2510            }, err => {
2511              if (!callback) {
2512                reject(err);
2513              } else {
2514                resolvedValues[curValueIndex] = callback.errorCallback(err);
2515                unresolvedCount--;
2516                if (unresolvedCount === 0) {
2517                  resolve(resolvedValues);
2518                }
2519              }
2520            });
2521          } catch (thenErr) {
2522            reject(thenErr);
2523          }
2524          unresolvedCount++;
2525          valueIndex++;
2526        }
2527        // Make the unresolvedCount zero-based again.
2528        unresolvedCount -= 2;
2529        if (unresolvedCount === 0) {
2530          resolve(resolvedValues);
2531        }
2532        return promise;
2533      }
2534      constructor(executor) {
2535        const promise = this;
2536        if (!(promise instanceof ZoneAwarePromise)) {
2537          throw new Error('Must be an instanceof Promise.');
2538        }
2539        promise[symbolState] = UNRESOLVED;
2540        promise[symbolValue] = []; // queue;
2541        try {
2542          const onceWrapper = once();
2543          executor && executor(onceWrapper(makeResolver(promise, RESOLVED)), onceWrapper(makeResolver(promise, REJECTED)));
2544        } catch (error) {
2545          resolvePromise(promise, false, error);
2546        }
2547      }
2548      get [Symbol.toStringTag]() {
2549        return 'Promise';
2550      }
2551      get [Symbol.species]() {
2552        return ZoneAwarePromise;
2553      }
2554      then(onFulfilled, onRejected) {
2555        // We must read `Symbol.species` safely because `this` may be anything. For instance, `this`
2556        // may be an object without a prototype (created through `Object.create(null)`); thus
2557        // `this.constructor` will be undefined. One of the use cases is SystemJS creating
2558        // prototype-less objects (modules) via `Object.create(null)`. The SystemJS creates an empty
2559        // object and copies promise properties into that object (within the `getOrCreateLoad`
2560        // function). The zone.js then checks if the resolved value has the `then` method and
2561        // invokes it with the `value` context. Otherwise, this will throw an error: `TypeError:
2562        // Cannot read properties of undefined (reading 'Symbol(Symbol.species)')`.
2563        let C = this.constructor?.[Symbol.species];
2564        if (!C || typeof C !== 'function') {
2565          C = this.constructor || ZoneAwarePromise;
2566        }
2567        const chainPromise = new C(noop);
2568        const zone = Zone.current;
2569        if (this[symbolState] == UNRESOLVED) {
2570          this[symbolValue].push(zone, chainPromise, onFulfilled, onRejected);
2571        } else {
2572          scheduleResolveOrReject(this, zone, chainPromise, onFulfilled, onRejected);
2573        }
2574        return chainPromise;
2575      }
2576      catch(onRejected) {
2577        return this.then(null, onRejected);
2578      }
2579      finally(onFinally) {
2580        // See comment on the call to `then` about why thee `Symbol.species` is safely accessed.
2581        let C = this.constructor?.[Symbol.species];
2582        if (!C || typeof C !== 'function') {
2583          C = ZoneAwarePromise;
2584        }
2585        const chainPromise = new C(noop);
2586        chainPromise[symbolFinally] = symbolFinally;
2587        const zone = Zone.current;
2588        if (this[symbolState] == UNRESOLVED) {
2589          this[symbolValue].push(zone, chainPromise, onFinally, onFinally);
2590        } else {
2591          scheduleResolveOrReject(this, zone, chainPromise, onFinally, onFinally);
2592        }
2593        return chainPromise;
2594      }
2595    }
2596    // Protect against aggressive optimizers dropping seemingly unused properties.
2597    // E.g. Closure Compiler in advanced mode.
2598    ZoneAwarePromise['resolve'] = ZoneAwarePromise.resolve;
2599    ZoneAwarePromise['reject'] = ZoneAwarePromise.reject;
2600    ZoneAwarePromise['race'] = ZoneAwarePromise.race;
2601    ZoneAwarePromise['all'] = ZoneAwarePromise.all;
2602    const NativePromise = global[symbolPromise] = global['Promise'];
2603    global['Promise'] = ZoneAwarePromise;
2604    const symbolThenPatched = __symbol__('thenPatched');
2605    function patchThen(Ctor) {
2606      const proto = Ctor.prototype;
2607      const prop = ObjectGetOwnPropertyDescriptor(proto, 'then');
2608      if (prop && (prop.writable === false || !prop.configurable)) {
2609        // check Ctor.prototype.then propertyDescriptor is writable or not
2610        // in meteor env, writable is false, we should ignore such case
2611        return;
2612      }
2613      const originalThen = proto.then;
2614      // Keep a reference to the original method.
2615      proto[symbolThen] = originalThen;
2616      Ctor.prototype.then = function (onResolve, onReject) {
2617        const wrapped = new ZoneAwarePromise((resolve, reject) => {
2618          originalThen.call(this, resolve, reject);
2619        });
2620        return wrapped.then(onResolve, onReject);
2621      };
2622      Ctor[symbolThenPatched] = true;
2623    }
2624    api.patchThen = patchThen;
2625    function zoneify(fn) {
2626      return function (self, args) {
2627        let resultPromise = fn.apply(self, args);
2628        if (resultPromise instanceof ZoneAwarePromise) {
2629          return resultPromise;
2630        }
2631        let ctor = resultPromise.constructor;
2632        if (!ctor[symbolThenPatched]) {
2633          patchThen(ctor);
2634        }
2635        return resultPromise;
2636      };
2637    }
2638    if (NativePromise) {
2639      patchThen(NativePromise);
2640      patchMethod(global, 'fetch', delegate => zoneify(delegate));
2641    }
2642    // This is not part of public API, but it is useful for tests, so we expose it.
2643    Promise[Zone.__symbol__('uncaughtPromiseErrors')] = _uncaughtPromiseErrors;
2644    return ZoneAwarePromise;
2645  });
2646}
2647function patchToString(Zone) {
2648  // override Function.prototype.toString to make zone.js patched function
2649  // look like native function
2650  Zone.__load_patch('toString', global => {
2651    // patch Func.prototype.toString to let them look like native
2652    const originalFunctionToString = Function.prototype.toString;
2653    const ORIGINAL_DELEGATE_SYMBOL = zoneSymbol('OriginalDelegate');
2654    const PROMISE_SYMBOL = zoneSymbol('Promise');
2655    const ERROR_SYMBOL = zoneSymbol('Error');
2656    const newFunctionToString = function toString() {
2657      if (typeof this === 'function') {
2658        const originalDelegate = this[ORIGINAL_DELEGATE_SYMBOL];
2659        if (originalDelegate) {
2660          if (typeof originalDelegate === 'function') {
2661            return originalFunctionToString.call(originalDelegate);
2662          } else {
2663            return Object.prototype.toString.call(originalDelegate);
2664          }
2665        }
2666        if (this === Promise) {
2667          const nativePromise = global[PROMISE_SYMBOL];
2668          if (nativePromise) {
2669            return originalFunctionToString.call(nativePromise);
2670          }
2671        }
2672        if (this === Error) {
2673          const nativeError = global[ERROR_SYMBOL];
2674          if (nativeError) {
2675            return originalFunctionToString.call(nativeError);
2676          }
2677        }
2678      }
2679      return originalFunctionToString.call(this);
2680    };
2681    newFunctionToString[ORIGINAL_DELEGATE_SYMBOL] = originalFunctionToString;
2682    Function.prototype.toString = newFunctionToString;
2683    // patch Object.prototype.toString to let them look like native
2684    const originalObjectToString = Object.prototype.toString;
2685    const PROMISE_OBJECT_TO_STRING = '[object Promise]';
2686    Object.prototype.toString = function () {
2687      if (typeof Promise === 'function' && this instanceof Promise) {
2688        return PROMISE_OBJECT_TO_STRING;
2689      }
2690      return originalObjectToString.call(this);
2691    };
2692  });
2693}
2694function patchCallbacks(api, target, targetName, method, callbacks) {
2695  const symbol = Zone.__symbol__(method);
2696  if (target[symbol]) {
2697    return;
2698  }
2699  const nativeDelegate = target[symbol] = target[method];
2700  target[method] = function (name, opts, options) {
2701    if (opts && opts.prototype) {
2702      callbacks.forEach(function (callback) {
2703        const source = `${targetName}.${method}::` + callback;
2704        const prototype = opts.prototype;
2705        // Note: the `patchCallbacks` is used for patching the `document.registerElement` and
2706        // `customElements.define`. We explicitly wrap the patching code into try-catch since
2707        // callbacks may be already patched by other web components frameworks (e.g. LWC
2707), and they
2708        // make those properties non-writable. This means that patching callback will throw an error
2709        // `cannot assign to read-only property`. See this code as an example:
2710        // https://github.com/salesforce/lwc/blob/master/packages/@lwc/engine-core/src/framework/base-bridge-element.ts#L180-L186
2711        // We don't want to stop the application rendering if we couldn't patch some
2712        // callback, e.g. `attributeChangedCallback`.
2713        try {
2714          if (prototype.hasOwnProperty(callback)) {
2715            const descriptor = api.ObjectGetOwnPropertyDescriptor(prototype, callback);
2716            if (descriptor && descriptor.value) {
2717              descriptor.value = api.wrapWithCurrentZone(descriptor.value, source);
2718              api._redefineProperty(opts.prototype, callback, descriptor);
2719            } else if (prototype[callback]) {
2720              prototype[callback] = api.wrapWithCurrentZone(prototype[callback], source);
2721            }
2722          } else if (prototype[callback]) {
2723            prototype[callback] = api.wrapWithCurrentZone(prototype[callback], source);
2724          }
2725        } catch {
2726          // Note: we leave the catch block empty since there's no way to handle the error related
2727          // to non-writable property.
2728        }
2729      });
2730    }
2731    return nativeDelegate.call(target, name, opts, options);
2732  };
2733  api.attachOriginToPatched(target[method], nativeDelegate);
2734}
2735function patchUtil(Zone) {
2736  Zone.__load_patch('util', (global, Zone, api) => {
2737    // Collect native event names by looking at properties
2738    // on the global namespace, e.g. 'onclick'.
2739    const eventNames = getOnEventNames(global);
2740    api.patchOnProperties = patchOnProperties;
2741    api.patchMethod = patchMethod;
2742    api.bindArguments = bindArguments;
2743    api.patchMacroTask = patchMacroTask;
2744    // In earlier version of zone.js (<0.9.0), we use env name `__zone_symbol__BLACK_LISTED_EVENTS`
2745    // to define which events will not be patched by `Zone.js`. In newer version (>=0.9.0), we
2746    // change the env name to `__zone_symbol__UNPATCHED_EVENTS` to keep the name consistent with
2747    // angular repo. The  `__zone_symbol__BLACK_LISTED_EVENTS` is deprecated, but it is still be
2748    // supported for backwards compatibility.
2749    const SYMBOL_BLACK_LISTED_EVENTS = Zone.__symbol__('BLACK_LISTED_EVENTS');
2750    const SYMBOL_UNPATCHED_EVENTS = Zone.__symbol__('UNPATCHED_EVENTS');
2751    if (global[SYMBOL_UNPATCHED_EVENTS]) {
2752      global[SYMBOL_BLACK_LISTED_EVENTS] = global[SYMBOL_UNPATCHED_EVENTS];
2753    }
2754    if (global[SYMBOL_BLACK_LISTED_EVENTS]) {
2755      Zone[SYMBOL_BLACK_LISTED_EVENTS] = Zone[SYMBOL_UNPATCHED_EVENTS] = global[SYMBOL_BLACK_LISTED_EVENTS];
2756    }
2757    api.patchEventPrototype = patchEventPrototype;
2758    api.patchEventTarget = patchEventTarget;
2759    api.isIEOrEdge = isIEOrEdge;
2760    api.ObjectDefineProperty = ObjectDefineProperty;
2761    api.ObjectGetOwnPropertyDescriptor = ObjectGetOwnPropertyDescriptor;
2762    api.ObjectCreate = ObjectCreate;
2763    api.ArraySlice = ArraySlice;
2764    api.patchClass = patchClass;
2765    api.wrapWithCurrentZone = wrapWithCurrentZone;
2766    api.filterProperties = filterProperties;
2767    api.attachOriginToPatched = attachOriginToPatched;
2768    api._redefineProperty = Object.defineProperty;
2769    api.patchCallbacks = patchCallbacks;
2770    api.getGlobalObjects = () => ({
2771      globalSources,
2772      zoneSymbolEventNames,
2773      eventNames,
2774      isBrowser,
2775      isMix,
2776      isNode,
2777      TRUE_STR,
2778      FALSE_STR,
2779      ZONE_SYMBOL_PREFIX,
2780      ADD_EVENT_LISTENER_STR,
2781      REMOVE_EVENT_LISTENER_STR
2782    });
2783  });
2784}
2785function patchCommon(Zone) {
2786  patchPromise(Zone);
2787  patchToString(Zone);
2788  patchUtil(Zone);
2789}
2790const Zone$1 = loadZone();
2791patchCommon(Zone$1);
2792patchBrowser(Zone$1);
2793
2794/***/ }),
2795
2796/***/ 45568:
2797/*!**************************************************************!*\
2798  !*** ./node_modules/@angular/compiler/fesm2022/compiler.mjs ***!
2799  \**************************************************************/
2800/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
2801
2802__webpack_require__.r(__webpack_exports__);
2803/* harmony export */ __webpack_require__.d(__webpack_exports__, {
2804/* harmony export */   AST: () => (/* binding */ AST),
2805/* harmony export */   ASTWithName: () => (/* binding */ ASTWithName),
2806/* harmony export */   ASTWithSource: () => (/* binding */ ASTWithSource),
2807/* harmony export */   AbsoluteSourceSpan: () => (/* binding */ AbsoluteSourceSpan),
2808/* harmony export */   ArrayType: () => (/* binding */ ArrayType),
2809/* harmony export */   ArrowFunctionExpr: () => (/* binding */ ArrowFunctionExpr),
2810/* harmony export */   AstMemoryEfficientTransformer: () => (/* binding */ AstMemoryEfficientTransformer),
2811/* harmony export */   AstTransformer: () => (/* binding */ AstTransformer),
2812/* harmony export */   Attribute: () => (/* binding */ Attribute),
2813/* harmony export */   Binary: () => (/* binding */ Binary),
2814/* harmony export */   BinaryOperator: () => (/* binding */ BinaryOperator),
2815/* harmony export */   BinaryOperatorExpr: () => (/* binding */ BinaryOperatorExpr),
2816/* harmony export */   BindingPipe: () => (/* binding */ BindingPipe),
2817/* harmony export */   Block: () => (/* binding */ Block),
2818/* harmony export */   BlockParameter: () => (/* binding */ BlockParameter),
2819/* harmony export */   BoundElementProperty: () => (/* binding */ BoundElementProperty),
2820/* harmony export */   BuiltinType: () => (/* binding */ BuiltinType),
2821/* harmony export */   BuiltinTypeName: () => (/* binding */ BuiltinTypeName),
2822/* harmony export */   CUSTOM_ELEMENTS_SCHEMA: () => (/* binding */ CUSTOM_ELEMENTS_SCHEMA),
2823/* harmony export */   Call: () => (/* binding */ Call),
2824/* harmony export */   Chain: () => (/* binding */ Chain),
2825/* harmony export */   ChangeDetectionStrategy: () => (/* binding */ ChangeDetectionStrategy),
2826/* harmony export */   CommaExpr: () => (/* binding */ CommaExpr),
2827/* harmony export */   Comment: () => (/* binding */ Comment),
2828/* harmony export */   CompilerConfig: () => (/* binding */ CompilerConfig),
2829/* harmony export */   Conditional: () => (/* binding */ Conditional),
2830/* harmony export */   ConditionalExpr: () => (/* binding */ ConditionalExpr),
2831/* harmony export */   ConstantPool: () => (/* binding */ ConstantPool),
2832/* harmony export */   CssSelector: () => (/* binding */ CssSelector),
2833/* harmony export */   DEFAULT_INTERPOLATION_CONFIG: () => (/* binding */ DEFAULT_INTERPOLATION_CONFIG),
2834/* harmony export */   DYNAMIC_TYPE: () => (/* binding */ DYNAMIC_TYPE),
2835/* harmony export */   DeclareFunctionStmt: () => (/* binding */ DeclareFunctionStmt),
2836/* harmony export */   DeclareVarStmt: () => (/* binding */ DeclareVarStmt),
2837/* harmony export */   DomElementSchemaRegistry: () => (/* binding */ DomElementSchemaRegistry),
2838/* harmony export */   DynamicImportExpr: () => (/* binding */ DynamicImportExpr),
2839/* harmony export */   EOF: () => (/* binding */ EOF),
2840/* harmony export */   Element: () => (/* binding */ Element),
2841/* harmony export */   ElementSchemaRegistry: () => (/* binding */ ElementSchemaRegistry),
2842/* harmony export */   EmitterVisitorContext: () => (/* binding */ EmitterVisitorContext),
2843/* harmony export */   EmptyExpr: () => (/* binding */ EmptyExpr$1),
2844/* harmony export */   Expansion: () => (/* binding */ Expansion),
2845/* harmony export */   ExpansionCase: () => (/* binding */ ExpansionCase),
2846/* harmony export */   Expression: () => (/* binding */ Expression),
2847/* harmony export */   ExpressionBinding: () => (/* binding */ ExpressionBinding),
2848/* harmony export */   ExpressionStatement: () => (/* binding */ ExpressionStatement),
2849/* harmony export */   ExpressionType: () => (/* binding */ ExpressionType),
2850/* harmony export */   ExternalExpr: () => (/* binding */ ExternalExpr),
2851/* harmony export */   ExternalReference: () => (/* binding */ ExternalReference),
2852/* harmony export */   FactoryTarget: () => (/* binding */ FactoryTarget$1),
2853/* harmony export */   FunctionExpr: () => (/* binding */ FunctionExpr),
2854/* harmony export */   HtmlParser: () => (/* binding */ HtmlParser),
2855/* harmony export */   HtmlTagDefinition: () => (/* binding */ HtmlTagDefinition),
2856/* harmony export */   I18NHtmlParser: () => (/* binding */ I18NHtmlParser),
2857/* harmony export */   IfStmt: () => (/* binding */ IfStmt),
2858/* harmony export */   ImplicitReceiver: () => (/* binding */ ImplicitReceiver),
2859/* harmony export */   InstantiateExpr: () => (/* binding */ InstantiateExpr),
2860/* harmony export */   Interpolation: () => (/* binding */ Interpolation$1),
2861/* harmony export */   InterpolationConfig: () => (/* binding */ InterpolationConfig),
2862/* harmony export */   InvokeFunctionExpr: () => (/* binding */ InvokeFunctionExpr),
2863/* harmony export */   JSDocComment: () => (/* binding */ JSDocComment),
2864/* harmony export */   JitEvaluator: () => (/* binding */ JitEvaluator),
2865/* harmony export */   KeyedRead: () => (/* binding */ KeyedRead),
2866/* harmony export */   KeyedWrite: () => (/* binding */ KeyedWrite),
2867/* harmony export */   LeadingComment: () => (/* binding */ LeadingComment),
2868/* harmony export */   Lexer: () => (/* binding */ Lexer),
2869/* harmony export */   LiteralArray: () => (/* binding */ LiteralArray),
2870/* harmony export */   LiteralArrayExpr: () => (/* binding */ LiteralArrayExpr),
2871/* harmony export */   LiteralExpr: () => (/* binding */ LiteralExpr),
2872/* harmony export */   LiteralMap: () => (/* binding */ LiteralMap),
2873/* harmony export */   LiteralMapExpr: () => (/* binding */ LiteralMapExpr),
2874/* harmony export */   LiteralPrimitive: () => (/* binding */ LiteralPrimitive),
2875/* harmony export */   LocalizedString: () => (/* binding */ LocalizedString),
2876/* harmony export */   MapType: () => (/* binding */ MapType),
2877/* harmony export */   MessageBundle: () => (/* binding */ MessageBundle),
2878/* harmony export */   NONE_TYPE: () => (/* binding */ NONE_TYPE),
2879/* harmony export */   NO_ERRORS_SCHEMA: () => (/* binding */ NO_ERRORS_SCHEMA),
2880/* harmony export */   NodeWithI18n: () => (/* binding */ NodeWithI18n),
2881/* harmony export */   NonNullAssert: () => (/* binding */ NonNullAssert),
2882/* harmony export */   NotExpr: () => (/* binding */ NotExpr),
2883/* harmony export */   ParseError: () => (/* binding */ ParseError),
2884/* harmony export */   ParseErrorLevel: () => (/* binding */ ParseErrorLevel),
2885/* harmony export */   ParseLocation: () => (/* binding */ ParseLocation),
2886/* harmony export */   ParseSourceFile: () => (/* binding */ ParseSourceFile),
2887/* harmony export */   ParseSourceSpan: () => (/* binding */ ParseSourceSpan),
2888/* harmony export */   ParseSpan: () => (/* binding */ ParseSpan),
2889/* harmony export */   ParseTreeResult: () => (/* binding */ ParseTreeResult),
2890/* harmony export */   ParsedEvent: () => (/* binding */ ParsedEvent),
2891/* harmony export */   ParsedProperty: () => (/* binding */ ParsedProperty),
2892/* harmony export */   ParsedPropertyType: () => (/* binding */ ParsedPropertyType),
2893/* harmony export */   ParsedVariable: () => (/* binding */ ParsedVariable),
2894/* harmony export */   Parser: () => (/* binding */ Parser$1),
2895/* harmony export */   ParserError: () => (/* binding */ ParserError),
2896/* harmony export */   PrefixNot: () => (/* binding */ PrefixNot),
2897/* harmony export */   PropertyRead: () => (/* binding */ PropertyRead),
2898/* harmony export */   PropertyWrite: () => (/* binding */ PropertyWrite),
2899/* harmony export */   R3BoundTarget: () => (/* binding */ R3BoundTarget),
2900/* harmony export */   R3Identifiers: () => (/* binding */ Identifiers),
2901/* harmony export */   R3NgModuleMetadataKind: () => (/* binding */ R3NgModuleMetadataKind),
2902/* harmony export */   R3SelectorScopeMode: () => (/* binding */ R3SelectorScopeMode),
2903/* harmony export */   R3TargetBinder: () => (/* binding */ R3TargetBinder),
2904/* harmony export */   R3TemplateDependencyKind: () => (/* binding */ R3TemplateDependencyKind),
2905/* harmony export */   ReadKeyExpr: () => (/* binding */ ReadKeyExpr),
2906/* harmony export */   ReadPropExpr: () => (/* binding */ ReadPropExpr),
2907/* harmony export */   ReadVarExpr: () => (/* binding */ ReadVarExpr),
2908/* harmony export */   RecursiveAstVisitor: () => (/* binding */ RecursiveAstVisitor),
2909/* harmony export */   RecursiveVisitor: () => (/* binding */ RecursiveVisitor),
2910/* harmony export */   ResourceLoader: () => (/* binding */ ResourceLoader),
2911/* harmony export */   ReturnStatement: () => (/* binding */ ReturnStatement),
2912/* harmony export */   STRING_TYPE: () => (/* binding */ STRING_TYPE),
2913/* harmony export */   SafeCall: () => (/* binding */ SafeCall),
2914/* harmony export */   SafeKeyedRead: () => (/* binding */ SafeKeyedRead),
2915/* harmony export */   SafePropertyRead: () => (/* binding */ SafePropertyRead),
2916/* harmony export */   SelectorContext: () => (/* binding */ SelectorContext),
2917/* harmony export */   SelectorListContext: () => (/* binding */ SelectorListContext),
2918/* harmony export */   SelectorMatcher: () => (/* binding */ SelectorMatcher),
2919/* harmony export */   Serializer: () => (/* binding */ Serializer),
2920/* harmony export */   SplitInterpolation: () => (/* binding */ SplitInterpolation),
2921/* harmony export */   Statement: () => (/* binding */ Statement),
2922/* harmony export */   StmtModifier: () => (/* binding */ StmtModifier),
2923/* harmony export */   TagContentType: () => (/* binding */ TagContentType),
2924/* harmony export */   TaggedTemplateExpr: () => (/* binding */ TaggedTemplateExpr),
2925/* harmony export */   TemplateBindingParseResult: () => (/* binding */ TemplateBindingParseResult),
2926/* harmony export */   TemplateLiteral: () => (/* binding */ TemplateLiteral),
2927/* harmony export */   TemplateLiteralElement: () => (/* binding */ TemplateLiteralElement),
2928/* harmony export */   Text: () => (/* binding */ Text),
2929/* harmony export */   ThisReceiver: () => (/* binding */ ThisReceiver),
2930/* harmony export */   TmplAstBlockNode: () => (/* binding */ BlockNode),
2931/* harmony export */   TmplAstBoundAttribute: () => (/* binding */ BoundAttribute),
2932/* harmony export */   TmplAstBoundDeferredTrigger: () => (/* binding */ BoundDeferredTrigger),
2933/* harmony export */   TmplAstBoundEvent: () => (/* binding */ BoundEvent),
2934/* harmony export */   TmplAstBoundText: () => (/* binding */ BoundText),
2935/* harmony export */   TmplAstContent: () => (/* binding */ Content),
2936/* harmony export */   TmplAstDeferredBlock: () => (/* binding */ DeferredBlock),
2937/* harmony export */   TmplAstDeferredBlockError: () => (/* binding */ DeferredBlockError),
2938/* harmony export */   TmplAstDeferredBlockLoading: () => (/* binding */ DeferredBlockLoading),
2939/* harmony export */   TmplAstDeferredBlockPlaceholder: () => (/* binding */ DeferredBlockPlaceholder),
2940/* harmony export */   TmplAstDeferredTrigger: () => (/* binding */ DeferredTrigger),
2941/* harmony export */   TmplAstElement: () => (/* binding */ Element$1),
2942/* harmony export */   TmplAstForLoopBlock: () => (/* binding */ ForLoopBlock),
2943/* harmony export */   TmplAstForLoopBlockEmpty: () => (/* binding */ ForLoopBlockEmpty),
2944/* harmony export */   TmplAstHoverDeferredTrigger: () => (/* binding */ HoverDeferredTrigger),
2945/* harmony export */   TmplAstIcu: () => (/* binding */ Icu$1),
2946/* harmony export */   TmplAstIdleDeferredTrigger: () => (/* binding */ IdleDeferredTrigger),
2947/* harmony export */   TmplAstIfBlock: () => (/* binding */ IfBlock),
2948/* harmony export */   TmplAstIfBlockBranch: () => (/* binding */ IfBlockBranch),
2949/* harmony export */   TmplAstImmediateDeferredTrigger: () => (/* binding */ ImmediateDeferredTrigger),
2950/* harmony export */   TmplAstInteractionDeferredTrigger: () => (/* binding */ InteractionDeferredTrigger),
2951/* harmony export */   TmplAstRecursiveVisitor: () => (/* binding */ RecursiveVisitor$1),
2952/* harmony export */   TmplAstReference: () => (/* binding */ Reference),
2953/* harmony export */   TmplAstSwitchBlock: () => (/* binding */ SwitchBlock),
2954/* harmony export */   TmplAstSwitchBlockCase: () => (/* binding */ SwitchBlockCase),
2955/* harmony export */   TmplAstTemplate: () => (/* binding */ Template),
2956/* harmony export */   TmplAstText: () => (/* binding */ Text$3),
2957/* harmony export */   TmplAstTextAttribute: () => (/* binding */ TextAttribute),
2958/* harmony export */   TmplAstTimerDeferredTrigger: () => (/* binding */ TimerDeferredTrigger),
2959/* harmony export */   TmplAstUnknownBlock: () => (/* binding */ UnknownBlock),
2960/* harmony export */   TmplAstVariable: () => (/* binding */ Variable),
2961/* harmony export */   TmplAstViewportDeferredTrigger: () => (/* binding */ ViewportDeferredTrigger),
2962/* harmony export */   Token: () => (/* binding */ Token),
2963/* harmony export */   TokenType: () => (/* binding */ TokenType),
2964/* harmony export */   TransplantedType: () => (/* binding */ TransplantedType),
2965/* harmony export */   TreeError: () => (/* binding */ TreeError),
2966/* harmony export */   Type: () => (/* binding */ Type),
2967/* harmony export */   TypeModifier: () => (/* binding */ TypeModifier),
2968/* harmony export */   TypeofExpr: () => (/* binding */ TypeofExpr),
2969/* harmony export */   Unary: () => (/* binding */ Unary),
2970/* harmony export */   UnaryOperator: () => (/* binding */ UnaryOperator),
2971/* harmony export */   UnaryOperatorExpr: () => (/* binding */ UnaryOperatorExpr),
2972/* harmony export */   VERSION: () => (/* binding */ VERSION),
2973/* harmony export */   VariableBinding: () => (/* binding */ VariableBinding),
2974/* harmony export */   Version: () => (/* binding */ Version),
2975/* harmony export */   ViewEncapsulation: () => (/* binding */ ViewEncapsulation),
2976/* harmony export */   WrappedNodeExpr: () => (/* binding */ WrappedNodeExpr),
2977/* harmony export */   WriteKeyExpr: () => (/* binding */ WriteKeyExpr),
2978/* harmony export */   WritePropExpr: () => (/* binding */ WritePropExpr),
2979/* harmony export */   WriteVarExpr: () => (/* binding */ WriteVarExpr),
2980/* harmony export */   Xliff: () => (/* binding */ Xliff),
2981/* harmony export */   Xliff2: () => (/* binding */ Xliff2),
2982/* harmony export */   Xmb: () => (/* binding */ Xmb),
2983/* harmony export */   XmlParser: () => (/* binding */ XmlParser),
2984/* harmony export */   Xtb: () => (/* binding */ Xtb),
2985/* harmony export */   compileClassDebugInfo: () => (/* binding */ compileClassDebugInfo),
2986/* harmony export */   compileClassMetadata: () => (/* binding */ compileClassMetadata),
2987/* harmony export */   compileComponentClassMetadata: () => (/* binding */ compileComponentClassMetadata),
2988/* harmony export */   compileComponentFromMetadata: () => (/* binding */ compileComponentFromMetadata),
2989/* harmony export */   compileDeclareClassMetadata: () => (/* binding */ compileDeclareClassMetadata),
2990/* harmony export */   compileDeclareComponentFromMetadata: () => (/* binding */ compileDeclareComponentFromMetadata),
2991/* harmony export */   compileDeclareDirectiveFromMetadata: () => (/* binding */ compileDeclareDirectiveFromMetadata),
2992/* harmony export */   compileDeclareFactoryFunction: () => (/* binding */ compileDeclareFactoryFunction),
2993/* harmony export */   compileDeclareInjectableFromMetadata: () => (/* binding */ compileDeclareInjectableFromMetadata),
2994/* harmony export */   compileDeclareInjectorFromMetadata: () => (/* binding */ compileDeclareInjectorFromMetadata),
2995/* harmony export */   compileDeclareNgModuleFromMetadata: () => (/* binding */ compileDeclareNgModuleFromMetadata),
2996/* harmony export */   compileDeclarePipeFromMetadata: () => (/* binding */ compileDeclarePipeFromMetadata),
2997/* harmony export */   compileDirectiveFromMetadata: () => (/* binding */ compileDirectiveFromMetadata),
2998/* harmony export */   compileFactoryFunction: () => (/* binding */ compileFactoryFunction),
2999/* harmony export */   compileInjectable: () => (/* binding */ compileInjectable),
3000/* harmony export */   compileInjector: () => (/* binding */ compileInjector),
3001/* harmony export */   compileNgModule: () => (/* binding */ compileNgModule),
3002/* harmony export */   compilePipeFromMetadata: () => (/* binding */ compilePipeFromMetadata),
3003/* harmony export */   computeMsgId: () => (/* binding */ computeMsgId),
3004/* harmony export */   core: () => (/* binding */ core),
3005/* harmony export */   createCssSelectorFromNode: () => (/* binding */ createCssSelectorFromNode),
3006/* harmony export */   createInjectableType: () => (/* binding */ createInjectableType),
3007/* harmony export */   createMayBeForwardRefExpression: () => (/* binding */ createMayBeForwardRefExpression),
3008/* harmony export */   devOnlyGuardedExpression: () => (/* binding */ devOnlyGuardedExpression),
3009/* harmony export */   emitDistinctChangesOnlyDefaultValue: () => (/* binding */ emitDistinctChangesOnlyDefaultValue),
3010/* harmony export */   encapsulateStyle: () => (/* binding */ encapsulateStyle),
3011/* harmony export */   getHtmlTagDefinition: () => (/* binding */ getHtmlTagDefinition),
3012/* harmony export */   getNsPrefix: () => (/* binding */ getNsPrefix),
3013/* harmony export */   getSafePropertyAccessString: () => (/* binding */ getSafePropertyAccessString),
3014/* harmony export */   identifierName: () => (/* binding */ identifierName),
3015/* harmony export */   isIdentifier: () => (/* binding */ isIdentifier),
3016/* harmony export */   isNgContainer: () => (/* binding */ isNgContainer),
3017/* harmony export */   isNgContent: () => (/* binding */ isNgContent),
3018/* harmony export */   isNgTemplate: () => (/* binding */ isNgTemplate),
3019/* harmony export */   jsDocComment: () => (/* binding */ jsDocComment),
3020/* harmony export */   leadingComment: () => (/* binding */ leadingComment),
3021/* harmony export */   literal: () => (/* binding */ literal),
3022/* harmony export */   literalMap: () => (/* binding */ literalMap),
3023/* harmony export */   makeBindingParser: () => (/* binding */ makeBindingParser),
3024/* harmony export */   mergeNsAndName: () => (/* binding */ mergeNsAndName),
3025/* harmony export */   outputAst: () => (/* binding */ output_ast),
3026/* harmony export */   parseHostBindings: () => (/* binding */ parseHostBindings),
3027/* harmony export */   parseTemplate: () => (/* binding */ parseTemplate),
3028/* harmony export */   preserveWhitespacesDefault: () => (/* binding */ preserveWhitespacesDefault),
3029/* harmony export */   publishFacade: () => (/* binding */ publishFacade),
3030/* harmony export */   r3JitTypeSourceSpan: () => (/* binding */ r3JitTypeSourceSpan),
3031/* harmony export */   sanitizeIdentifier: () => (/* binding */ sanitizeIdentifier),
3032/* harmony export */   splitNsName: () => (/* binding */ splitNsName),
3033/* harmony export */   tmplAstVisitAll: () => (/* binding */ visitAll$1),
3034/* harmony export */   verifyHostBindings: () => (/* binding */ verifyHostBindings),
3035/* harmony export */   visitAll: () => (/* binding */ visitAll)
3036/* harmony export */ });
3037/**
3038 * @license Angular v17.3.9
3039 * (c) 2010-2024 Google LLC. https://angular.io/
3040 * License: MIT
3041 */
3042
3043const _SELECTOR_REGEXP = new RegExp('(\\:not\\()|' +
3044// 1: ":not("
3045'(([\\.\\#]?)[-\\w]+)|' +
3046// 2: "tag"; 3: "."/"#";
3047// "-" should appear first in the regexp below as FF31 parses "[.-\w]" as a range
3048// 4: attribute; 5: attribute_string; 6: attribute_value
3049'(?:\\[([-.\\w*\\\\$]+)(?:=([\"\']?)([^\\]\"\']*)\\5)?\\])|' +
3050// "[name]", "[name=value]",
3051// "[name="value"]",
3052// "[name='value']"
3053'(\\))|' +
3054// 7: ")"
3055'(\\s*,\\s*)',
3056// 8: ","
3057'g');
3058/**
3059 * A css selector contains an element name,
3060 * css classes and attribute/value pairs with the purpose
3061 * of selecting subsets out of them.
3062 */
3063class CssSelector {
3064  constructor() {
3065    this.element = null;
3066    this.classNames = [];
3067    /**
3068     * The selectors are encoded in pairs where:
3069     * - even locations are attribute names
3070     * - odd locations are attribute values.
3071     *
3072     * Example:
3073     * Selector: `[key1=value1][key2]` would parse to:
3074     * ```
3075     * ['key1', 'value1', 'key2', '']
3076     * ```
3077     */
3078    this.attrs = [];
3079    this.notSelectors = [];
3080  }
3081  static parse(selector) {
3082    const results = [];
3083    const _addResult = (res, cssSel) => {
3084      if (cssSel.notSelectors.length > 0 && !cssSel.element && cssSel.classNames.length == 0 && cssSel.attrs.length == 0) {
3085        cssSel.element = '*';
3086      }
3087      res.push(cssSel);
3088    };
3089    let cssSelector = new CssSelector();
3090    let match;
3091    let current = cssSelector;
3092    let inNot = false;
3093    _SELECTOR_REGEXP.lastIndex = 0;
3094    while (match = _SELECTOR_REGEXP.exec(selector)) {
3095      if (match[1 /* SelectorRegexp.NOT */]) {
3096        if (inNot) {
3097          throw new Error('Nesting :not in a selector is not allowed');
3098        }
3099        inNot = true;
3100        current = new CssSelector();
3101        cssSelector.notSelectors.push(current);
3102      }
3103      const tag = match[2 /* SelectorRegexp.TAG */];
3104      if (tag) {
3105        const prefix = match[3 /* SelectorRegexp.PREFIX */];
3106        if (prefix === '#') {
3107          // #hash
3108          current.addAttribute('id', tag.slice(1));
3109        } else if (prefix === '.') {
3110          // Class
3111          current.addClassName(tag.slice(1));
3112        } else {
3113          // Element
3114          current.setElement(tag);
3115        }
3116      }
3117      const attribute = match[4 /* SelectorRegexp.ATTRIBUTE */];
3118      if (attribute) {
3119        current.addAttribute(current.unescapeAttribute(attribute), match[6 /* SelectorRegexp.ATTRIBUTE_VALUE */]);
3120      }
3121      if (match[7 /* SelectorRegexp.NOT_END */]) {
3122        inNot = false;
3123        current = cssSelector;
3124      }
3125      if (match[8 /* SelectorRegexp.SEPARATOR */]) {
3126        if (inNot) {
3127          throw new Error('Multiple selectors in :not are not supported');
3128        }
3129        _addResult(results, cssSelector);
3130        cssSelector = current = new CssSelector();
3131      }
3132    }
3133    _addResult(results, cssSelector);
3134    return results;
3135  }
3136  /**
3137   * Unescape `\$` sequences from the CSS attribute selector.
3138   *
3139   * This is needed because `$` can have a special meaning in CSS selectors,
3140   * but we might want to match an attribute that contains `$`.
3141   * [MDN web link for more
3142   * info](https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors).
3143   * @param attr the attribute to unescape.
3144   * @returns the unescaped string.
3145   */
3146  unescapeAttribute(attr) {
3147    let result = '';
3148    let escaping = false;
3149    for (let i = 0; i < attr.length; i++) {
3150      const char = attr.charAt(i);
3151      if (char === '\\') {
3152        escaping = true;
3153        continue;
3154      }
3155      if (char === '$' && !escaping) {
3156        throw new Error(`Error in attribute selector "${attr}". ` + `Unescaped "$" is not supported. Please escape with "\\$".`);
3157      }
3158      escaping = false;
3159      result += char;
3160    }
3161    return result;
3162  }
3163  /**
3164   * Escape `$` sequences from the CSS attribute selector.
3165   *
3166   * This is needed because `$` can have a special meaning in CSS selectors,
3167   * with this method we are escaping `$` with `\$'.
3168   * [MDN web link for more
3169   * info](https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors).
3170   * @param attr the attribute to escape.
3171   * @returns the escaped string.
3172   */
3173  escapeAttribute(attr) {
3174    return attr.replace(/\\/g, '\\\\').replace(/\$/g, '\\$');
3175  }
3176  isElementSelector() {
3177    return this.hasElementSelector() && this.classNames.length == 0 && this.attrs.length == 0 && this.notSelectors.length === 0;
3178  }
3179  hasElementSelector() {
3180    return !!this.element;
3181  }
3182  setElement(element = null) {
3183    this.element = element;
3184  }
3185  getAttrs() {
3186    const result = [];
3187    if (this.classNames.length > 0) {
3188      result.push('class', this.classNames.join(' '));
3189    }
3190    return result.concat(this.attrs);
3191  }
3192  addAttribute(name, value = '') {
3193    this.attrs.push(name, value && value.toLowerCase() || '');
3194  }
3195  addClassName(name) {
3196    this.classNames.push(name.toLowerCase());
3197  }
3198  toString() {
3199    let res = this.element || '';
3200    if (this.classNames) {
3201      this.classNames.forEach(klass => res += `.${klass}`);
3202    }
3203    if (this.attrs) {
3204      for (let i = 0; i < this.attrs.length; i += 2) {
3205        const name = this.escapeAttribute(this.attrs[i]);
3206        const value = this.attrs[i + 1];
3207        res += `[${name}${value ? '=' + value : ''}]`;
3208      }
3209    }
3210    this.notSelectors.forEach(notSelector => res += `:not(${notSelector})`);
3211    return res;
3212  }
3213}
3214/**
3215 * Reads a list of CssSelectors and allows to calculate which ones
3216 * are contained in a given CssSelector.
3217 */
3218class SelectorMatcher {
3219  constructor() {
3220    this._elementMap = new Map();
3221    this._elementPartialMap = new Map();
3222    this._classMap = new Map();
3223    this._classPartialMap = new Map();
3224    this._attrValueMap = new Map();
3225    this._attrValuePartialMap = new Map();
3226    this._listContexts = [];
3227  }
3228  static createNotMatcher(notSelectors) {
3229    const notMatcher = new SelectorMatcher();
3230    notMatcher.addSelectables(notSelectors, null);
3231    return notMatcher;
3232  }
3233  addSelectables(cssSelectors, callbackCtxt) {
3234    let listContext = null;
3235    if (cssSelectors.length > 1) {
3236      listContext = new SelectorListContext(cssSelectors);
3237      this._listContexts.push(listContext);
3238    }
3239    for (let i = 0; i < cssSelectors.length; i++) {
3240      this._addSelectable(cssSelectors[i], callbackCtxt, listContext);
3241    }
3242  }
3243  /**
3244   * Add an object that can be found later on by calling `match`.
3245   * @param cssSelector A css selector
3246   * @param callbackCtxt An opaque object that will be given to the callback of the `match` function
3247   */
3248  _addSelectable(cssSelector, callbackCtxt, listContext) {
3249    let matcher = this;
3250    const element = cssSelector.element;
3251    const classNames = cssSelector.classNames;
3252    const attrs = cssSelector.attrs;
3253    const selectable = new SelectorContext(cssSelector, callbackCtxt, listContext);
3254    if (element) {
3255      const isTerminal = attrs.length === 0 && classNames.length === 0;
3256      if (isTerminal) {
3257        this._addTerminal(matcher._elementMap, element, selectable);
3258      } else {
3259        matcher = this._addPartial(matcher._elementPartialMap, element);
3260      }
3261    }
3262    if (classNames) {
3263      for (let i = 0; i < classNames.length; i++) {
3264        const isTerminal = attrs.length === 0 && i === classNames.length - 1;
3265        const className = classNames[i];
3266        if (isTerminal) {
3267          this._addTerminal(matcher._classMap, className, selectable);
3268        } else {
3269          matcher = this._addPartial(matcher._classPartialMap, className);
3270        }
3271      }
3272    }
3273    if (attrs) {
3274      for (let i = 0; i < attrs.length; i += 2) {
3275        const isTerminal = i === attrs.length - 2;
3276        const name = attrs[i];
3277        const value = attrs[i + 1];
3278        if (isTerminal) {
3279          const terminalMap = matcher._attrValueMap;
3280          let terminalValuesMap = terminalMap.get(name);
3281          if (!terminalValuesMap) {
3282            terminalValuesMap = new Map();
3283            terminalMap.set(name, terminalValuesMap);
3284          }
3285          this._addTerminal(terminalValuesMap, value, selectable);
3286        } else {
3287          const partialMap = matcher._attrValuePartialMap;
3288          let partialValuesMap = partialMap.get(name);
3289          if (!partialValuesMap) {
3290            partialValuesMap = new Map();
3291            partialMap.set(name, partialValuesMap);
3292          }
3293          matcher = this._addPartial(partialValuesMap, value);
3294        }
3295      }
3296    }
3297  }
3298  _addTerminal(map, name, selectable) {
3299    let terminalList = map.get(name);
3300    if (!terminalList) {
3301      terminalList = [];
3302      map.set(name, terminalList);
3303    }
3304    terminalList.push(selectable);
3305  }
3306  _addPartial(map, name) {
3307    let matcher = map.get(name);
3308    if (!matcher) {
3309      matcher = new SelectorMatcher();
3310      map.set(name, matcher);
3311    }
3312    return matcher;
3313  }
3314  /**
3315   * Find the objects that have been added via `addSelectable`
3316   * whose css selector is contained in the given css selector.
3317   * @param cssSelector A css selector
3318   * @param matchedCallback This callback will be called with the object handed into `addSelectable`
3319   * @return boolean true if a match was found
3320   */
3321  match(cssSelector, matchedCallback) {
3322    let result = false;
3323    const element = cssSelector.element;
3324    const classNames = cssSelector.classNames;
3325    const attrs = cssSelector.attrs;
3326    for (let i = 0; i < this._listContexts.length; i++) {
3327      this._listContexts[i].alreadyMatched = false;
3328    }
3329    result = this._matchTerminal(this._elementMap, element, cssSelector, matchedCallback) || result;
3330    result = this._matchPartial(this._elementPartialMap, element, cssSelector, matchedCallback) || result;
3331    if (classNames) {
3332      for (let i = 0; i < classNames.length; i++) {
3333        const className = classNames[i];
3334        result = this._matchTerminal(this._classMap, className, cssSelector, matchedCallback) || result;
3335        result = this._matchPartial(this._classPartialMap, className, cssSelector, matchedCallback) || result;
3336      }
3337    }
3338    if (attrs) {
3339      for (let i = 0; i < attrs.length; i += 2) {
3340        const name = attrs[i];
3341        const value = attrs[i + 1];
3342        const terminalValuesMap = this._attrValueMap.get(name);
3343        if (value) {
3344          result = this._matchTerminal(terminalValuesMap, '', cssSelector, matchedCallback) || result;
3345        }
3346        result = this._matchTerminal(terminalValuesMap, value, cssSelector, matchedCallback) || result;
3347        const partialValuesMap = this._attrValuePartialMap.get(name);
3348        if (value) {
3349          result = this._matchPartial(partialValuesMap, '', cssSelector, matchedCallback) || result;
3350        }
3351        result = this._matchPartial(partialValuesMap, value, cssSelector, matchedCallback) || result;
3352      }
3353    }
3354    return result;
3355  }
3356  /** @internal */
3357  _matchTerminal(map, name, cssSelector, matchedCallback) {
3358    if (!map || typeof name !== 'string') {
3359      return false;
3360    }
3361    let selectables = map.get(name) || [];
3362    const starSelectables = map.get('*');
3363    if (starSelectables) {
3364      selectables = selectables.concat(starSelectables);
3365    }
3366    if (selectables.length === 0) {
3367      return false;
3368    }
3369    let selectable;
3370    let result = false;
3371    for (let i = 0; i < selectables.length; i++) {
3372      selectable = selectables[i];
3373      result = selectable.finalize(cssSelector, matchedCallback) || result;
3374    }
3375    return result;
3376  }
3377  /** @internal */
3378  _matchPartial(map, name, cssSelector, matchedCallback) {
3379    if (!map || typeof name !== 'string') {
3380      return false;
3381    }
3382    const nestedSelector = map.get(name);
3383    if (!nestedSelector) {
3384      return false;
3385    }
3386    // TODO(perf): get rid of recursion and measure again
3387    // TODO(perf): don't pass the whole selector into the recursion,
3388    // but only the not processed parts
3389    return nestedSelector.match(cssSelector, matchedCallback);
3390  }
3391}
3392class SelectorListContext {
3393  constructor(selectors) {
3394    this.selectors = selectors;
3395    this.alreadyMatched = false;
3396  }
3397}
3398// Store context to pass back selector and context when a selector is matched
3399class SelectorContext {
3400  constructor(selector, cbContext, listContext) {
3401    this.selector = selector;
3402    this.cbContext = cbContext;
3403    this.listContext = listContext;
3404    this.notSelectors = selector.notSelectors;
3405  }
3406  finalize(cssSelector, callback) {
3407    let result = true;
3408    if (this.notSelectors.length > 0 && (!this.listContext || !this.listContext.alreadyMatched)) {
3409      const notMatcher = SelectorMatcher.createNotMatcher(this.notSelectors);
3410      result = !notMatcher.match(cssSelector, null);
3411    }
3412    if (result && callback && (!this.listContext || !this.listContext.alreadyMatched)) {
3413      if (this.listContext) {
3414        this.listContext.alreadyMatched = true;
3415      }
3416      callback(this.selector, this.cbContext);
3417    }
3418    return result;
3419  }
3420}
3421
3422// Attention:
3423// Stores the default value of `emitDistinctChangesOnly` when the `emitDistinctChangesOnly` is not
3424// explicitly set.
3425const emitDistinctChangesOnlyDefaultValue = true;
3426var ViewEncapsulation;
3427(function (ViewEncapsulation) {
3428  ViewEncapsulation[ViewEncapsulation["Emulated"] = 0] = "Emulated";
3429  // Historically the 1 value was for `Native` encapsulation which has been removed as of v11.
3430  ViewEncapsulation[ViewEncapsulation["None"] = 2] = "None";
3431  ViewEncapsulation[ViewEncapsulation["ShadowDom"] = 3] = "ShadowDom";
3432})(ViewEncapsulation || (ViewEncapsulation = {}));
3433var ChangeDetectionStrategy;
3434(function (ChangeDetectionStrategy) {
3435  ChangeDetectionStrategy[ChangeDetectionStrategy["OnPush"] = 0] = "OnPush";
3436  ChangeDetectionStrategy[ChangeDetectionStrategy["Default"] = 1] = "Default";
3437})(ChangeDetectionStrategy || (ChangeDetectionStrategy = {}));
3438/** Flags describing an input for a directive. */
3439var InputFlags;
3440(function (InputFlags) {
3441  InputFlags[InputFlags["None"] = 0] = "None";
3442  InputFlags[InputFlags["SignalBased"] = 1] = "SignalBased";
3443  InputFlags[InputFlags["HasDecoratorInputTransform"] = 2] = "HasDecoratorInputTransform";
3444})(InputFlags || (InputFlags = {}));
3445const CUSTOM_ELEMENTS_SCHEMA = {
3446  name: 'custom-elements'
3447};
3448const NO_ERRORS_SCHEMA = {
3449  name: 'no-errors-schema'
3450};
3451const Type$1 = Function;
3452var SecurityContext;
3453(function (SecurityContext) {
3454  SecurityContext[SecurityContext["NONE"] = 0] = "NONE";
3455  SecurityContext[SecurityContext["HTML"] = 1] = "HTML";
3456  SecurityContext[SecurityContext["STYLE"] = 2] = "STYLE";
3457  SecurityContext[SecurityContext["SCRIPT"] = 3] = "SCRIPT";
3458  SecurityContext[SecurityContext["URL"] = 4] = "URL";
3459  SecurityContext[SecurityContext["RESOURCE_URL"] = 5] = "RESOURCE_URL";
3460})(SecurityContext || (SecurityContext = {}));
3461var MissingTranslationStrategy;
3462(function (MissingTranslationStrategy) {
3463  MissingTranslationStrategy[MissingTranslationStrategy["Error"] = 0] = "Error";
3464  MissingTranslationStrategy[MissingTranslationStrategy["Warning"] = 1] = "Warning";
3465  MissingTranslationStrategy[MissingTranslationStrategy["Ignore"] = 2] = "Ignore";
3466})(MissingTranslationStrategy || (MissingTranslationStrategy = {}));
3467function parserSelectorToSimpleSelector(selector) {
3468  const classes = selector.classNames && selector.classNames.length ? [8 /* SelectorFlags.CLASS */, ...selector.classNames] : [];
3469  const elementName = selector.element && selector.element !== '*' ? selector.element : '';
3470  return [elementName, ...selector.attrs, ...classes];
3471}
3472function parserSelectorToNegativeSelector(selector) {
3473  const classes = selector.classNames && selector.classNames.length ? [8 /* SelectorFlags.CLASS */, ...selector.classNames] : [];
3474  if (selector.element) {
3475    return [1 /* SelectorFlags.NOT */ | 4 /* SelectorFlags.ELEMENT */, selector.element, ...selector.attrs, ...classes];
3476  } else if (selector.attrs.length) {
3477    return [1 /* SelectorFlags.NOT */ | 2 /* SelectorFlags.ATTRIBUTE */, ...selector.attrs, ...classes];
3478  } else {
3479    return selector.classNames && selector.classNames.length ? [1 /* SelectorFlags.NOT */ | 8 /* SelectorFlags.CLASS */, ...selector.classNames] : [];
3480  }
3481}
3482function parserSelectorToR3Selector(selector) {
3483  const positive = parserSelectorToSimpleSelector(selector);
3484  const negative = selector.notSelectors && selector.notSelectors.length ? selector.notSelectors.map(notSelector => parserSelectorToNegativeSelector(notSelector)) : [];
3485  return positive.concat(...negative);
3486}
3487function parseSelectorToR3Selector(selector) {
3488  return selector ? CssSelector.parse(selector).map(parserSelectorToR3Selector) : [];
3489}
3490var core = /*#__PURE__*/Object.freeze({
3491  __proto__: null,
3492  emitDistinctChangesOnlyDefaultValue: emitDistinctChangesOnlyDefaultValue,
3493  get ViewEncapsulation() {
3494    return ViewEncapsulation;
3495  },
3496  get ChangeDetectionStrategy() {
3497    return ChangeDetectionStrategy;
3498  },
3499  get InputFlags() {
3500    return InputFlags;
3501  },
3502  CUSTOM_ELEMENTS_SCHEMA: CUSTOM_ELEMENTS_SCHEMA,
3503  NO_ERRORS_SCHEMA: NO_ERRORS_SCHEMA,
3504  Type: Type$1,
3505  get SecurityContext() {
3506    return SecurityContext;
3507  },
3508  get MissingTranslationStrategy() {
3509    return MissingTranslationStrategy;
3510  },
3511  parseSelectorToR3Selector: parseSelectorToR3Selector
3512});
3513
3514/**
3515 * A lazily created TextEncoder instance for converting strings into UTF-8 bytes
3516 */
3517let textEncoder;
3518/**
3519 * Return the message id or compute it using the XLIFF1 digest.
3520 */
3521function digest$1(message) {
3522  return message.id || computeDigest(message);
3523}
3524/**
3525 * Compute the message id using the XLIFF1 digest.
3526 */
3527function computeDigest(message) {
3528  return sha1(serializeNodes(message.nodes).join('') + `[${message.meaning}]`);
3529}
3530/**
3531 * Return the message id or compute it using the XLIFF2/XMB/$localize digest.
3532 */
3533function decimalDigest(message) {
3534  return message.id || computeDecimalDigest(message);
3535}
3536/**
3537 * Compute the message id using the XLIFF2/XMB/$localize digest.
3538 */
3539function computeDecimalDigest(message) {
3540  const visitor = new _SerializerIgnoreIcuExpVisitor();
3541  const parts = message.nodes.map(a => a.visit(visitor, null));
3542  return computeMsgId(parts.join(''), message.meaning);
3543}
3544/**
3545 * Serialize the i18n ast to something xml-like in order to generate an UID.
3546 *
3547 * The visitor is also used in the i18n parser tests
3548 *
3549 * @internal
3550 */
3551class _SerializerVisitor {
3552  visitText(text, context) {
3553    return text.value;
3554  }
3555  visitContainer(container, context) {
3556    return `[${container.children.map(child => child.visit(this)).join(', ')}]`;
3557  }
3558  visitIcu(icu, context) {
3559    const strCases = Object.keys(icu.cases).map(k => `${k} {${icu.cases[k].visit(this)}}`);
3560    return `{${icu.expression}, ${icu.type}, ${strCases.join(', ')}}`;
3561  }
3562  visitTagPlaceholder(ph, context) {
3563    return ph.isVoid ? `<ph tag name="${ph.startName}"/>` : `<ph tag name="${ph.startName}">${ph.children.map(child => child.visit(this)).join(', ')}</ph name="${ph.closeName}">`;
3564  }
3565  visitPlaceholder(ph, context) {
3566    return ph.value ? `<ph name="${ph.name}">${ph.value}</ph>` : `<ph name="${ph.name}"/>`;
3567  }
3568  visitIcuPlaceholder(ph, context) {
3569    return `<ph icu name="${ph.name}">${ph.value.visit(this)}</ph>`;
3570  }
3571  visitBlockPlaceholder(ph, context) {
3572    return `<ph block name="${ph.startName}">${ph.children.map(child => child.visit(this)).join(', ')}</ph name="${ph.closeName}">`;
3573  }
3574}
3575const serializerVisitor$1 = new _SerializerVisitor();
3576function serializeNodes(nodes) {
3577  return nodes.map(a => a.visit(serializerVisitor$1, null));
3578}
3579/**
3580 * Serialize the i18n ast to something xml-like in order to generate an UID.
3581 *
3582 * Ignore the ICU expressions so that message IDs stays identical if only the expression changes.
3583 *
3584 * @internal
3585 */
3586class _SerializerIgnoreIcuExpVisitor extends _SerializerVisitor {
3587  visitIcu(icu, context) {
3588    let strCases = Object.keys(icu.cases).map(k => `${k} {${icu.cases[k].visit(this)}}`);
3589    // Do not take the expression into account
3590    return `{${icu.type}, ${strCases.join(', ')}}`;
3591  }
3592}
3593/**
3594 * Compute the SHA1 of the given string
3595 *
3596 * see https://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf
3597 *
3598 * WARNING: this function has not been designed not tested with security in mind.
3599 *          DO NOT USE IT IN A SECURITY SENSITIVE CONTEXT.
3600 */
3601function sha1(str) {
3602  textEncoder ??= new TextEncoder();
3603  const utf8 = [...textEncoder.encode(str)];
3604  const words32 = bytesToWords32(utf8, Endian.Big);
3605  const len = utf8.length * 8;
3606  const w = new Uint32Array(80);
3607  let a = 0x67452301,
3608    b = 0xefcdab89,
3609    c = 0x98badcfe,
3610    d = 0x10325476,
3611    e = 0xc3d2e1f0;
3612  words32[len >> 5] |= 0x80 << 24 - len % 32;
3613  words32[(len + 64 >> 9 << 4) + 15] = len;
3614  for (let i = 0; i < words32.length; i += 16) {
3615    const h0 = a,
3616      h1 = b,
3617      h2 = c,
3618      h3 = d,
3619      h4 = e;
3620    for (let j = 0; j < 80; j++) {
3621      if (j < 16) {
3622        w[j] = words32[i + j];
3623      } else {
3624        w[j] = rol32(w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16], 1);
3625      }
3626      const fkVal = fk(j, b, c, d);
3627      const f = fkVal[0];
3628      const k = fkVal[1];
3629      const temp = [rol32(a, 5), f, e, k, w[j]].reduce(add32);
3630      e = d;
3631      d = c;
3632      c = rol32(b, 30);
3633      b = a;
3634      a = temp;
3635    }
3636    a = add32(a, h0);
3637    b = add32(b, h1);
3638    c = add32(c, h2);
3639    d = add32(d, h3);
3640    e = add32(e, h4);
3641  }
3642  // Convert the output parts to a 160-bit hexadecimal string
3643  return toHexU32(a) + toHexU32(b) + toHexU32(c) + toHexU32(d) + toHexU32(e);
3644}
3645/**
3646 * Convert and format a number as a string representing a 32-bit unsigned hexadecimal number.
3647 * @param value The value to format as a string.
3648 * @returns A hexadecimal string representing the value.
3649 */
3650function toHexU32(value) {
3651  // unsigned right shift of zero ensures an unsigned 32-bit number
3652  return (value >>> 0).toString(16).padStart(8, '0');
3653}
3654function fk(index, b, c, d) {
3655  if (index < 20) {
3656    return [b & c | ~b & d, 0x5a827999];
3657  }
3658  if (index < 40) {
3659    return [b ^ c ^ d, 0x6ed9eba1];
3660  }
3661  if (index < 60) {
3662    return [b & c | b & d | c & d, 0x8f1bbcdc];
3663  }
3664  return [b ^ c ^ d, 0xca62c1d6];
3665}
3666/**
3667 * Compute the fingerprint of the given string
3668 *
3669 * The output is 64 bit number encoded as a decimal string
3670 *
3671 * based on:
3672 * https://github.com/google/closure-compiler/blob/master/src/com/google/javascript/jscomp/GoogleJsMessageIdGenerator.java
3673 */
3674function fingerprint(str) {
3675  textEncoder ??= new TextEncoder();
3676  const utf8 = textEncoder.encode(str);
3677  const view = new DataView(utf8.buffer, utf8.byteOffset, utf8.byteLength);
3678  let hi = hash32(view, utf8.length, 0);
3679  let lo = hash32(view, utf8.length, 102072);
3680  if (hi == 0 && (lo == 0 || lo == 1)) {
3681    hi = hi ^ 0x130f9bef;
3682    lo = lo ^ -0x6b5f56d8;
3683  }
3684  return BigInt.asUintN(32, BigInt(hi)) << BigInt(32) | BigInt.asUintN(32, BigInt(lo));
3685}
3686function computeMsgId(msg, meaning = '') {
3687  let msgFingerprint = fingerprint(msg);
3688  if (meaning) {
3689    // Rotate the 64-bit message fingerprint one bit to the left and then add the meaning
3690    // fingerprint.
3691    msgFingerprint = BigInt.asUintN(64, msgFingerprint << BigInt(1)) | msgFingerprint >> BigInt(63) & BigInt(1);
3692    msgFingerprint += fingerprint(meaning);
3693  }
3694  return BigInt.asUintN(63, msgFingerprint).toString();
3695}
3696function hash32(view, length, c) {
3697  let a = 0x9e3779b9,
3698    b = 0x9e3779b9;
3699  let index = 0;
3700  const end = length - 12;
3701  for (; index <= end; index += 12) {
3702    a += view.getUint32(index, true);
3703    b += view.getUint32(index + 4, true);
3704    c += view.getUint32(index + 8, true);
3705    const res = mix(a, b, c);
3706    a = res[0], b = res[1], c = res[2];
3707  }
3708  const remainder = length - index;
3709  // the first byte of c is reserved for the length
3710  c += length;
3711  if (remainder >= 4) {
3712    a += view.getUint32(index, true);
3713    index += 4;
3714    if (remainder >= 8) {
3715      b += view.getUint32(index, true);
3716      index += 4;
3717      // Partial 32-bit word for c
3718      if (remainder >= 9) {
3719        c += view.getUint8(index++) << 8;
3720      }
3721      if (remainder >= 10) {
3722        c += view.getUint8(index++) << 16;
3723      }
3724      if (remainder === 11) {
3725        c += view.getUint8(index++) << 24;
3726      }
3727    } else {
3728      // Partial 32-bit word for b
3729      if (remainder >= 5) {
3730        b += view.getUint8(index++);
3731      }
3732      if (remainder >= 6) {
3733        b += view.getUint8(index++) << 8;
3734      }
3735      if (remainder === 7) {
3736        b += view.getUint8(index++) << 16;
3737      }
3738    }
3739  } else {
3740    // Partial 32-bit word for a
3741    if (remainder >= 1) {
3742      a += view.getUint8(index++);
3743    }
3744    if (remainder >= 2) {
3745      a += view.getUint8(index++) << 8;
3746    }
3747    if (remainder === 3) {
3748      a += view.getUint8(index++) << 16;
3749    }
3750  }
3751  return mix(a, b, c)[2];
3752}
3753// clang-format off
3754function mix(a, b, c) {
3755  a -= b;
3756  a -= c;
3757  a ^= c >>> 13;
3758  b -= c;
3759  b -= a;
3760  b ^= a << 8;
3761  c -= a;
3762  c -= b;
3763  c ^= b >>> 13;
3764  a -= b;
3765  a -= c;
3766  a ^= c >>> 12;
3767  b -= c;
3768  b -= a;
3769  b ^= a << 16;
3770  c -= a;
3771  c -= b;
3772  c ^= b >>> 5;
3773  a -= b;
3774  a -= c;
3775  a ^= c >>> 3;
3776  b -= c;
3777  b -= a;
3778  b ^= a << 10;
3779  c -= a;
3780  c -= b;
3781  c ^= b >>> 15;
3782  return [a, b, c];
3783}
3784// clang-format on
3785// Utils
3786var Endian;
3787(function (Endian) {
3788  Endian[Endian["Little"] = 0] = "Little";
3789  Endian[Endian["Big"] = 1] = "Big";
3790})(Endian || (Endian = {}));
3791function add32(a, b) {
3792  return add32to64(a, b)[1];
3793}
3794function add32to64(a, b) {
3795  const low = (a & 0xffff) + (b & 0xffff);
3796  const high = (a >>> 16) + (b >>> 16) + (low >>> 16);
3797  return [high >>> 16, high << 16 | low & 0xffff];
3798}
3799// Rotate a 32b number left `count` position
3800function rol32(a, count) {
3801  return a << count | a >>> 32 - count;
3802}
3803function bytesToWords32(bytes, endian) {
3804  const size = bytes.length + 3 >>> 2;
3805  const words32 = [];
3806  for (let i = 0; i < size; i++) {
3807    words32[i] = wordAt(bytes, i * 4, endian);
3808  }
3809  return words32;
3810}
3811function byteAt(bytes, index) {
3812  return index >= bytes.length ? 0 : bytes[index];
3813}
3814function wordAt(bytes, index, endian) {
3815  let word = 0;
3816  if (endian === Endian.Big) {
3817    for (let i = 0; i < 4; i++) {
3818      word += byteAt(bytes, index + i) << 24 - 8 * i;
3819    }
3820  } else {
3821    for (let i = 0; i < 4; i++) {
3822      word += byteAt(bytes, index + i) << 8 * i;
3823    }
3824  }
3825  return word;
3826}
3827
3828//// Types
3829var TypeModifier;
3830(function (TypeModifier) {
3831  TypeModifier[TypeModifier["None"] = 0] = "None";
3832  TypeModifier[TypeModifier["Const"] = 1] = "Const";
3833})(TypeModifier || (TypeModifier = {}));
3834class Type {
3835  constructor(modifiers = TypeModifier.None) {
3836    this.modifiers = modifiers;
3837  }
3838  hasModifier(modifier) {
3839    return (this.modifiers & modifier) !== 0;
3840  }
3841}
3842var BuiltinTypeName;
3843(function (BuiltinTypeName) {
3844  BuiltinTypeName[BuiltinTypeName["Dynamic"] = 0] = "Dynamic";
3845  BuiltinTypeName[BuiltinTypeName["Bool"] = 1] = "Bool";
3846  BuiltinTypeName[BuiltinTypeName["String"] = 2] = "String";
3847  BuiltinTypeName[BuiltinTypeName["Int"] = 3] = "Int";
3848  BuiltinTypeName[BuiltinTypeName["Number"] = 4] = "Number";
3849  BuiltinTypeName[BuiltinTypeName["Function"] = 5] = "Function";
3850  BuiltinTypeName[BuiltinTypeName["Inferred"] = 6] = "Inferred";
3851  BuiltinTypeName[BuiltinTypeName["None"] = 7] = "None";
3852})(BuiltinTypeName || (BuiltinTypeName = {}));
3853class BuiltinType extends Type {
3854  constructor(name, modifiers) {
3855    super(modifiers);
3856    this.name = name;
3857  }
3858  visitType(visitor, context) {
3859    return visitor.visitBuiltinType(this, context);
3860  }
3861}
3862class ExpressionType extends Type {
3863  constructor(value, modifiers, typeParams = null) {
3864    super(modifiers);
3865    this.value = value;
3866    this.typeParams = typeParams;
3867  }
3868  visitType(visitor, context) {
3869    return visitor.visitExpressionType(this, context);
3870  }
3871}
3872class ArrayType extends Type {
3873  constructor(of, modifiers) {
3874    super(modifiers);
3875    this.of = of;
3876  }
3877  visitType(visitor, context) {
3878    return visitor.visitArrayType(this, context);
3879  }
3880}
3881class MapType extends Type {
3882  constructor(valueType, modifiers) {
3883    super(modifiers);
3884    this.valueType = valueType || null;
3885  }
3886  visitType(visitor, context) {
3887    return visitor.visitMapType(this, context);
3888  }
3889}
3890class TransplantedType extends Type {
3891  constructor(type, modifiers) {
3892    super(modifiers);
3893    this.type = type;
3894  }
3895  visitType(visitor, context) {
3896    return visitor.visitTransplantedType(this, context);
3897  }
3898}
3899const DYNAMIC_TYPE = new BuiltinType(BuiltinTypeName.Dynamic);
3900const INFERRED_TYPE = new BuiltinType(BuiltinTypeName.Inferred);
3901const BOOL_TYPE = new BuiltinType(BuiltinTypeName.Bool);
3902const INT_TYPE = new BuiltinType(BuiltinTypeName.Int);
3903const NUMBER_TYPE = new BuiltinType(BuiltinTypeName.Number);
3904const STRING_TYPE = new BuiltinType(BuiltinTypeName.String);
3905const FUNCTION_TYPE = new BuiltinType(BuiltinTypeName.Function);
3906const NONE_TYPE = new BuiltinType(BuiltinTypeName.None);
3907///// Expressions
3908var UnaryOperator;
3909(function (UnaryOperator) {
3910  UnaryOperator[UnaryOperator["Minus"] = 0] = "Minus";
3911  UnaryOperator[UnaryOperator["Plus"] = 1] = "Plus";
3912})(UnaryOperator || (UnaryOperator = {}));
3913var BinaryOperator;
3914(function (BinaryOperator) {
3915  BinaryOperator[BinaryOperator["Equals"] = 0] = "Equals";
3916  BinaryOperator[BinaryOperator["NotEquals"] = 1] = "NotEquals";
3917  BinaryOperator[BinaryOperator["Identical"] = 2] = "Identical";
3918  BinaryOperator[BinaryOperator["NotIdentical"] = 3] = "NotIdentical";
3919  BinaryOperator[BinaryOperator["Minus"] = 4] = "Minus";
3920  BinaryOperator[BinaryOperator["Plus"] = 5] = "Plus";
3921  BinaryOperator[BinaryOperator["Divide"] = 6] = "Divide";
3922  BinaryOperator[BinaryOperator["Multiply"] = 7] = "Multiply";
3923  BinaryOperator[BinaryOperator["Modulo"] = 8] = "Modulo";
3924  BinaryOperator[BinaryOperator["And"] = 9] = "And";
3925  BinaryOperator[BinaryOperator["Or"] = 10] = "Or";
3926  BinaryOperator[BinaryOperator["BitwiseOr"] = 11] = "BitwiseOr";
3927  BinaryOperator[BinaryOperator["BitwiseAnd"] = 12] = "BitwiseAnd";
3928  BinaryOperator[BinaryOperator["Lower"] = 13] = "Lower";
3929  BinaryOperator[BinaryOperator["LowerEquals"] = 14] = "LowerEquals";
3930  BinaryOperator[BinaryOperator["Bigger"] = 15] = "Bigger";
3931  BinaryOperator[BinaryOperator["BiggerEquals"] = 16] = "BiggerEquals";
3932  BinaryOperator[BinaryOperator["NullishCoalesce"] = 17] = "NullishCoalesce";
3933})(BinaryOperator || (BinaryOperator = {}));
3934function nullSafeIsEquivalent(base, other) {
3935  if (base == null || other == null) {
3936    return base == other;
3937  }
3938  return base.isEquivalent(other);
3939}
3940function areAllEquivalentPredicate(base, other, equivalentPredicate) {
3941  const len = base.length;
3942  if (len !== other.length) {
3943    return false;
3944  }
3945  for (let i = 0; i < len; i++) {
3946    if (!equivalentPredicate(base[i], other[i])) {
3947      return false;
3948    }
3949  }
3950  return true;
3951}
3952function areAllEquivalent(base, other) {
3953  return areAllEquivalentPredicate(base, other, (baseElement, otherElement) => baseElement.isEquivalent(otherElement));
3954}
3955class Expression {
3956  constructor(type, sourceSpan) {
3957    this.type = type || null;
3958    this.sourceSpan = sourceSpan || null;
3959  }
3960  prop(name, sourceSpan) {
3961    return new ReadPropExpr(this, name, null, sourceSpan);
3962  }
3963  key(index, type, sourceSpan) {
3964    return new ReadKeyExpr(this, index, type, sourceSpan);
3965  }
3966  callFn(params, sourceSpan, pure) {
3967    return new InvokeFunctionExpr(this, params, null, sourceSpan, pure);
3968  }
3969  instantiate(params, type, sourceSpan) {
3970    return new InstantiateExpr(this, params, type, sourceSpan);
3971  }
3972  conditional(trueCase, falseCase = null, sourceSpan) {
3973    return new ConditionalExpr(this, trueCase, falseCase, null, sourceSpan);
3974  }
3975  equals(rhs, sourceSpan) {
3976    return new BinaryOperatorExpr(BinaryOperator.Equals, this, rhs, null, sourceSpan);
3977  }
3978  notEquals(rhs, sourceSpan) {
3979    return new BinaryOperatorExpr(BinaryOperator.NotEquals, this, rhs, null, sourceSpan);
3980  }
3981  identical(rhs, sourceSpan) {
3982    return new BinaryOperatorExpr(BinaryOperator.Identical, this, rhs, null, sourceSpan);
3983  }
3984  notIdentical(rhs, sourceSpan) {
3985    return new BinaryOperatorExpr(BinaryOperator.NotIdentical, this, rhs, null, sourceSpan);
3986  }
3987  minus(rhs, sourceSpan) {
3988    return new BinaryOperatorExpr(BinaryOperator.Minus, this, rhs, null, sourceSpan);
3989  }
3990  plus(rhs, sourceSpan) {
3991    return new BinaryOperatorExpr(BinaryOperator.Plus, this, rhs, null, sourceSpan);
3992  }
3993  divide(rhs, sourceSpan) {
3994    return new BinaryOperatorExpr(BinaryOperator.Divide, this, rhs, null, sourceSpan);
3995  }
3996  multiply(rhs, sourceSpan) {
3997    return new BinaryOperatorExpr(BinaryOperator.Multiply, this, rhs, null, sourceSpan);
3998  }
3999  modulo(rhs, sourceSpan) {
4000    return new BinaryOperatorExpr(BinaryOperator.Modulo, this, rhs, null, sourceSpan);
4001  }
4002  and(rhs, sourceSpan) {
4003    return new BinaryOperatorExpr(BinaryOperator.And, this, rhs, null, sourceSpan);
4004  }
4005  bitwiseOr(rhs, sourceSpan, parens = true) {
4006    return new BinaryOperatorExpr(BinaryOperator.BitwiseOr, this, rhs, null, sourceSpan, parens);
4007  }
4008  bitwiseAnd(rhs, sourceSpan, parens = true) {
4009    return new BinaryOperatorExpr(BinaryOperator.BitwiseAnd, this, rhs, null, sourceSpan, parens);
4010  }
4011  or(rhs, sourceSpan) {
4012    return new BinaryOperatorExpr(BinaryOperator.Or, this, rhs, null, sourceSpan);
4013  }
4014  lower(rhs, sourceSpan) {
4015    return new BinaryOperatorExpr(BinaryOperator.Lower, this, rhs, null, sourceSpan);
4016  }
4017  lowerEquals(rhs, sourceSpan) {
4018    return new BinaryOperatorExpr(BinaryOperator.LowerEquals, this, rhs, null, sourceSpan);
4019  }
4020  bigger(rhs, sourceSpan) {
4021    return new BinaryOperatorExpr(BinaryOperator.Bigger, this, rhs, null, sourceSpan);
4022  }
4023  biggerEquals(rhs, sourceSpan) {
4024    return new BinaryOperatorExpr(BinaryOperator.BiggerEquals, this, rhs, null, sourceSpan);
4025  }
4026  isBlank(sourceSpan) {
4027    // Note: We use equals by purpose here to compare to null and undefined in JS.
4028    // We use the typed null to allow strictNullChecks to narrow types.
4029    return this.equals(TYPED_NULL_EXPR, sourceSpan);
4030  }
4031  nullishCoalesce(rhs, sourceSpan) {
4032    return new BinaryOperatorExpr(BinaryOperator.NullishCoalesce, this, rhs, null, sourceSpan);
4033  }
4034  toStmt() {
4035    return new ExpressionStatement(this, null);
4036  }
4037}
4038class ReadVarExpr extends Expression {
4039  constructor(name, type, sourceSpan) {
4040    super(type, sourceSpan);
4041    this.name = name;
4042  }
4043  isEquivalent(e) {
4044    return e instanceof ReadVarExpr && this.name === e.name;
4045  }
4046  isConstant() {
4047    return false;
4048  }
4049  visitExpression(visitor, context) {
4050    return visitor.visitReadVarExpr(this, context);
4051  }
4052  clone() {
4053    return new ReadVarExpr(this.name, this.type, this.sourceSpan);
4054  }
4055  set(value) {
4056    return new WriteVarExpr(this.name, value, null, this.sourceSpan);
4057  }
4058}
4059class TypeofExpr extends Expression {
4060  constructor(expr, type, sourceSpan) {
4061    super(type, sourceSpan);
4062    this.expr = expr;
4063  }
4064  visitExpression(visitor, context) {
4065    return visitor.visitTypeofExpr(this, context);
4066  }
4067  isEquivalent(e) {
4068    return e instanceof TypeofExpr && e.expr.isEquivalent(this.expr);
4069  }
4070  isConstant() {
4071    return this.expr.isConstant();
4072  }
4073  clone() {
4074    return new TypeofExpr(this.expr.clone());
4075  }
4076}
4077class WrappedNodeExpr extends Expression {
4078  constructor(node, type, sourceSpan) {
4079    super(type, sourceSpan);
4080    this.node = node;
4081  }
4082  isEquivalent(e) {
4083    return e instanceof WrappedNodeExpr && this.node === e.node;
4084  }
4085  isConstant() {
4086    return false;
4087  }
4088  visitExpression(visitor, context) {
4089    return visitor.visitWrappedNodeExpr(this, context);
4090  }
4091  clone() {
4092    return new WrappedNodeExpr(this.node, this.type, this.sourceSpan);
4093  }
4094}
4095class WriteVarExpr extends Expression {
4096  constructor(name, value, type, sourceSpan) {
4097    super(type || value.type, sourceSpan);
4098    this.name = name;
4099    this.value = value;
4100  }
4101  isEquivalent(e) {
4102    return e instanceof WriteVarExpr && this.name === e.name && this.value.isEquivalent(e.value);
4103  }
4104  isConstant() {
4105    return false;
4106  }
4107  visitExpression(visitor, context) {
4108    return visitor.visitWriteVarExpr(this, context);
4109  }
4110  clone() {
4111    return new WriteVarExpr(this.name, this.value.clone(), this.type, this.sourceSpan);
4112  }
4113  toDeclStmt(type, modifiers) {
4114    return new DeclareVarStmt(this.name, this.value, type, modifiers, this.sourceSpan);
4115  }
4116  toConstDecl() {
4117    return this.toDeclStmt(INFERRED_TYPE, StmtModifier.Final);
4118  }
4119}
4120class WriteKeyExpr extends Expression {
4121  constructor(receiver, index, value, type, sourceSpan) {
4122    super(type || value.type, sourceSpan);
4123    this.receiver = receiver;
4124    this.index = index;
4125    this.value = value;
4126  }
4127  isEquivalent(e) {
4128    return e instanceof WriteKeyExpr && this.receiver.isEquivalent(e.receiver) && this.index.isEquivalent(e.index) && this.value.isEquivalent(e.value);
4129  }
4130  isConstant() {
4131    return false;
4132  }
4133  visitExpression(visitor, context) {
4134    return visitor.visitWriteKeyExpr(this, context);
4135  }
4136  clone() {
4137    return new WriteKeyExpr(this.receiver.clone(), this.index.clone(), this.value.clone(), this.type, this.sourceSpan);
4138  }
4139}
4140class WritePropExpr extends Expression {
4141  constructor(receiver, name, value, type, sourceSpan) {
4142    super(type || value.type, sourceSpan);
4143    this.receiver = receiver;
4144    this.name = name;
4145    this.value = value;
4146  }
4147  isEquivalent(e) {
4148    return e instanceof WritePropExpr && this.receiver.isEquivalent(e.receiver) && this.name === e.name && this.value.isEquivalent(e.value);
4149  }
4150  isConstant() {
4151    return false;
4152  }
4153  visitExpression(visitor, context) {
4154    return visitor.visitWritePropExpr(this, context);
4155  }
4156  clone() {
4157    return new WritePropExpr(this.receiver.clone(), this.name, this.value.clone(), this.type, this.sourceSpan);
4158  }
4159}
4160class InvokeFunctionExpr extends Expression {
4161  constructor(fn, args, type, sourceSpan, pure = false) {
4162    super(type, sourceSpan);
4163    this.fn = fn;
4164    this.args = args;
4165    this.pure = pure;
4166  }
4167  // An alias for fn, which allows other logic to handle calls and property reads together.
4168  get receiver() {
4169    return this.fn;
4170  }
4171  isEquivalent(e) {
4172    return e instanceof InvokeFunctionExpr && this.fn.isEquivalent(e.fn) && areAllEquivalent(this.args, e.args) && this.pure === e.pure;
4173  }
4174  isConstant() {
4175    return false;
4176  }
4177  visitExpression(visitor, context) {
4178    return visitor.visitInvokeFunctionExpr(this, context);
4179  }
4180  clone() {
4181    return new InvokeFunctionExpr(this.fn.clone(), this.args.map(arg => arg.clone()), this.type, this.sourceSpan, this.pure);
4182  }
4183}
4184class TaggedTemplateExpr extends Expression {
4185  constructor(tag, template, type, sourceSpan) {
4186    super(type, sourceSpan);
4187    this.tag = tag;
4188    this.template = template;
4189  }
4190  isEquivalent(e) {
4191    return e instanceof TaggedTemplateExpr && this.tag.isEquivalent(e.tag) && areAllEquivalentPredicate(this.template.elements, e.template.elements, (a, b) => a.text === b.text) && areAllEquivalent(this.template.expressions, e.template.expressions);
4192  }
4193  isConstant() {
4194    return false;
4195  }
4196  visitExpression(visitor, context) {
4197    return visitor.visitTaggedTemplateExpr(this, context);
4198  }
4199  clone() {
4200    return new TaggedTemplateExpr(this.tag.clone(), this.template.clone(), this.type, this.sourceSpan);
4201  }
4202}
4203class InstantiateExpr extends Expression {
4204  constructor(classExpr, args, type, sourceSpan) {
4205    super(type, sourceSpan);
4206    this.classExpr = classExpr;
4207    this.args = args;
4208  }
4209  isEquivalent(e) {
4210    return e instanceof InstantiateExpr && this.classExpr.isEquivalent(e.classExpr) && areAllEquivalent(this.args, e.args);
4211  }
4212  isConstant() {
4213    return false;
4214  }
4215  visitExpression(visitor, context) {
4216    return visitor.visitInstantiateExpr(this, context);
4217  }
4218  clone() {
4219    return new InstantiateExpr(this.classExpr.clone(), this.args.map(arg => arg.clone()), this.type, this.sourceSpan);
4220  }
4221}
4222class LiteralExpr extends Expression {
4223  constructor(value, type, sourceSpan) {
4224    super(type, sourceSpan);
4225    this.value = value;
4226  }
4227  isEquivalent(e) {
4228    return e instanceof LiteralExpr && this.value === e.value;
4229  }
4230  isConstant() {
4231    return true;
4232  }
4233  visitExpression(visitor, context) {
4234    return visitor.visitLiteralExpr(this, context);
4235  }
4236  clone() {
4237    return new LiteralExpr(this.value, this.type, this.sourceSpan);
4238  }
4239}
4240class TemplateLiteral {
4241  constructor(elements, expressions) {
4242    this.elements = elements;
4243    this.expressions = expressions;
4244  }
4245  clone() {
4246    return new TemplateLiteral(this.elements.map(el => el.clone()), this.expressions.map(expr => expr.clone()));
4247  }
4248}
4249class TemplateLiteralElement {
4250  constructor(text, sourceSpan, rawText) {
4251    this.text = text;
4252    this.sourceSpan = sourceSpan;
4253    // If `rawText` is not provided, try to extract the raw string from its
4254    // associated `sourceSpan`. If that is also not available, "fake" the raw
4255    // string instead by escaping the following control sequences:
4256    // - "\" would otherwise indicate that the next character is a control character.
4257    // - "`" and "${" are template string control sequences that would otherwise prematurely
4258    // indicate the end of the template literal element.
4259    this.rawText = rawText ?? sourceSpan?.toString() ?? escapeForTemplateLiteral(escapeSlashes(text));
4260  }
4261  clone() {
4262    return new TemplateLiteralElement(this.text, this.sourceSpan, this.rawText);
4263  }
4264}
4265class LiteralPiece {
4266  constructor(text, sourceSpan) {
4267    this.text = text;
4268    this.sourceSpan = sourceSpan;
4269  }
4270}
4271class PlaceholderPiece {
4272  /**
4273   * Create a new instance of a `PlaceholderPiece`.
4274   *
4275   * @param text the name of this placeholder (e.g. `PH_1`).
4276   * @param sourceSpan the location of this placeholder in its localized message the source code.
4277   * @param associatedMessage reference to another message that this placeholder is associated with.
4278   * The `associatedMessage` is mainly used to provide a relationship to an ICU message that has
4279   * been extracted out from the message containing the placeholder.
4280   */
4281  constructor(text, sourceSpan, associatedMessage) {
4282    this.text = text;
4283    this.sourceSpan = sourceSpan;
4284    this.associatedMessage = associatedMessage;
4285  }
4286}
4287const MEANING_SEPARATOR$1 = '|';
4288const ID_SEPARATOR$1 = '@@';
4289const LEGACY_ID_INDICATOR = '␟';
4290class LocalizedString extends Expression {
4291  constructor(metaBlock, messageParts, placeHolderNames, expressions, sourceSpan) {
4292    super(STRING_TYPE, sourceSpan);
4293    this.metaBlock = metaBlock;
4294    this.messageParts = messageParts;
4295    this.placeHolderNames = placeHolderNames;
4296    this.expressions = expressions;
4297  }
4298  isEquivalent(e) {
4299    // return e instanceof LocalizedString && this.message === e.message;
4300    return false;
4301  }
4302  isConstant() {
4303    return false;
4304  }
4305  visitExpression(visitor, context) {
4306    return visitor.visitLocalizedString(this, context);
4307  }
4308  clone() {
4309    return new LocalizedString(this.metaBlock, this.messageParts, this.placeHolderNames, this.expressions.map(expr => expr.clone()), this.sourceSpan);
4310  }
4311  /**
4312   * Serialize the given `meta` and `messagePart` into "cooked" and "raw" strings that can be used
4313   * in a `$localize` tagged string. The format of the metadata is the same as that parsed by
4314   * `parseI18nMeta()`.
4315   *
4316   * @param meta The metadata to serialize
4317   * @param messagePart The first part of the tagged string
4318   */
4319  serializeI18nHead() {
4320    let metaBlock = this.metaBlock.description || '';
4321    if (this.metaBlock.meaning) {
4322      metaBlock = `${this.metaBlock.meaning}${MEANING_SEPARATOR$1}${metaBlock}`;
4323    }
4324    if (this.metaBlock.customId) {
4325      metaBlock = `${metaBlock}${ID_SEPARATOR$1}${this.metaBlock.customId}`;
4326    }
4327    if (this.metaBlock.legacyIds) {
4328      this.metaBlock.legacyIds.forEach(legacyId => {
4329        metaBlock = `${metaBlock}${LEGACY_ID_INDICATOR}${legacyId}`;
4330      });
4331    }
4332    return createCookedRawString(metaBlock, this.messageParts[0].text, this.getMessagePartSourceSpan(0));
4333  }
4334  getMessagePartSourceSpan(i) {
4335    return this.messageParts[i]?.sourceSpan ?? this.sourceSpan;
4336  }
4337  getPlaceholderSourceSpan(i) {
4338    return this.placeHolderNames[i]?.sourceSpan ?? this.expressions[i]?.sourceSpan ?? this.sourceSpan;
4339  }
4340  /**
4341   * Serialize the given `placeholderName` and `messagePart` into "cooked" and "raw" str
4341ings that
4342   * can be used in a `$localize` tagged string.
4343   *
4344   * The format is `:<placeholder-name>[@@<associated-id>]:`.
4345   *
4346   * The `associated-id` is the message id of the (usually an ICU) message to which this placeholder
4347   * refers.
4348   *
4349   * @param partIndex The index of the message part to serialize.
4350   */
4351  serializeI18nTemplatePart(partIndex) {
4352    const placeholder = this.placeHolderNames[partIndex - 1];
4353    const messagePart = this.messageParts[partIndex];
4354    let metaBlock = placeholder.text;
4355    if (placeholder.associatedMessage?.legacyIds.length === 0) {
4356      metaBlock += `${ID_SEPARATOR$1}${computeMsgId(placeholder.associatedMessage.messageString, placeholder.associatedMessage.meaning)}`;
4357    }
4358    return createCookedRawString(metaBlock, messagePart.text, this.getMessagePartSourceSpan(partIndex));
4359  }
4360}
4361const escapeSlashes = str => str.replace(/\\/g, '\\\\');
4362const escapeStartingColon = str => str.replace(/^:/, '\\:');
4363const escapeColons = str => str.replace(/:/g, '\\:');
4364const escapeForTemplateLiteral = str => str.replace(/`/g, '\\`').replace(/\${/g, '$\\{');
4365/**
4366 * Creates a `{cooked, raw}` object from the `metaBlock` and `messagePart`.
4367 *
4368 * The `raw` text must have various character sequences escaped:
4369 * * "\" would otherwise indicate that the next character is a control character.
4370 * * "`" and "${" are template string control sequences that would otherwise prematurely indicate
4371 *   the end of a message part.
4372 * * ":" inside a metablock would prematurely indicate the end of the metablock.
4373 * * ":" at the start of a messagePart with no metablock would erroneously indicate the start of a
4374 *   metablock.
4375 *
4376 * @param metaBlock Any metadata that should be prepended to the string
4377 * @param messagePart The message part of the string
4378 */
4379function createCookedRawString(metaBlock, messagePart, range) {
4380  if (metaBlock === '') {
4381    return {
4382      cooked: messagePart,
4383      raw: escapeForTemplateLiteral(escapeStartingColon(escapeSlashes(messagePart))),
4384      range
4385    };
4386  } else {
4387    return {
4388      cooked: `:${metaBlock}:${messagePart}`,
4389      raw: escapeForTemplateLiteral(`:${escapeColons(escapeSlashes(metaBlock))}:${escapeSlashes(messagePart)}`),
4390      range
4391    };
4392  }
4393}
4394class ExternalExpr extends Expression {
4395  constructor(value, type, typeParams = null, sourceSpan) {
4396    super(type, sourceSpan);
4397    this.value = value;
4398    this.typeParams = typeParams;
4399  }
4400  isEquivalent(e) {
4401    return e instanceof ExternalExpr && this.value.name === e.value.name && this.value.moduleName === e.value.moduleName && this.value.runtime === e.value.runtime;
4402  }
4403  isConstant() {
4404    return false;
4405  }
4406  visitExpression(visitor, context) {
4407    return visitor.visitExternalExpr(this, context);
4408  }
4409  clone() {
4410    return new ExternalExpr(this.value, this.type, this.typeParams, this.sourceSpan);
4411  }
4412}
4413class ExternalReference {
4414  constructor(moduleName, name, runtime) {
4415    this.moduleName = moduleName;
4416    this.name = name;
4417    this.runtime = runtime;
4418  }
4419}
4420class ConditionalExpr extends Expression {
4421  constructor(condition, trueCase, falseCase = null, type, sourceSpan) {
4422    super(type || trueCase.type, sourceSpan);
4423    this.condition = condition;
4424    this.falseCase = falseCase;
4425    this.trueCase = trueCase;
4426  }
4427  isEquivalent(e) {
4428    return e instanceof ConditionalExpr && this.condition.isEquivalent(e.condition) && this.trueCase.isEquivalent(e.trueCase) && nullSafeIsEquivalent(this.falseCase, e.falseCase);
4429  }
4430  isConstant() {
4431    return false;
4432  }
4433  visitExpression(visitor, context) {
4434    return visitor.visitConditionalExpr(this, context);
4435  }
4436  clone() {
4437    return new ConditionalExpr(this.condition.clone(), this.trueCase.clone(), this.falseCase?.clone(), this.type, this.sourceSpan);
4438  }
4439}
4440class DynamicImportExpr extends Expression {
4441  constructor(url, sourceSpan) {
4442    super(null, sourceSpan);
4443    this.url = url;
4444  }
4445  isEquivalent(e) {
4446    return e instanceof DynamicImportExpr && this.url === e.url;
4447  }
4448  isConstant() {
4449    return false;
4450  }
4451  visitExpression(visitor, context) {
4452    return visitor.visitDynamicImportExpr(this, context);
4453  }
4454  clone() {
4455    return new DynamicImportExpr(this.url, this.sourceSpan);
4456  }
4457}
4458class NotExpr extends Expression {
4459  constructor(condition, sourceSpan) {
4460    super(BOOL_TYPE, sourceSpan);
4461    this.condition = condition;
4462  }
4463  isEquivalent(e) {
4464    return e instanceof NotExpr && this.condition.isEquivalent(e.condition);
4465  }
4466  isConstant() {
4467    return false;
4468  }
4469  visitExpression(visitor, context) {
4470    return visitor.visitNotExpr(this, context);
4471  }
4472  clone() {
4473    return new NotExpr(this.condition.clone(), this.sourceSpan);
4474  }
4475}
4476class FnParam {
4477  constructor(name, type = null) {
4478    this.name = name;
4479    this.type = type;
4480  }
4481  isEquivalent(param) {
4482    return this.name === param.name;
4483  }
4484  clone() {
4485    return new FnParam(this.name, this.type);
4486  }
4487}
4488class FunctionExpr extends Expression {
4489  constructor(params, statements, type, sourceSpan, name) {
4490    super(type, sourceSpan);
4491    this.params = params;
4492    this.statements = statements;
4493    this.name = name;
4494  }
4495  isEquivalent(e) {
4496    return (e instanceof FunctionExpr || e instanceof DeclareFunctionStmt) && areAllEquivalent(this.params, e.params) && areAllEquivalent(this.statements, e.statements);
4497  }
4498  isConstant() {
4499    return false;
4500  }
4501  visitExpression(visitor, context) {
4502    return visitor.visitFunctionExpr(this, context);
4503  }
4504  toDeclStmt(name, modifiers) {
4505    return new DeclareFunctionStmt(name, this.params, this.statements, this.type, modifiers, this.sourceSpan);
4506  }
4507  clone() {
4508    // TODO: Should we deep clone statements?
4509    return new FunctionExpr(this.params.map(p => p.clone()), this.statements, this.type, this.sourceSpan, this.name);
4510  }
4511}
4512class ArrowFunctionExpr extends Expression {
4513  // Note that `body: Expression` represents `() => expr` whereas
4514  // `body: Statement[]` represents `() => { expr }`.
4515  constructor(params, body, type, sourceSpan) {
4516    super(type, sourceSpan);
4517    this.params = params;
4518    this.body = body;
4519  }
4520  isEquivalent(e) {
4521    if (!(e instanceof ArrowFunctionExpr) || !areAllEquivalent(this.params, e.params)) {
4522      return false;
4523    }
4524    if (this.body instanceof Expression && e.body instanceof Expression) {
4525      return this.body.isEquivalent(e.body);
4526    }
4527    if (Array.isArray(this.body) && Array.isArray(e.body)) {
4528      return areAllEquivalent(this.body, e.body);
4529    }
4530    return false;
4531  }
4532  isConstant() {
4533    return false;
4534  }
4535  visitExpression(visitor, context) {
4536    return visitor.visitArrowFunctionExpr(this, context);
4537  }
4538  clone() {
4539    // TODO: Should we deep clone statements?
4540    return new ArrowFunctionExpr(this.params.map(p => p.clone()), Array.isArray(this.body) ? this.body : this.body.clone(), this.type, this.sourceSpan);
4541  }
4542  toDeclStmt(name, modifiers) {
4543    return new DeclareVarStmt(name, this, INFERRED_TYPE, modifiers, this.sourceSpan);
4544  }
4545}
4546class UnaryOperatorExpr extends Expression {
4547  constructor(operator, expr, type, sourceSpan, parens = true) {
4548    super(type || NUMBER_TYPE, sourceSpan);
4549    this.operator = operator;
4550    this.expr = expr;
4551    this.parens = parens;
4552  }
4553  isEquivalent(e) {
4554    return e instanceof UnaryOperatorExpr && this.operator === e.operator && this.expr.isEquivalent(e.expr);
4555  }
4556  isConstant() {
4557    return false;
4558  }
4559  visitExpression(visitor, context) {
4560    return visitor.visitUnaryOperatorExpr(this, context);
4561  }
4562  clone() {
4563    return new UnaryOperatorExpr(this.operator, this.expr.clone(), this.type, this.sourceSpan, this.parens);
4564  }
4565}
4566class BinaryOperatorExpr extends Expression {
4567  constructor(operator, lhs, rhs, type, sourceSpan, parens = true) {
4568    super(type || lhs.type, sourceSpan);
4569    this.operator = operator;
4570    this.rhs = rhs;
4571    this.parens = parens;
4572    this.lhs = lhs;
4573  }
4574  isEquivalent(e) {
4575    return e instanceof BinaryOperatorExpr && this.operator === e.operator && this.lhs.isEquivalent(e.lhs) && this.rhs.isEquivalent(e.rhs);
4576  }
4577  isConstant() {
4578    return false;
4579  }
4580  visitExpression(visitor, context) {
4581    return visitor.visitBinaryOperatorExpr(this, context);
4582  }
4583  clone() {
4584    return new BinaryOperatorExpr(this.operator, this.lhs.clone(), this.rhs.clone(), this.type, this.sourceSpan, this.parens);
4585  }
4586}
4587class ReadPropExpr extends Expression {
4588  constructor(receiver, name, type, sourceSpan) {
4589    super(type, sourceSpan);
4590    this.receiver = receiver;
4591    this.name = name;
4592  }
4593  // An alias for name, which allows other logic to handle property reads and keyed reads together.
4594  get index() {
4595    return this.name;
4596  }
4597  isEquivalent(e) {
4598    return e instanceof ReadPropExpr && this.receiver.isEquivalent(e.receiver) && this.name === e.name;
4599  }
4600  isConstant() {
4601    return false;
4602  }
4603  visitExpression(visitor, context) {
4604    return visitor.visitReadPropExpr(this, context);
4605  }
4606  set(value) {
4607    return new WritePropExpr(this.receiver, this.name, value, null, this.sourceSpan);
4608  }
4609  clone() {
4610    return new ReadPropExpr(this.receiver.clone(), this.name, this.type, this.sourceSpan);
4611  }
4612}
4613class ReadKeyExpr extends Expression {
4614  constructor(receiver, index, type, sourceSpan) {
4615    super(type, sourceSpan);
4616    this.receiver = receiver;
4617    this.index = index;
4618  }
4619  isEquivalent(e) {
4620    return e instanceof ReadKeyExpr && this.receiver.isEquivalent(e.receiver) && this.index.isEquivalent(e.index);
4621  }
4622  isConstant() {
4623    return false;
4624  }
4625  visitExpression(visitor, context) {
4626    return visitor.visitReadKeyExpr(this, context);
4627  }
4628  set(value) {
4629    return new WriteKeyExpr(this.receiver, this.index, value, null, this.sourceSpan);
4630  }
4631  clone() {
4632    return new ReadKeyExpr(this.receiver.clone(), this.index.clone(), this.type, this.sourceSpan);
4633  }
4634}
4635class LiteralArrayExpr extends Expression {
4636  constructor(entries, type, sourceSpan) {
4637    super(type, sourceSpan);
4638    this.entries = entries;
4639  }
4640  isConstant() {
4641    return this.entries.every(e => e.isConstant());
4642  }
4643  isEquivalent(e) {
4644    return e instanceof LiteralArrayExpr && areAllEquivalent(this.entries, e.entries);
4645  }
4646  visitExpression(visitor, context) {
4647    return visitor.visitLiteralArrayExpr(this, context);
4648  }
4649  clone() {
4650    return new LiteralArrayExpr(this.entries.map(e => e.clone()), this.type, this.sourceSpan);
4651  }
4652}
4653class LiteralMapEntry {
4654  constructor(key, value, quoted) {
4655    this.key = key;
4656    this.value = value;
4657    this.quoted = quoted;
4658  }
4659  isEquivalent(e) {
4660    return this.key === e.key && this.value.isEquivalent(e.value);
4661  }
4662  clone() {
4663    return new LiteralMapEntry(this.key, this.value.clone(), this.quoted);
4664  }
4665}
4666class LiteralMapExpr extends Expression {
4667  constructor(entries, type, sourceSpan) {
4668    super(type, sourceSpan);
4669    this.entries = entries;
4670    this.valueType = null;
4671    if (type) {
4672      this.valueType = type.valueType;
4673    }
4674  }
4675  isEquivalent(e) {
4676    return e instanceof LiteralMapExpr && areAllEquivalent(this.entries, e.entries);
4677  }
4678  isConstant() {
4679    return this.entries.every(e => e.value.isConstant());
4680  }
4681  visitExpression(visitor, context) {
4682    return visitor.visitLiteralMapExpr(this, context);
4683  }
4684  clone() {
4685    const entriesClone = this.entries.map(entry => entry.clone());
4686    return new LiteralMapExpr(entriesClone, this.type, this.sourceSpan);
4687  }
4688}
4689class CommaExpr extends Expression {
4690  constructor(parts, sourceSpan) {
4691    super(parts[parts.length - 1].type, sourceSpan);
4692    this.parts = parts;
4693  }
4694  isEquivalent(e) {
4695    return e instanceof CommaExpr && areAllEquivalent(this.parts, e.parts);
4696  }
4697  isConstant() {
4698    return false;
4699  }
4700  visitExpression(visitor, context) {
4701    return visitor.visitCommaExpr(this, context);
4702  }
4703  clone() {
4704    return new CommaExpr(this.parts.map(p => p.clone()));
4705  }
4706}
4707const NULL_EXPR = new LiteralExpr(null, null, null);
4708const TYPED_NULL_EXPR = new LiteralExpr(null, INFERRED_TYPE, null);
4709//// Statements
4710var StmtModifier;
4711(function (StmtModifier) {
4712  StmtModifier[StmtModifier["None"] = 0] = "None";
4713  StmtModifier[StmtModifier["Final"] = 1] = "Final";
4714  StmtModifier[StmtModifier["Private"] = 2] = "Private";
4715  StmtModifier[StmtModifier["Exported"] = 4] = "Exported";
4716  StmtModifier[StmtModifier["Static"] = 8] = "Static";
4717})(StmtModifier || (StmtModifier = {}));
4718class LeadingComment {
4719  constructor(text, multiline, trailingNewline) {
4720    this.text = text;
4721    this.multiline = multiline;
4722    this.trailingNewline = trailingNewline;
4723  }
4724  toString() {
4725    return this.multiline ? ` ${this.text} ` : this.text;
4726  }
4727}
4728class JSDocComment extends LeadingComment {
4729  constructor(tags) {
4730    super('', /* multiline */true, /* trailingNewline */true);
4731    this.tags = tags;
4732  }
4733  toString() {
4734    return serializeTags(this.tags);
4735  }
4736}
4737class Statement {
4738  constructor(modifiers = StmtModifier.None, sourceSpan = null, leadingComments) {
4739    this.modifiers = modifiers;
4740    this.sourceSpan = sourceSpan;
4741    this.leadingComments = leadingComments;
4742  }
4743  hasModifier(modifier) {
4744    return (this.modifiers & modifier) !== 0;
4745  }
4746  addLeadingComment(leadingComment) {
4747    this.leadingComments = this.leadingComments ?? [];
4748    this.leadingComments.push(leadingComment);
4749  }
4750}
4751class DeclareVarStmt extends Statement {
4752  constructor(name, value, type, modifiers, sourceSpan, leadingComments) {
4753    super(modifiers, sourceSpan, leadingComments);
4754    this.name = name;
4755    this.value = value;
4756    this.type = type || value && value.type || null;
4757  }
4758  isEquivalent(stmt) {
4759    return stmt instanceof DeclareVarStmt && this.name === stmt.name && (this.value ? !!stmt.value && this.value.isEquivalent(stmt.value) : !stmt.value);
4760  }
4761  visitStatement(visitor, context) {
4762    return visitor.visitDeclareVarStmt(this, context);
4763  }
4764}
4765class DeclareFunctionStmt extends Statement {
4766  constructor(name, params, statements, type, modifiers, sourceSpan, leadingComments) {
4767    super(modifiers, sourceSpan, leadingComments);
4768    this.name = name;
4769    this.params = params;
4770    this.statements = statements;
4771    this.type = type || null;
4772  }
4773  isEquivalent(stmt) {
4774    return stmt instanceof DeclareFunctionStmt && areAllEquivalent(this.params, stmt.params) && areAllEquivalent(this.statements, stmt.statements);
4775  }
4776  visitStatement(visitor, context) {
4777    return visitor.visitDeclareFunctionStmt(this, context);
4778  }
4779}
4780class ExpressionStatement extends Statement {
4781  constructor(expr, sourceSpan, leadingComments) {
4782    super(StmtModifier.None, sourceSpan, leadingComments);
4783    this.expr = expr;
4784  }
4785  isEquivalent(stmt) {
4786    return stmt instanceof ExpressionStatement && this.expr.isEquivalent(stmt.expr);
4787  }
4788  visitStatement(visitor, context) {
4789    return visitor.visitExpressionStmt(this, context);
4790  }
4791}
4792class ReturnStatement extends Statement {
4793  constructor(value, sourceSpan = null, leadingComments) {
4794    super(StmtModifier.None, sourceSpan, leadingComments);
4795    this.value = value;
4796  }
4797  isEquivalent(stmt) {
4798    return stmt instanceof ReturnStatement && this.value.isEquivalent(stmt.value);
4799  }
4800  visitStatement(visitor, context) {
4801    return visitor.visitReturnStmt(this, context);
4802  }
4803}
4804class IfStmt extends Statement {
4805  constructor(condition, trueCase, falseCase = [], sourceSpan, leadingComments) {
4806    super(StmtModifier.None, sourceSpan, leadingComments);
4807    this.condition = condition;
4808    this.trueCase = trueCase;
4809    this.falseCase = falseCase;
4810  }
4811  isEquivalent(stmt) {
4812    return stmt instanceof IfStmt && this.condition.isEquivalent(stmt.condition) && areAllEquivalent(this.trueCase, stmt.trueCase) && areAllEquivalent(this.falseCase, stmt.falseCase);
4813  }
4814  visitStatement(visitor, context) {
4815    return visitor.visitIfStmt(this, context);
4816  }
4817}
4818class RecursiveAstVisitor$1 {
4819  visitType(ast, context) {
4820    return ast;
4821  }
4822  visitExpression(ast, context) {
4823    if (ast.type) {
4824      ast.type.visitType(this, context);
4825    }
4826    return ast;
4827  }
4828  visitBuiltinType(type, context) {
4829    return this.visitType(type, context);
4830  }
4831  visitExpressionType(type, context) {
4832    type.value.visitExpression(this, context);
4833    if (type.typeParams !== null) {
4834      type.typeParams.forEach(param => this.visitType(param, context));
4835    }
4836    return this.visitType(type, context);
4837  }
4838  visitArrayType(type, context) {
4839    return this.visitType(type, context);
4840  }
4841  visitMapType(type, context) {
4842    return this.visitType(type, context);
4843  }
4844  visitTransplantedType(type, context) {
4845    return type;
4846  }
4847  visitWrappedNodeExpr(ast, context) {
4848    return ast;
4849  }
4850  visitTypeofExpr(ast, context) {
4851    return this.visitExpression(ast, context);
4852  }
4853  visitReadVarExpr(ast, context) {
4854    return this.visitExpression(ast, context);
4855  }
4856  visitWriteVarExpr(ast, context) {
4857    ast.value.visitExpression(this, context);
4858    return this.visitExpression(ast, context);
4859  }
4860  visitWriteKeyExpr(ast, context) {
4861    ast.receiver.visitExpression(this, context);
4862    ast.index.visitExpression(this, context);
4863    ast.value.visitExpression(this, context);
4864    return this.visitExpression(ast, context);
4865  }
4866  visitWritePropExpr(ast, context) {
4867    ast.receiver.visitExpression(this, context);
4868    ast.value.visitExpression(this, context);
4869    return this.visitExpression(ast, context);
4870  }
4871  visitDynamicImportExpr(ast, context) {
4872    return this.visitExpression(ast, context);
4873  }
4874  visitInvokeFunctionExpr(ast, context) {
4875    ast.fn.visitExpression(this, context);
4876    this.visitAllExpressions(ast.args, context);
4877    return this.visitExpression(ast, context);
4878  }
4879  visitTaggedTemplateExpr(ast, context) {
4880    ast.tag.visitExpression(this, context);
4881    this.visitAllExpressions(ast.template.expressions, context);
4882    return this.visitExpression(ast, context);
4883  }
4884  visitInstantiateExpr(ast, context) {
4885    ast.classExpr.visitExpression(this, context);
4886    this.visitAllExpressions(ast.args, context);
4887    return this.visitExpression(ast, context);
4888  }
4889  visitLiteralExpr(ast, context) {
4890    return this.visitExpression(ast, context);
4891  }
4892  visitLocalizedString(ast, context) {
4893    return this.visitExpression(ast, context);
4894  }
4895  visitExternalExpr(ast, context) {
4896    if (ast.typeParams) {
4897      ast.typeParams.forEach(type => type.visitType(this, context));
4898    }
4899    return this.visitExpression(ast, context);
4900  }
4901  visitConditionalExpr(ast, context) {
4902    ast.condition.visitExpression(this, context);
4903    ast.trueCase.visitExpression(this, context);
4904    ast.falseCase.visitExpression(this, context);
4905    return this.visitExpression(ast, context);
4906  }
4907  visitNotExpr(ast, context) {
4908    ast.condition.visitExpression(this, context);
4909    return this.visitExpression(ast, context);
4910  }
4911  visitFunctionExpr(ast, context) {
4912    this.visitAllStatements(ast.statements, context);
4913    return this.visitExpression(ast, context);
4914  }
4915  visitArrowFunctionExpr(ast, context) {
4916    if (Array.isArray(ast.body)) {
4917      this.visitAllStatements(ast.body, context);
4918    } else {
4919      this.visitExpression(ast.body, context);
4920    }
4921    return this.visitExpression(ast, context);
4922  }
4923  visitUnaryOperatorExpr(ast, context) {
4924    ast.expr.visitExpression(this, context);
4925    return this.visitExpression(ast, context);
4926  }
4927  visitBinaryOperatorExpr(ast, context) {
4928    ast.lhs.visitExpression(this, context);
4929    ast.rhs.visitExpression(this, context);
4930    return this.visitExpression(ast, context);
4931  }
4932  visitReadPropExpr(ast, context) {
4933    ast.receiver.visitExpression(this, context);
4934    return this.visitExpression(ast, context);
4935  }
4936  visitReadKeyExpr(ast, context) {
4937    ast.receiver.visitExpression(this, context);
4938    ast.index.visitExpression(this, context);
4939    return this.visitExpression(ast, context);
4940  }
4941  visitLiteralArrayExpr(ast, context) {
4942    this.visitAllExpressions(ast.entries, context);
4943    return this.visitExpression(ast, context);
4944  }
4945  visitLiteralMapExpr(ast, context) {
4946    ast.entries.forEach(entry => entry.value.visitExpression(this, context));
4947    return this.visitExpression(ast, context);
4948  }
4949  visitCommaExpr(ast, context) {
4950    this.visitAllExpressions(ast.parts, context);
4951    return this.visitExpression(ast, context);
4952  }
4953  visitAllExpressions(exprs, context) {
4954    exprs.forEach(expr => expr.visitExpression(this, context));
4955  }
4956  visitDeclareVarStmt(stmt, context) {
4957    if (stmt.value) {
4958      stmt.value.visitExpression(this, context);
4959    }
4960    if (stmt.type) {
4961      stmt.type.visitType(this, context);
4962    }
4963    return stmt;
4964  }
4965  visitDeclareFunctionStmt(stmt, context) {
4966    this.visitAllStatements(stmt.statements, context);
4967    if (stmt.type) {
4968      stmt.type.visitType(this, context);
4969    }
4970    return stmt;
4971  }
4972  visitExpressionStmt(stmt, context) {
4973    stmt.expr.visitExpression(this, context);
4974    return stmt;
4975  }
4976  visitReturnStmt(stmt, context) {
4977    stmt.value.visitExpression(this, context);
4978    return stmt;
4979  }
4980  visitIfStmt(stmt, context) {
4981    stmt.condition.visitExpression(this, context);
4982    this.visitAllStatements(stmt.trueCase, context);
4983    this.visitAllStatements(stmt.falseCase, context);
4984    return stmt;
4985  }
4986  visitAllStatements(stmts, context) {
4987    stmts.forEach(stmt => stmt.visitStatement(this, context));
4988  }
4989}
4990function leadingComment(text, multiline = false, trailingNewline = true) {
4991  return new LeadingComment(text, multiline, trailingNewline);
4992}
4993function jsDocComment(tags = []) {
4994  return new JSDocComment(tags);
4995}
4996function variable(name, type, sourceSpan) {
4997  return new ReadVarExpr(name, type, sourceSpan);
4998}
4999function importExpr(id, typeParams = null, sourceSpan) {
5000  return new ExternalExpr(id, null, typeParams, sourceSpan);
5001}
5002function importType(id, typeParams, typeModifiers) {
5003  return id != null ? expressionType(importExpr(id, typeParams, null), typeModifiers) : null;
5004}
5005function expressionType(expr, typeModifiers, typeParams) {
5006  return new ExpressionType(expr, typeModifiers, typeParams);
5007}
5008function transplantedType(type, typeModifiers) {
5009  return new TransplantedType(type, typeModifiers);
5010}
5011function typeofExpr(expr) {
5012  return new TypeofExpr(expr);
5013}
5014function literalArr(values, type, sourceSpan) {
5015  return new LiteralArrayExpr(values, type, sourceSpan);
5016}
5017function literalMap(values, type = null) {
5018  return new LiteralMapExpr(values.map(e => new LiteralMapEntry(e.key, e.value, e.quoted)), type, null);
5019}
5020function unary(operator, expr, type, sourceSpan) {
5021  return new UnaryOperatorExpr(operator, expr, type, sourceSpan);
5022}
5023function not(expr, sourceSpan) {
5024  return new NotExpr(expr, sourceSpan);
5025}
5026function fn(params, body, type, sourceSpan, name) {
5027  return new FunctionExpr(params, body, type, sourceSpan, name);
5028}
5029function arrowFn(params, body, type, sourceSpan) {
5030  return new ArrowFunctionExpr(params, body, type, sourceSpan);
5031}
5032function ifStmt(condition, thenClause, elseClause, sourceSpan, leadingComments) {
5033  return new IfStmt(condition, thenClause, elseClause, sourceSpan, leadingComments);
5034}
5035function taggedTemplate(tag, template, type, sourceSpan) {
5036  return new TaggedTemplateExpr(tag, template, type, sourceSpan);
5037}
5038function literal(value, type, sourceSpan) {
5039  return new LiteralExpr(value, type, sourceSpan);
5040}
5041function localizedString(metaBlock, messageParts, placeholderNames, expressions, sourceSpan) {
5042  return new LocalizedString(metaBlock, messageParts, placeholderNames, expressions, sourceSpan);
5043}
5044function isNull(exp) {
5045  return exp instanceof LiteralExpr && exp.value === null;
5046}
5047/*
5048 * Serializes a `Tag` into a string.
5049 * Returns a string like " @foo {bar} baz" (note the leading whitespace before `@foo`).
5050 */
5051function tagToString(tag) {
5052  let out = '';
5053  if (tag.tagName) {
5054    out += ` @${tag.tagName}`;
5055  }
5056  if (tag.text) {
5057    if (tag.text.match(/\/\*|\*\//)) {
5058      throw new Error('JSDoc text cannot contain "/*" and "*/"');
5059    }
5060    out += ' ' + tag.text.replace(/@/g, '\\@');
5061  }
5062  return out;
5063}
5064function serializeTags(tags) {
5065  if (tags.length === 0) return '';
5066  if (tags.length === 1 && tags[0].tagName && !tags[0].text) {
5067    // The JSDOC comment is a single simple tag: e.g `/** @tagname */`.
5068    return `*${tagToString(tags[0])} `;
5069  }
5070  let out = '*\n';
5071  for (const tag of tags) {
5072    out += ' *';
5073    // If the tagToString is multi-line, insert " * " prefixes on lines.
5074    out += tagToString(tag).replace(/\n/g, '\n * ');
5075    out += '\n';
5076  }
5077  out += ' ';
5078  return out;
5079}
5080var output_ast = /*#__PURE__*/Object.freeze({
5081  __proto__: null,
5082  get TypeModifier() {
5083    return TypeModifier;
5084  },
5085  Type: Type,
5086  get BuiltinTypeName() {
5087    return BuiltinTypeName;
5088  },
5089  BuiltinType: BuiltinType,
5090  ExpressionType: ExpressionType,
5091  ArrayType: ArrayType,
5092  MapType: MapType,
5093  TransplantedType: TransplantedType,
5094  DYNAMIC_TYPE: DYNAMIC_TYPE,
5095  INFERRED_TYPE: INFERRED_TYPE,
5096  BOOL_TYPE: BOOL_TYPE,
5097  INT_TYPE: INT_TYPE,
5098  NUMBER_TYPE: NUMBER_TYPE,
5099  STRING_TYPE: STRING_TYPE,
5100  FUNCTION_TYPE: FUNCTION_TYPE,
5101  NONE_TYPE: NONE_TYPE,
5102  get UnaryOperator() {
5103    return UnaryOperator;
5104  },
5105  get BinaryOperator() {
5106    return BinaryOperator;
5107  },
5108  nullSafeIsEquivalent: nullSafeIsEquivalent,
5109  areAllEquivalent: areAllEquivalent,
5110  Expression: Expression,
5111  ReadVarExpr: ReadVarExpr,
5112  TypeofExpr: TypeofExpr,
5113  WrappedNodeExpr: WrappedNodeExpr,
5114  WriteVarExpr: WriteVarExpr,
5115  WriteKeyExpr: WriteKeyExpr,
5116  WritePropExpr: WritePropExpr,
5117  InvokeFunctionExpr: InvokeFunctionExpr,
5118  TaggedTemplateExpr: TaggedTemplateExpr,
5119  InstantiateExpr: InstantiateExpr,
5120  LiteralExpr: LiteralExpr,
5121  TemplateLiteral: TemplateLiteral,
5122  TemplateLiteralElement: TemplateLiteralElement,
5123  LiteralPiece: LiteralPiece,
5124  PlaceholderPiece: PlaceholderPiece,
5125  LocalizedString: LocalizedString,
5126  ExternalExpr: ExternalExpr,
5127  ExternalReference: ExternalReference,
5128  ConditionalExpr: ConditionalExpr,
5129  DynamicImportExpr: DynamicImportExpr,
5130  NotExpr: NotExpr,
5131  FnParam: FnParam,
5132  FunctionExpr: FunctionExpr,
5133  ArrowFunctionExpr: ArrowFunctionExpr,
5134  UnaryOperatorExpr: UnaryOperatorExpr,
5135  BinaryOperatorExpr: BinaryOperatorExpr,
5136  ReadPropExpr: ReadPropExpr,
5137  ReadKeyExpr: ReadKeyExpr,
5138  LiteralArrayExpr: LiteralArrayExpr,
5139  LiteralMapEntry: LiteralMapEntry,
5140  LiteralMapExpr: LiteralMapExpr,
5141  CommaExpr: CommaExpr,
5142  NULL_EXPR: NULL_EXPR,
5143  TYPED_NULL_EXPR: TYPED_NULL_EXPR,
5144  get StmtModifier() {
5145    return StmtModifier;
5146  },
5147  LeadingComment: LeadingComment,
5148  JSDocComment: JSDocComment,
5149  Statement: Statement,
5150  DeclareVarStmt: DeclareVarStmt,
5151  DeclareFunctionStmt: DeclareFunctionStmt,
5152  ExpressionStatement: ExpressionStatement,
5153  ReturnStatement: ReturnStatement,
5154  IfStmt: IfStmt,
5155  RecursiveAstVisitor: RecursiveAstVisitor$1,
5156  leadingComment: leadingComment,
5157  jsDocComment: jsDocComment,
5158  variable: variable,
5159  importExpr: importExpr,
5160  importType: importType,
5161  expressionType: expressionType,
5162  transplantedType: transplantedType,
5163  typeofExpr: typeofExpr,
5164  literalArr: literalArr,
5165  literalMap: literalMap,
5166  unary: unary,
5167  not: not,
5168  fn: fn,
5169  arrowFn: arrowFn,
5170  ifStmt: ifStmt,
5171  taggedTemplate: taggedTemplate,
5172  literal: literal,
5173  localizedString: localizedString,
5174  isNull: isNull
5175});
5176const CONSTANT_PREFIX = '_c';
5177/**
5178 * `ConstantPool` tries to reuse literal factories when two or more literals are identical.
5179 * We determine whether literals are identical by creating a key out of their AST using the
5180 * `KeyVisitor`. This constant is used to replace dynamic expressions which can't be safely
5181 * converted into a key. E.g. given an expression `{foo: bar()}`, since we don't know what
5182 * the result of `bar` will be, we create a key that looks like `{foo: <unknown>}`. Note
5183 * that we use a variable, rather than something like `null` in order to avoid collisions.
5184 */
5185const UNKNOWN_VALUE_KEY = variable('<unknown>');
5186/**
5187 * Context to use when producing a key.
5188 *
5189 * This ensures we see the constant not the reference variable when producing
5190 * a key.
5191 */
5192const KEY_CONTEXT = {};
5193/**
5194 * Generally all primitive values are excluded from the `ConstantPool`, but there is an exclusion
5195 * for strings that reach a certain length threshold. This constant defines the length threshold for
5196 * strings.
5197 */
5198const POOL_INCLUSION_LENGTH_THRESHOLD_FOR_STRINGS = 50;
5199/**
5200 * A node that is a place-holder that allows the node to be replaced when the actual
5201 * node is known.
5202 *
5203 * This allows the constant pool to change an expression from a direct reference to
5204 * a constant to a shared constant. It returns a fix-up node that is later allowed to
5205 * change the referenced expression.
5206 */
5207class FixupExpression extends Expression {
5208  constructor(resolved) {
5209    super(resolved.type);
5210    this.resolved = resolved;
5211    this.shared = false;
5212    this.original = resolved;
5213  }
5214  visitExpression(visitor, context) {
5215    if (context === KEY_CONTEXT) {
5216      // When producing a key we want to traverse the constant not the
5217      // variable used to refer to it.
5218      return this.original.visitExpression(visitor, context);
5219    } else {
5220      return this.resolved.visitExpression(visitor, context);
5221    }
5222  }
5223  isEquivalent(e) {
5224    return e instanceof FixupExpression && this.resolved.isEquivalent(e.resolved);
5225  }
5226  isConstant() {
5227    return true;
5228  }
5229  clone() {
5230    throw new Error(`Not supported.`);
5231  }
5232  fixup(expression) {
5233    this.resolved = expression;
5234    this.shared = true;
5235  }
5236}
5237/**
5238 * A constant pool allows a code emitter to share constant in an output context.
5239 *
5240 * The constant pool also supports sharing access to ivy definitions references.
5241 */
5242class ConstantPool {
5243  constructor(isClosureCompilerEnabled = false) {
5244    this.isClosureCompilerEnabled = isClosureCompilerEnabled;
5245    this.statements = [];
5246    this.literals = new Map();
5247    this.literalFactories = new Map();
5248    this.sharedConstants = new Map();
5249    /**
5250     * Constant pool also tracks claimed names from {@link uniqueName}.
5251     * This is useful to avoid collisions if variables are intended to be
5252     * named a certain way- but may conflict. We wouldn't want to always suffix
5253     * them with unique numbers.
5254     */
5255    this._claimedNames = new Map();
5256    this.nextNameIndex = 0;
5257  }
5258  getConstLiteral(literal, forceShared) {
5259    if (literal instanceof LiteralExpr && !isLongStringLiteral(literal) || literal instanceof FixupExpression) {
5260      // Do no put simple literals into the constant pool or try to produce a constant for a
5261      // reference to a constant.
5262      return literal;
5263    }
5264    const key = GenericKeyFn.INSTANCE.keyOf(literal);
5265    let fixup = this.literals.get(key);
5266    let newValue = false;
5267    if (!fixup) {
5268      fixup = new FixupExpression(literal);
5269      this.literals.set(key, fixup);
5270      newValue = true;
5271    }
5272    if (!newValue && !fixup.shared || newValue && forceShared) {
5273      // Replace the expression with a variable
5274      const name = this.freshName();
5275      let definition;
5276      let usage;
5277      if (this.isClosureCompilerEnabled && isLongStringLiteral(literal)) {
5278        // For string literals, Closure will **always** inline the string at
5279        // **all** usages, duplicating it each time. For large strings, this
5280        // unnecessarily bloats bundle size. To work around this restriction, we
5281        // wrap the string in a function, and call that function for each usage.
5282        // This tricks Closure into using inline logic for functions instead of
5283        // string literals. Function calls are only inlined if the body is small
5284        // enough to be worth it. By doing this, very large strings will be
5285        // shared across multiple usages, rather than duplicating the string at
5286        // each usage site.
5287        //
5288        // const myStr = function() { return "very very very long string"; };
5289        // const usage1 = myStr();
5290        // const usage2 = myStr();
5291        definition = variable(name).set(new FunctionExpr([],
5292        // Params.
5293        [
5294        // Statements.
5295        new ReturnStatement(literal)]));
5296        usage = variable(name).callFn([]);
5297      } else {
5298        // Just declare and use the variable directly, without a function call
5299        // indirection. This saves a few bytes and avoids an unnecessary call.
5300        definition = variable(name).set(literal);
5301        usage = variable(name);
5302      }
5303      this.statements.push(definition.toDeclStmt(INFERRED_TYPE, StmtModifier.Final));
5304      fixup.fixup(usage);
5305    }
5306    return fixup;
5307  }
5308  getSharedConstant(def, expr) {
5309    const key = def.keyOf(expr);
5310    if (!this.sharedConstants.has(key)) {
5311      const id = this.freshName();
5312      this.sharedConstants.set(key, variable(id));
5313      this.statements.push(def.toSharedConstantDeclaration(id, expr));
5314    }
5315    return this.sharedConstants.get(key);
5316  }
5317  getLiteralFactory(literal) {
5318    // Create a pure function that builds an array of a mix of constant and variable expressions
5319    if (literal instanceof LiteralArrayExpr) {
5320      const argumentsForKey = literal.entries.map(e => e.isConstant() ? e : UNKNOWN_VALUE_KEY);
5321      const key = GenericKeyFn.INSTANCE.keyOf(literalArr(argumentsForKey));
5322      return this._getLiteralFactory(key, literal.entries, entries => literalArr(entries));
5323    } else {
5324      const expressionForKey = literalMap(literal.entries.map(e => ({
5325        key: e.key,
5326        value: e.value.isConstant() ? e.value : UNKNOWN_VALUE_KEY,
5327        quoted: e.quoted
5328      })));
5329      const key = GenericKeyFn.INSTANCE.keyOf(expressionForKey);
5330      return this._getLiteralFactory(key, literal.entries.map(e => e.value), entries => literalMap(entries.map((value, index) => ({
5331        key: literal.entries[index].key,
5332        value,
5333        quoted: literal.entries[index].quoted
5334      }))));
5335    }
5336  }
5337  // TODO: useUniqueName(false) is necessary for naming compatibility with
5338  // TemplateDefinitionBuilder, but should be removed once Template Pipeline is the default.
5339  getSharedFunctionReference(fn, prefix, useUniqueName = true) {
5340    const isArrow = fn instanceof ArrowFunctionExpr;
5341    for (const current of this.statements) {
5342      // Arrow functions are saved as variables so we check if the
5343      // value of the variable is the same as the arrow function.
5344      if (isArrow && current instanceof DeclareVarStmt && current.value?.isEquivalent(fn)) {
5345        return variable(current.name);
5346      }
5347      // Function declarations are saved as function statements
5348      // so we compare them directly to the passed-in function.
5349      if (!isArrow && current instanceof DeclareFunctionStmt && fn.isEquivalent(current)) {
5350        return variable(current.name);
5351      }
5352    }
5353    // Otherwise declare the function.
5354    const name = useUniqueName ? this.uniqueName(prefix) : prefix;
5355    this.statements.push(fn.toDeclStmt(name, StmtModifier.Final));
5356    return variable(name);
5357  }
5358  _getLiteralFactory(key, values, resultMap) {
5359    let literalFactory = this.literalFactories.get(key);
5360    const literalFactoryArguments = values.filter(e => !e.isConstant());
5361    if (!literalFactory) {
5362      const resultExpressions = values.map((e, index) => e.isConstant() ? this.getConstLiteral(e, true) : variable(`a${index}`));
5363      const parameters = resultExpressions.filter(isVariable).map(e => new FnParam(e.name, DYNAMIC_TYPE));
5364      const pureFunctionDeclaration = arrowFn(parameters, resultMap(resultExpressions), INFERRED_TYPE);
5365      const name = this.freshName();
5366      this.statements.push(variable(name).set(pureFunctionDeclaration).toDeclStmt(INFERRED_TYPE, StmtModifier.Final));
5367      literalFactory = variable(name);
5368      this.literalFactories.set(key, literalFactory);
5369    }
5370    return {
5371      literalFactory,
5372      literalFactoryArguments
5373    };
5374  }
5375  /**
5376   * Produce a unique name in the context of this pool.
5377   *
5378   * The name might be unique among different prefixes if any of the prefixes end in
5379   * a digit so the prefix should be a constant string (not based on user input) and
5380   * must not end in a digit.
5381   */
5382  uniqueName(name, alwaysIncludeSuffix = true) {
5383    const count = this._claimedNames.get(name) ?? 0;
5384    const result = count === 0 && !alwaysIncludeSuffix ? `${name}` : `${name}${count}`;
5385    this._claimedNames.set(name, count + 1);
5386    return result;
5387  }
5388  freshName() {
5389    return this.uniqueName(CONSTANT_PREFIX);
5390  }
5391}
5392class GenericKeyFn {
5393  static #_ = this.INSTANCE = new GenericKeyFn();
5394  keyOf(expr) {
5395    if (expr instanceof LiteralExpr && typeof expr.value === 'string') {
5396      return `"${expr.value}"`;
5397    } else if (expr instanceof LiteralExpr) {
5398      return String(expr.value);
5399    } else if (expr instanceof LiteralArrayExpr) {
5400      const entries = [];
5401      for (const entry of expr.entries) {
5402        entries.push(this.keyOf(entry));
5403      }
5404      return `[${entries.join(',')}]`;
5405    } else if (expr instanceof LiteralMapExpr) {
5406      const entries = [];
5407      for (const entry of expr.entries) {
5408        let key = entry.key;
5409        if (entry.quoted) {
5410          key = `"${key}"`;
5411        }
5412        entries.push(key + ':' + this.keyOf(entry.value));
5413      }
5414      return `{${entries.join(',')}}`;
5415    } else if (expr instanceof ExternalExpr) {
5416      return `import("${expr.value.moduleName}", ${expr.value.name})`;
5417    } else if (expr instanceof ReadVarExpr) {
5418      return `read(${expr.name})`;
5419    } else if (expr instanceof TypeofExpr) {
5420      return `typeof(${this.keyOf(expr.expr)})`;
5421    } else {
5422      throw new Error(`${this.constructor.name} does not handle expressions of type ${expr.constructor.name}`);
5423    }
5424  }
5425}
5426function isVariable(e) {
5427  return e instanceof ReadVarExpr;
5428}
5429function isLongStringLiteral(expr) {
5430  return expr instanceof LiteralExpr && typeof expr.value === 'string' && expr.value.length >= POOL_INCLUSION_LENGTH_THRESHOLD_FOR_STRINGS;
5431}
5432const CORE = '@angular/core';
5433class Identifiers {
5434  /* Methods */
5435  static #_ = this.NEW_METHOD = 'factory';
5436  static #_2 = this.TRANSFORM_METHOD = 'transform';
5437  static #_3 = this.PATCH_DEPS = 'patchedDeps';
5438  static #_4 = this.core = {
5439    name: null,
5440    moduleName: CORE
5441  };
5442  /* Instructions */
5443  static #_5 = this.namespaceHTML = {
5444    name: 'ɵɵnamespaceHTML',
5445    moduleName: CORE
5446  };
5447  static #_6 = this.namespaceMathML = {
5448    name: 'ɵɵnamespaceMathML',
5449    moduleName: CORE
5450  };
5451  static #_7 = this.namespaceSVG = {
5452    name: 'ɵɵnamespaceSVG',
5453    moduleName: CORE
5454  };
5455  static #_8 = this.element = {
5456    name: 'ɵɵelement',
5457    moduleName: CORE
5458  };
5459  static #_9 = this.elementStart = {
5460    name: 'ɵɵelementStart',
5461    moduleName: CORE
5462  };
5463  static #_10 = this.elementEnd = {
5464    name: 'ɵɵelementEnd',
5465    moduleName: CORE
5466  };
5467  static #_11 = this.advance = {
5468    name: 'ɵɵadvance',
5469    moduleName: CORE
5470  };
5471  static #_12 = this.syntheticHostProperty = {
5472    name: 'ɵɵsyntheticHostProperty',
5473    moduleName: CORE
5474  };
5475  static #_13 = this.syntheticHostListener = {
5476    name: 'ɵɵsyntheticHostListener',
5477    moduleName: CORE
5478  };
5479  static #_14 = this.attribute = {
5480    name: 'ɵɵattribute',
5481    moduleName: CORE
5482  };
5483  static #_15 = this.attributeInterpolate1 = {
5484    name: 'ɵɵattributeInterpolate1',
5485    moduleName: CORE
5486  };
5487  static #_16 = this.attributeInterpolate2 = {
5488    name: 'ɵɵattributeInterpolate2',
5489    moduleName: CORE
5490  };
5491  static #_17 = this.attributeInterpolate3 = {
5492    name: 'ɵɵattributeInterpolate3',
5493    moduleName: CORE
5494  };
5495  static #_18 = this.attributeInterpolate4 = {
5496    name: 'ɵɵattributeInterpolate4',
5497    moduleName: CORE
5498  };
5499  static #_19 = this.attributeInterpolate5 = {
5500    name: 'ɵɵattributeInterpolate5',
5501    moduleName: CORE
5502  };
5503  static #_20 = this.attributeInterpolate6 = {
5504    name: 'ɵɵattributeInterpolate6',
5505    moduleName: CORE
5506  };
5507  static #_21 = this.attributeInterpolate7 = {
5508    name: 'ɵɵattributeInterpolate7',
5509    moduleName: CORE
5510  };
5511  static #_22 = this.attributeInterpolate8 = {
5512    name: 'ɵɵattributeInterpolate8',
5513    moduleName: CORE
5514  };
5515  static #_23 = this.attributeInterpolateV = {
5516    name: 'ɵɵattributeInterpolateV',
5517    moduleName: CORE
5518  };
5519  static #_24 = this.classProp = {
5520    name: 'ɵɵclassProp',
5521    moduleName: CORE
5522  };
5523  static #_25 = this.elementContainerStart = {
5524    name: 'ɵɵelementContainerStart',
5525    moduleName: CORE
5526  };
5527  static #_26 = this.elementContainerEnd = {
5528    name: 'ɵɵelementContainerEnd',
5529    moduleName: CORE
5530  };
5531  static #_27 = this.elementContainer = {
5532    name: 'ɵɵelementContainer',
5533    moduleName: CORE
5534  };
5535  static #_28 = this.styleMap = {
5536    name: 'ɵɵstyleMap',
5537    moduleName: CORE
5538  };
5539  static #_29 = this.styleMapInterpolate1 = {
5540    name: 'ɵɵstyleMapInterpolate1',
5541    moduleName: CORE
5542  };
5543  static #_30 = this.styleMapInterpolate2 = {
5544    name: 'ɵɵstyleMapInterpolate2',
5545    moduleName: CORE
5546  };
5547  static #_31 = this.styleMapInterpolate3 = {
5548    name: 'ɵɵstyleMapInterpolate3',
5549    moduleName: CORE
5550  };
5551  static #_32 = this.styleMapInterpolate4 = {
5552    name: 'ɵɵstyleMapInterpolate4',
5553    moduleName: CORE
5554  };
5555  static #_33 = this.styleMapInterpolate5 = {
5556    name: 'ɵɵstyleMapInterpolate5',
5557    moduleName: CORE
5558  };
5559  static #_34 = this.styleMapInterpolate6 = {
5560    name: 'ɵɵstyleMapInterpolate6',
5561    moduleName: CORE
5562  };
5563  static #_35 = this.styleMapInterpolate7 = {
5564    name: 'ɵɵstyleMapInterpolate7',
5565    moduleName: CORE
5566  };
5567  static #_36 = this.styleMapInterpolate8 = {
5568    name: 'ɵɵstyleMapInterpolate8',
5569    moduleName: CORE
5570  };
5571  static #_37 = this.styleMapInterpolateV = {
5572    name: 'ɵɵstyleMapInterpolateV',
5573    moduleName: CORE
5574  };
5575  static #_38 = this.classMap = {
5576    name: 'ɵɵclassMap',
5577    moduleName: CORE
5578  };
5579  static #_39 = this.classMapInterpolate1 = {
5580    name: 'ɵɵclassMapInterpolate1',
5581    moduleName: CORE
5582  };
5583  static #_40 = this.classMapInterpolate2 = {
5584    name: 'ɵɵclassMapInterpolate2',
5585    moduleName: CORE
5586  };
5587  static #_41 = this.classMapInterpolate3 = {
5588    name: 'ɵɵclassMapInterpolate3',
5589    moduleName: CORE
5590  };
5591  static #_42 = this.classMapInterpolate4 = {
5592    name: 'ɵɵclassMapInterpolate4',
5593    moduleName: CORE
5594  };
5595  static #_43 = this.classMapInterpolate5 = {
5596    name: 'ɵɵclassMapInterpolate5',
5597    moduleName: CORE
5598  };
5599  static #_44 = this.classMapInterpolate6 = {
5600    name: 'ɵɵclassMapInterpolate6',
5601    moduleName: CORE
5602  };
5603  static #_45 = this.classMapInterpolate7 = {
5604    name: 'ɵɵclassMapInterpolate7',
5605    moduleName: CORE
5606  };
5607  static #_46 = this.classMapInterpolate8 = {
5608    name: 'ɵɵclassMapInterpolate8',
5609    moduleName: CORE
5610  };
5611  static #_47 = this.classMapInterpolateV = {
5612    name: 'ɵɵclassMapInterpolateV',
5613    moduleName: CORE
5614  };
5615  static #_48 = this.styleProp = {
5616    name: 'ɵɵstyleProp',
5617    moduleName: CORE
5618  };
5619  static #_49 = this.stylePropInterpolate1 = {
5620    name: 'ɵɵstylePropInterpolate1',
5621    moduleName: CORE
5622  };
5623  static #_50 = this.stylePropInterpolate2 = {
5624    name: 'ɵɵstylePropInterpolate2',
5625    moduleName: CORE
5626  };
5627  static #_51 = this.stylePropInterpolate3 = {
5628    name: 'ɵɵstylePropInterpolate3',
5629    moduleName: CORE
5630  };
5631  static #_52 = this.stylePropInterpolate4 = {
5632    name: 'ɵɵstylePropInterpolate4',
5633    moduleName: CORE
5634  };
5635  static #_53 = this.stylePropInterpolate5 = {
5636    name: 'ɵɵstylePropInterpolate5',
5637    moduleName: CORE
5638  };
5639  static #_54 = this.stylePropInterpolate6 = {
5640    name: 'ɵɵstylePropInterpolate6',
5641    moduleName: CORE
5642  };
5643  static #_55 = this.stylePropInterpolate7 = {
5644    name: 'ɵɵstylePropInterpolate7',
5645    moduleName: CORE
5646  };
5647  static #_56 = this.stylePropInterpolate8 = {
5648    name: 'ɵɵstylePropInterpolate8',
5649    moduleName: CORE
5650  };
5651  static #_57 = this.stylePropInterpolateV = {
5652    name: 'ɵɵstylePropInterpolateV',
5653    moduleName: CORE
5654  };
5655  static #_58 = this.nextContext = {
5656    name: 'ɵɵnextContext',
5657    moduleName: CORE
5658  };
5659  static #_59 = this.resetView = {
5660    name: 'ɵɵresetView',
5661    moduleName: CORE
5662  };
5663  static #_60 = this.templateCreate = {
5664    name: 'ɵɵtemplate',
5665    moduleName: CORE
5666  };
5667  static #_61 = this.defer = {
5668    name: 'ɵɵdefer',
5669    moduleName: CORE
5670  };
5671  static #_62 = this.deferWhen = {
5672    name: 'ɵɵdeferWhen',
5673    moduleName: CORE
5674  };
5675  static #_63 = this.deferOnIdle = {
5676    name: 'ɵɵdeferOnIdle',
5677    moduleName: CORE
5678  };
5679  static #_64 = this.deferOnImmediate = {
5680    name: 'ɵɵdeferOnImmediate',
5681    moduleName: CORE
5682  };
5683  static #_65 = this.deferOnTimer = {
5684    name: 'ɵɵdeferOnTimer',
5685    moduleName: CORE
5686  };
5687  static #_66 = this.deferOnHover = {
5688    name: 'ɵɵdeferOnHover',
5689    moduleName: CORE
5690  };
5691  static #_67 = this.deferOnInteraction = {
5692    name: 'ɵɵdeferOnInteraction',
5693    moduleName: CORE
5694  };
5695  static #_68 = this.deferOnViewport = {
5696    name: 'ɵɵdeferOnViewport',
5697    moduleName: CORE
5698  };
5699  static #_69 = this.deferPrefetchWhen = {
5700    name: 'ɵɵdeferPrefetchWhen',
5701    moduleName: CORE
5702  };
5703  static #_70 = this.deferPrefetchOnIdle = {
5704    name: 'ɵɵdeferPrefetchOnIdle',
5705    moduleName: CORE
5706  };
5707  static #_71 = this.deferPrefetchOnImmediate = {
5708    name: 'ɵɵdeferPrefetchOnImmediate',
5709    moduleName: CORE
5710  };
5711  static #_72 = this.deferPrefetchOnTimer = {
5712    name: 'ɵɵdeferPrefetchOnTimer',
5713    moduleName: CORE
5714  };
5715  static #_73 = this.deferPrefetchOnHover = {
5716    name: 'ɵɵdeferPrefetchOnHover',
5717    moduleName: CORE
5718  };
5719  static #_74 = this.deferPrefetchOnInteraction = {
5720    name: 'ɵɵdeferPrefetchOnInteraction',
5721    moduleName: CORE
5722  };
5723  static #_75 = this.deferPrefetchOnViewport = {
5724    name: 'ɵɵdeferPrefetchOnViewport',
5725    moduleName: CORE
5726  };
5727  static #_76 = this.deferEnableTimerScheduling = {
5728    name: 'ɵɵdeferEnableTimerScheduling',
5729    moduleName: CORE
5730  };
5731  static #_77 = this.conditional = {
5732    name: 'ɵɵconditional',
5733    moduleName: CORE
5734  };
5735  static #_78 = this.repeater = {
5736    name: 'ɵɵrepeater',
5737    moduleName: CORE
5738  };
5739  static #_79 = this.repeaterCreate = {
5740    name: 'ɵɵrepeaterCreate',
5741    moduleName: CORE
5742  };
5743  static #_80 = this.repeaterTrackByIndex = {
5744    name: 'ɵɵrepeaterTrackByIndex',
5745    moduleName: CORE
5746  };
5747  static #_81 = this.repeaterTrackByIdentity = {
5748    name: 'ɵɵrepeaterTrackByIdentity',
5749    moduleName: CORE
5750  };
5751  static #_82 = this.componentInstance = {
5752    name: 'ɵɵcomponentInstance',
5753    moduleName: CORE
5754  };
5755  static #_83 = this.text = {
5756    name: 'ɵɵtext',
5757    moduleName: CORE
5758  };
5759  static #_84 = this.enableBindings = {
5760    name: 'ɵɵenableBindings',
5761    moduleName: CORE
5762  };
5763  static #_85 = this.disableBindings = {
5764    name: 'ɵɵdisableBindings',
5765    moduleName: CORE
5766  };
5767  static #_86 = this.getCurrentView = {
5768    name: 'ɵɵgetCurrentView',
5769    moduleName: CORE
5770  };
5771  static #_87 = this.textInterpolate = {
5772    name: 'ɵɵtextInterpolate',
5773    moduleName: CORE
5774  };
5775  static #_88 = this.textInterpolate1 = {
5776    name: 'ɵɵtextInterpolate1',
5777    moduleName: CORE
5778  };
5779  static #_89 = this.textInterpolate2 = {
5780    name: 'ɵɵtextInterpolate2',
5781    moduleName: CORE
5782  };
5783  static #_90 = this.textInterpolate3 = {
5784    name: 'ɵɵtextInterpolate3',
5785    moduleName: CORE
5786  };
5787  static #_91 = this.textInterpolate4 = {
5788    name: 'ɵɵtextInterpolate4',
5789    moduleName: CORE
5790  };
5791  static #_92 = this.textInterpolate5 = {
5792    name: 'ɵɵtextInterpolate5',
5793    moduleName: CORE
5794  };
5795  static #_93 = this.textInterpolate6 = {
5796    name: 'ɵɵtextInterpolate6',
5797    moduleName: CORE
5798  };
5799  static #_94 = this.textInterpolate7 = {
5800    name: 'ɵɵtextInterpolate7',
5801    moduleName: CORE
5802  };
5803  static #_95 = this.textInterpolate8 = {
5804    name: 'ɵɵtextInterpolate8',
5805    moduleName: CORE
5806  };
5807  static #_96 = this.textInterpolateV = {
5808    name: 'ɵɵtextInterpolateV',
5809    moduleName: CORE
5810  };
5811  static #_97 = this.restoreView = {
5812    name: 'ɵɵrestoreView',
5813    moduleName: CORE
5814  };
5815  static #_98 = this.pureFunction0 = {
5816    name: 'ɵɵpureFunction0',
5817    moduleName: CORE
5818  };
5819  static #_99 = this.pureFunction1 = {
5820    name: 'ɵɵpureFunction1',
5821    moduleName: CORE
5822  };
5823  static #_100 = this.pureFunction2 = {
5824    name: 'ɵɵpureFunction2',
5825    moduleName: CORE
5826  };
5827  static #_101 = this.pureFunction3 = {
5828    name: 'ɵɵpureFunction3',
5829    moduleName: CORE
5830  };
5831  static #_102 = this.pureFunction4 = {
5832    name: 'ɵɵpureFunction4',
5833    moduleName: CORE
5834  };
5835  static #_103 = this.pureFunction5 = {
5836    name: 'ɵɵpureFunction5',
5837    moduleName: CORE
5838  };
5839  static #_104 = this.pureFunction6 = {
5840    name: 'ɵɵpureFunction6',
5841    moduleName: CORE
5842  };
5843  static #_105 = this.pureFunction7 = {
5844    name: 'ɵɵpureFunction7',
5845    moduleName: CORE
5846  };
5847  static #_106 = this.pureFunction8 = {
5848    name: 'ɵɵpureFunction8',
5849    moduleName: CORE
5850  };
5851  static #_107 = this.pureFunctionV = {
5852    name: 'ɵɵpureFunctionV',
5853    moduleName: CORE
5854  };
5855  static #_108 = this.pipeBind1 = {
5856    name: 'ɵɵpipeBind1',
5857    moduleName: CORE
5858  };
5859  static #_109 = this.pipeBind2 = {
5860    name: 'ɵɵpipeBind2',
5861    moduleName: CORE
5862  };
5863  static #_110 = this.pipeBind3 = {
5864    name: 'ɵɵpipeBind3',
5865    moduleName: CORE
5866  };
5867  static #_111 = this.pipeBind4 = {
5868    name: 'ɵɵpipeBind4',
5869    moduleName: CORE
5870  };
5871  static #_112 = this.pipeBindV = {
5872    name: 'ɵɵpipeBindV',
5873    moduleName: CORE
5874  };
5875  static #_113 = this.hostProperty = {
5876    name: 'ɵɵhostProperty',
5877    moduleName: CORE
5878  };
5879  static #_114 = this.property = {
5880    name: 'ɵɵproperty',
5881    moduleName: CORE
5882  };
5883  static #_115 = this.propertyInterpolate = {
5884    name: 'ɵɵpropertyInterpolate',
5885    moduleName: CORE
5886  };
5887  static #_116 = this.propertyInterpolate1 = {
5888    name: 'ɵɵpropertyInterpolate1',
5889    moduleName: CORE
5890  };
5891  static #_117 = this.propertyInterpolate2 = {
5892    name: 'ɵɵpropertyInterpolate2',
5893    moduleName: CORE
5894  };
5895  static #_118 = this.propertyInterpolate3 = {
5896    name: 'ɵɵpropertyInterpolate3',
5897    moduleName: CORE
5898  };
5899  static #_119 = this.propertyInterpolate4 = {
5900    name: 'ɵɵpropertyInterpolate4',
5901    moduleName: CORE
5902  };
5903  static #_120 = this.propertyInterpolate5 = {
5904    name: 'ɵɵpropertyInterpolate5',
5905    moduleName: CORE
5906  };
5907  static #_121 = this.propertyInterpolate6 = {
5908    name: 'ɵɵpropertyInterpolate6',
5909    moduleName: CORE
5910  };
5911  static #_122 = this.propertyInterpolate7 = {
5912    name: 'ɵɵpropertyInterpolate7',
5913    moduleName: CORE
5914  };
5915  static #_123 = this.propertyInterpolate8 = {
5916    name: 'ɵɵpropertyInterpolate8',
5917    moduleName: CORE
5918  };
5919  static #_124 = this.propertyInterpolateV = {
5920    name: 'ɵɵpropertyInterpolateV',
5921    moduleName: CORE
5922  };
5923  static #_125 = this.i18n = {
5924    name: 'ɵɵi18n',
5925    moduleName: CORE
5926  };
5927  static #_126 = this.i18nAttributes = {
5928    name: 'ɵɵi18nAttributes',
5929    moduleName: CORE
5930  };
5931  static #_127 = this.i18nExp = {
5932    name: 'ɵɵi18nExp',
5933    moduleName: CORE
5934  };
5935  static #_128 = this.i18nStart = {
5936    name: 'ɵɵi18nStart',
5937    moduleName: CORE
5938  };
5939  static #_129 = this.i18nEnd = {
5940    name: 'ɵɵi18nEnd',
5941    moduleName: CORE
5942  };
5943  static #_130 = this.i18nApply = {
5944    name: 'ɵɵi18nApply',
5945    moduleName: CORE
5946  };
5947  static #_131 = this.i18nPostprocess = {
5948    name: 'ɵɵi18nPostprocess',
5949    moduleName: CORE
5950  };
5951  static #_132 = this.pipe = {
5952    name: 'ɵɵpipe',
5953    moduleName: CORE
5954  };
5955  static #_133 = this.projection = {
5956    name: 'ɵɵprojection',
5957    moduleName: CORE
5958  };
5959  static #_134 = this.projectionDef = {
5960    name: 'ɵɵprojectionDef',
5961    moduleName: CORE
5962  };
5963  static #_135 = this.reference = {
5964    name: 'ɵɵreference',
5965    moduleName: CORE
5966  };
5967  static #_136 = this.inject = {
5968    name: 'ɵɵinject',
5969    moduleName: CORE
5970  };
5971  static #_137 = this.injectAttribute = {
5972    name: 'ɵɵinjectAttribute',
5973    moduleName: CORE
5974  };
5975  static #_138 = this.directiveInject = {
5976    name: 'ɵɵdirectiveInject',
5977    moduleName: CORE
5978  };
5979  static #_139 = this.invalidFactory = {
5980    name: 'ɵɵinvalidFactory',
5981    moduleName: CORE
5982  };
5983  static #_140 = this.invalidFactoryDep = {
5984    name: 'ɵɵinvalidFactoryDep',
5985    moduleName: CORE
5986  };
5987  static #_141 = this.templateRefExtractor = {
5988    name: 'ɵɵtemplateRefExtractor',
5989    moduleName: CORE
5990  };
5991  static #_142 = this.forwardRef = {
5992    name: 'forwardRef',
5993    moduleName: CORE
5994  };
5995  static #_143 = this.resolveForwardRef = {
5996    name: 'resolveForwardRef',
5997    moduleName: CORE
5998  };
5999  static #_144 = this.ɵɵdefineInjectable = {
6000    name: 'ɵɵdefineInjectable',
6001    moduleName: CORE
6002  };
6003  static #_145 = this.declareInjectable = {
6004    name: 'ɵɵngDeclareInjectable',
6005    moduleName: CORE
6006  };
6007  static #_146 = this.InjectableDeclaration = {
6008    name: 'ɵɵInjectableDeclaration',
6009    moduleName: CORE
6010  };
6011  static #_147 = this.resolveWindow = {
6012    name: 'ɵɵresolveWindow',
6013    moduleName: CORE
6014  };
6015  static #_148 = this.resolveDocument = {
6016    name: 'ɵɵresolveDocument',
6017    moduleName: CORE
6018  };
6019  static #_149 = this.resolveBody = {
6020    name: 'ɵɵresolveBody',
6021    moduleName: CORE
6022  };
6023  static #_150 = this.getComponentDepsFactory = {
6024    name: 'ɵɵgetComponentDepsFactory',
6025    moduleName: CORE
6026  };
6027  static #_151 = this.defineComponent = {
6028    name: 'ɵɵdefineComponent',
6029    moduleName: CORE
6030  };
6031  static #_152 = this.declareComponent = {
6032    name: 'ɵɵngDeclareComponent',
6033    moduleName: CORE
6034  };
6035  static #_153 = this.setComponentScope = {
6036    name: 'ɵɵsetComponentScope',
6037    moduleName: CORE
6038  };
6039  static #_154 = this.ChangeDetectionStrategy = {
6040    name: 'ChangeDetectionStrategy',
6041    moduleName: CORE
6042  };
6043  static #_155 = this.ViewEncapsulation = {
6044    name: 'ViewEncapsulation',
6045    moduleName: CORE
6046  };
6047  static #_156 = this.ComponentDeclaration = {
6048    name: 'ɵɵComponentDeclaration',
6049    moduleName: CORE
6050  };
6051  static #_157 = this.FactoryDeclaration = {
6052    name: 'ɵɵFactoryDeclaration',
6053    moduleName: CORE
6054  };
6055  static #_158 = this.declareFactory = {
6056    name: 'ɵɵngDeclareFactory',
6057    moduleName: CORE
6058  };
6059  static #_159 = this.FactoryTarget = {
6060    name: 'ɵɵFactoryTarget',
6061    moduleName: CORE
6062  };
6063  static #_160 = this.defineDirective = {
6064    name: 'ɵɵdefineDirective',
6065    moduleName: CORE
6066  };
6067  static #_161 = this.declareDirective = {
6068    name: 'ɵɵngDeclareDirective',
6069    moduleName: CORE
6070  };
6071  static #_162 = this.DirectiveDeclaration = {
6072    name: 'ɵɵDirectiveDeclaration',
6073    moduleName: CORE
6074  };
6075  static #_163 = this.InjectorDef = {
6076    name: 'ɵɵInjectorDef',
6077    moduleName: CORE
6078  };
6079  static #_164 = this.InjectorDeclaration = {
6080    name: 'ɵɵInjectorDeclaration',
6081    moduleName: CORE
6082  };
6083  static #_165 = this.defineInjector = {
6084    name: 'ɵɵdefineInjector',
6085    moduleName: CORE
6086  };
6087  static #_166 = this.declareInjector = {
6088    name: 'ɵɵngDeclareInjector',
6089    moduleName: CORE
6090  };
6091  static #_167 = this.NgModuleDeclaration = {
6092    name: 'ɵɵNgModuleDeclaration',
6093    moduleName: CORE
6094  };
6095  static #_168 = this.ModuleWithProviders = {
6096    name: 'ModuleWithProviders',
6097    moduleName: CORE
6098  };
6099  static #_169 = this.defineNgModule = {
6100    name: 'ɵɵdefineNgModule',
6101    moduleName: CORE
6102  };
6103  static #_170 = this.declareNgModule = {
6104    name: 'ɵɵngDeclareNgModule',
6105    moduleName: CORE
6106  };
6107  static #_171 = this.setNgModuleScope = {
6108    name: 'ɵɵsetNgModuleScope',
6109    moduleName: CORE
6110  };
6111  static #_172 = this.registerNgModuleType = {
6112    name: 'ɵɵregisterNgModuleType',
6113    moduleName: CORE
6114  };
6115  static #_173 = this.PipeDeclaration = {
6116    name: 'ɵɵPipeDeclaration',
6117    moduleName: CORE
6118  };
6119  static #_174 = this.definePipe = {
6120    name: 'ɵɵdefinePipe',
6121    moduleName: CORE
6122  };
6123  static #_175 = this.declarePipe = {
6124    name: 'ɵɵngDeclarePipe',
6125    moduleName: CORE
6126  };
6127  static #_176 = this.declareClassMetadata = {
6128    name: 'ɵɵngDeclareClassMetadata',
6129    moduleName: CORE
6130  };
6131  static #_177 = this.setClassMetadata = {
6132    name: 'ɵsetClassMetadata',
6133    moduleName: CORE
6134  };
6135  static #_178 = this.setClassMetadataAsync = {
6136    name: 'ɵsetClassMetadataAsync',
6137    moduleName: CORE
6138  };
6139  static #_179 = this.setClassDebugInfo = {
6140    name: 'ɵsetClassDebugInfo',
6141    moduleName: CORE
6142  };
6143  static #_180 = this.queryRefresh = {
6144    name: 'ɵɵqueryRefresh',
6145    moduleName: CORE
6146  };
6147  static #_181 = this.viewQuery = {
6148    name: 'ɵɵviewQuery',
6149    moduleName: CORE
6150  };
6151  static #_182 = this.loadQuery = {
6152    name: 'ɵɵloadQuery',
6153    moduleName: CORE
6154  };
6155  static #_183 = this.contentQuery = {
6156    name: 'ɵɵcontentQuery',
6157    moduleName: CORE
6158  }; // Signal queries
6159  static #_184 = this.viewQuerySignal = {
6160    name: 'ɵɵviewQuerySignal',
6161    moduleName: CORE
6162  };
6163  static #_185 = this.contentQuerySignal = {
6164    name: 'ɵɵcontentQuerySignal',
6165    moduleName: CORE
6166  };
6167  static #_186 = this.queryAdvance = {
6168    name: 'ɵɵqueryAdvance',
6169    moduleName: CORE
6170  }; // Two-way bindings
6171  static #_187 = this.twoWayProperty = {
6172    name: 'ɵɵtwoWayProperty',
6173    moduleName: CORE
6174  };
6175  static #_188 = this.twoWayBindingSet = {
6176    name: 'ɵɵtwoWayBindingSet',
6177    moduleName: CORE
6178  };
6179  static #_189 = this.twoWayListener = {
6180    name: 'ɵɵtwoWayListener',
6181    moduleName: CORE
6182  };
6183  static #_190 = this.NgOnChangesFeature = {
6184    name: 'ɵɵNgOnChangesFeature',
6185    moduleName: CORE
6186  };
6187  static #_191 = this.InheritDefinitionFeature = {
6188    name: 'ɵɵInheritDefinitionFeature',
6189    moduleName: CORE
6190  };
6191  static #_192 = this.CopyDefinitionFeature = {
6192    name: 'ɵɵCopyDefinitionFeature',
6193    moduleName: CORE
6194  };
6195  static #_193 = this.StandaloneFeature = {
6196    name: 'ɵɵStandaloneFeature',
6197    moduleName: CORE
6198  };
6199  static #_194 = this.ProvidersFeature = {
6200    name: 'ɵɵProvidersFeature',
6201    moduleName: CORE
6202  };
6203  static #_195 = this.HostDirectivesFeature = {
6204    name: 'ɵɵHostDirectivesFeature',
6205    moduleName: CORE
6206  };
6207  static #_196 = this.InputTransformsFeatureFeature = {
6208    name: 'ɵɵInputTransformsFeature',
6209    moduleName: CORE
6210  };
6211  static #_197 = this.listener = {
6212    name: 'ɵɵlistener',
6213    m
6213oduleName: CORE
6214  };
6215  static #_198 = this.getInheritedFactory = {
6216    name: 'ɵɵgetInheritedFactory',
6217    moduleName: CORE
6218  };
6219  static #_199 = this.InputFlags = {
6220    name: 'ɵɵInputFlags',
6221    moduleName: CORE
6222  }; // sanitization-related functions
6223  static #_200 = this.sanitizeHtml = {
6224    name: 'ɵɵsanitizeHtml',
6225    moduleName: CORE
6226  };
6227  static #_201 = this.sanitizeStyle = {
6228    name: 'ɵɵsanitizeStyle',
6229    moduleName: CORE
6230  };
6231  static #_202 = this.sanitizeResourceUrl = {
6232    name: 'ɵɵsanitizeResourceUrl',
6233    moduleName: CORE
6234  };
6235  static #_203 = this.sanitizeScript = {
6236    name: 'ɵɵsanitizeScript',
6237    moduleName: CORE
6238  };
6239  static #_204 = this.sanitizeUrl = {
6240    name: 'ɵɵsanitizeUrl',
6241    moduleName: CORE
6242  };
6243  static #_205 = this.sanitizeUrlOrResourceUrl = {
6244    name: 'ɵɵsanitizeUrlOrResourceUrl',
6245    moduleName: CORE
6246  };
6247  static #_206 = this.trustConstantHtml = {
6248    name: 'ɵɵtrustConstantHtml',
6249    moduleName: CORE
6250  };
6251  static #_207 = this.trustConstantResourceUrl = {
6252    name: 'ɵɵtrustConstantResourceUrl',
6253    moduleName: CORE
6254  };
6255  static #_208 = this.validateIframeAttribute = {
6256    name: 'ɵɵvalidateIframeAttribute',
6257    moduleName: CORE
6258  }; // type-checking
6259  static #_209 = this.InputSignalBrandWriteType = {
6260    name: 'ɵINPUT_SIGNAL_BRAND_WRITE_TYPE',
6261    moduleName: CORE
6262  };
6263  static #_210 = this.UnwrapDirectiveSignalInputs = {
6264    name: 'ɵUnwrapDirectiveSignalInputs',
6265    moduleName: CORE
6266  };
6267  static #_211 = this.unwrapWritableSignal = {
6268    name: 'ɵunwrapWritableSignal',
6269    moduleName: CORE
6270  };
6271}
6272const DASH_CASE_REGEXP = /-+([a-z0-9])/g;
6273function dashCaseToCamelCase(input) {
6274  return input.replace(DASH_CASE_REGEXP, (...m) => m[1].toUpperCase());
6275}
6276function splitAtColon(input, defaultValues) {
6277  return _splitAt(input, ':', defaultValues);
6278}
6279function splitAtPeriod(input, defaultValues) {
6280  return _splitAt(input, '.', defaultValues);
6281}
6282function _splitAt(input, character, defaultValues) {
6283  const characterIndex = input.indexOf(character);
6284  if (characterIndex == -1) return defaultValues;
6285  return [input.slice(0, characterIndex).trim(), input.slice(characterIndex + 1).trim()];
6286}
6287function noUndefined(val) {
6288  return val === undefined ? null : val;
6289}
6290function error(msg) {
6291  throw new Error(`Internal Error: ${msg}`);
6292}
6293// Escape characters that have a special meaning in Regular Expressions
6294function escapeRegExp(s) {
6295  return s.replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
6296}
6297function utf8Encode(str) {
6298  let encoded = [];
6299  for (let index = 0; index < str.length; index++) {
6300    let codePoint = str.charCodeAt(index);
6301    // decode surrogate
6302    // see https://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
6303    if (codePoint >= 0xd800 && codePoint <= 0xdbff && str.length > index + 1) {
6304      const low = str.charCodeAt(index + 1);
6305      if (low >= 0xdc00 && low <= 0xdfff) {
6306        index++;
6307        codePoint = (codePoint - 0xd800 << 10) + low - 0xdc00 + 0x10000;
6308      }
6309    }
6310    if (codePoint <= 0x7f) {
6311      encoded.push(codePoint);
6312    } else if (codePoint <= 0x7ff) {
6313      encoded.push(codePoint >> 6 & 0x1F | 0xc0, codePoint & 0x3f | 0x80);
6314    } else if (codePoint <= 0xffff) {
6315      encoded.push(codePoint >> 12 | 0xe0, codePoint >> 6 & 0x3f | 0x80, codePoint & 0x3f | 0x80);
6316    } else if (codePoint <= 0x1fffff) {
6317      encoded.push(codePoint >> 18 & 0x07 | 0xf0, codePoint >> 12 & 0x3f | 0x80, codePoint >> 6 & 0x3f | 0x80, codePoint & 0x3f | 0x80);
6318    }
6319  }
6320  return encoded;
6321}
6322function stringify(token) {
6323  if (typeof token === 'string') {
6324    return token;
6325  }
6326  if (Array.isArray(token)) {
6327    return '[' + token.map(stringify).join(', ') + ']';
6328  }
6329  if (token == null) {
6330    return '' + token;
6331  }
6332  if (token.overriddenName) {
6333    return `${token.overriddenName}`;
6334  }
6335  if (token.name) {
6336    return `${token.name}`;
6337  }
6338  if (!token.toString) {
6339    return 'object';
6340  }
6341  // WARNING: do not try to `JSON.stringify(token)` here
6342  // see https://github.com/angular/angular/issues/23440
6343  const res = token.toString();
6344  if (res == null) {
6345    return '' + res;
6346  }
6347  const newLineIndex = res.indexOf('\n');
6348  return newLineIndex === -1 ? res : res.substring(0, newLineIndex);
6349}
6350class Version {
6351  constructor(full) {
6352    this.full = full;
6353    const splits = full.split('.');
6354    this.major = splits[0];
6355    this.minor = splits[1];
6356    this.patch = splits.slice(2).join('.');
6357  }
6358}
6359const _global = globalThis;
6360function newArray(size, value) {
6361  const list = [];
6362  for (let i = 0; i < size; i++) {
6363    list.push(value);
6364  }
6365  return list;
6366}
6367/**
6368 * Partitions a given array into 2 arrays, based on a boolean value returned by the condition
6369 * function.
6370 *
6371 * @param arr Input array that should be partitioned
6372 * @param conditionFn Condition function that is called for each item in a given array and returns a
6373 * boolean value.
6374 */
6375function partitionArray(arr, conditionFn) {
6376  const truthy = [];
6377  const falsy = [];
6378  for (const item of arr) {
6379    (conditionFn(item) ? truthy : falsy).push(item);
6380  }
6381  return [truthy, falsy];
6382}
6383
6384// https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit
6385const VERSION$1 = 3;
6386const JS_B64_PREFIX = '# sourceMappingURL=data:application/json;base64,';
6387class SourceMapGenerator {
6388  constructor(file = null) {
6389    this.file = file;
6390    this.sourcesContent = new Map();
6391    this.lines = [];
6392    this.lastCol0 = 0;
6393    this.hasMappings = false;
6394  }
6395  // The content is `null` when the content is expected to be loaded using the URL
6396  addSource(url, content = null) {
6397    if (!this.sourcesContent.has(url)) {
6398      this.sourcesContent.set(url, content);
6399    }
6400    return this;
6401  }
6402  addLine() {
6403    this.lines.push([]);
6404    this.lastCol0 = 0;
6405    return this;
6406  }
6407  addMapping(col0, sourceUrl, sourceLine0, sourceCol0) {
6408    if (!this.currentLine) {
6409      throw new Error(`A line must be added before mappings can be added`);
6410    }
6411    if (sourceUrl != null && !this.sourcesContent.has(sourceUrl)) {
6412      throw new Error(`Unknown source file "${sourceUrl}"`);
6413    }
6414    if (col0 == null) {
6415      throw new Error(`The column in the generated code must be provided`);
6416    }
6417    if (col0 < this.lastCol0) {
6418      throw new Error(`Mapping should be added in output order`);
6419    }
6420    if (sourceUrl && (sourceLine0 == null || sourceCol0 == null)) {
6421      throw new Error(`The source location must be provided when a source url is provided`);
6422    }
6423    this.hasMappings = true;
6424    this.lastCol0 = col0;
6425    this.currentLine.push({
6426      col0,
6427      sourceUrl,
6428      sourceLine0,
6429      sourceCol0
6430    });
6431    return this;
6432  }
6433  /**
6434   * @internal strip this from published d.ts files due to
6435   * https://github.com/microsoft/TypeScript/issues/36216
6436   */
6437  get currentLine() {
6438    return this.lines.slice(-1)[0];
6439  }
6440  toJSON() {
6441    if (!this.hasMappings) {
6442      return null;
6443    }
6444    const sourcesIndex = new Map();
6445    const sources = [];
6446    const sourcesContent = [];
6447    Array.from(this.sourcesContent.keys()).forEach((url, i) => {
6448      sourcesIndex.set(url, i);
6449      sources.push(url);
6450      sourcesContent.push(this.sourcesContent.get(url) || null);
6451    });
6452    let mappings = '';
6453    let lastCol0 = 0;
6454    let lastSourceIndex = 0;
6455    let lastSourceLine0 = 0;
6456    let lastSourceCol0 = 0;
6457    this.lines.forEach(segments => {
6458      lastCol0 = 0;
6459      mappings += segments.map(segment => {
6460        // zero-based starting column of the line in the generated code
6461        let segAsStr = toBase64VLQ(segment.col0 - lastCol0);
6462        lastCol0 = segment.col0;
6463        if (segment.sourceUrl != null) {
6464          // zero-based index into the “sources” list
6465          segAsStr += toBase64VLQ(sourcesIndex.get(segment.sourceUrl) - lastSourceIndex);
6466          lastSourceIndex = sourcesIndex.get(segment.sourceUrl);
6467          // the zero-based starting line in the original source
6468          segAsStr += toBase64VLQ(segment.sourceLine0 - lastSourceLine0);
6469          lastSourceLine0 = segment.sourceLine0;
6470          // the zero-based starting column in the original source
6471          segAsStr += toBase64VLQ(segment.sourceCol0 - lastSourceCol0);
6472          lastSourceCol0 = segment.sourceCol0;
6473        }
6474        return segAsStr;
6475      }).join(',');
6476      mappings += ';';
6477    });
6478    mappings = mappings.slice(0, -1);
6479    return {
6480      'file': this.file || '',
6481      'version': VERSION$1,
6482      'sourceRoot': '',
6483      'sources': sources,
6484      'sourcesContent': sourcesContent,
6485      'mappings': mappings
6486    };
6487  }
6488  toJsComment() {
6489    return this.hasMappings ? '//' + JS_B64_PREFIX + toBase64String(JSON.stringify(this, null, 0)) : '';
6490  }
6491}
6492function toBase64String(value) {
6493  let b64 = '';
6494  const encoded = utf8Encode(value);
6495  for (let i = 0; i < encoded.length;) {
6496    const i1 = encoded[i++];
6497    const i2 = i < encoded.length ? encoded[i++] : null;
6498    const i3 = i < encoded.length ? encoded[i++] : null;
6499    b64 += toBase64Digit(i1 >> 2);
6500    b64 += toBase64Digit((i1 & 3) << 4 | (i2 === null ? 0 : i2 >> 4));
6501    b64 += i2 === null ? '=' : toBase64Digit((i2 & 15) << 2 | (i3 === null ? 0 : i3 >> 6));
6502    b64 += i2 === null || i3 === null ? '=' : toBase64Digit(i3 & 63);
6503  }
6504  return b64;
6505}
6506function toBase64VLQ(value) {
6507  value = value < 0 ? (-value << 1) + 1 : value << 1;
6508  let out = '';
6509  do {
6510    let digit = value & 31;
6511    value = value >> 5;
6512    if (value > 0) {
6513      digit = digit | 32;
6514    }
6515    out += toBase64Digit(digit);
6516  } while (value > 0);
6517  return out;
6518}
6519const B64_DIGITS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
6520function toBase64Digit(value) {
6521  if (value < 0 || value >= 64) {
6522    throw new Error(`Can only encode value in the range [0, 63]`);
6523  }
6524  return B64_DIGITS[value];
6525}
6526const _SINGLE_QUOTE_ESCAPE_STRING_RE = /'|\\|\n|\r|\$/g;
6527const _LEGAL_IDENTIFIER_RE = /^[$A-Z_][0-9A-Z_$]*$/i;
6528const _INDENT_WITH = '  ';
6529class _EmittedLine {
6530  constructor(indent) {
6531    this.indent = indent;
6532    this.partsLength = 0;
6533    this.parts = [];
6534    this.srcSpans = [];
6535  }
6536}
6537class EmitterVisitorContext {
6538  static createRoot() {
6539    return new EmitterVisitorContext(0);
6540  }
6541  constructor(_indent) {
6542    this._indent = _indent;
6543    this._lines = [new _EmittedLine(_indent)];
6544  }
6545  /**
6546   * @internal strip this from published d.ts files due to
6547   * https://github.com/microsoft/TypeScript/issues/36216
6548   */
6549  get _currentLine() {
6550    return this._lines[this._lines.length - 1];
6551  }
6552  println(from, lastPart = '') {
6553    this.print(from || null, lastPart, true);
6554  }
6555  lineIsEmpty() {
6556    return this._currentLine.parts.length === 0;
6557  }
6558  lineLength() {
6559    return this._currentLine.indent * _INDENT_WITH.length + this._currentLine.partsLength;
6560  }
6561  print(from, part, newLine = false) {
6562    if (part.length > 0) {
6563      this._currentLine.parts.push(part);
6564      this._currentLine.partsLength += part.length;
6565      this._currentLine.srcSpans.push(from && from.sourceSpan || null);
6566    }
6567    if (newLine) {
6568      this._lines.push(new _EmittedLine(this._indent));
6569    }
6570  }
6571  removeEmptyLastLine() {
6572    if (this.lineIsEmpty()) {
6573      this._lines.pop();
6574    }
6575  }
6576  incIndent() {
6577    this._indent++;
6578    if (this.lineIsEmpty()) {
6579      this._currentLine.indent = this._indent;
6580    }
6581  }
6582  decIndent() {
6583    this._indent--;
6584    if (this.lineIsEmpty()) {
6585      this._currentLine.indent = this._indent;
6586    }
6587  }
6588  toSource() {
6589    return this.sourceLines.map(l => l.parts.length > 0 ? _createIndent(l.indent) + l.parts.join('') : '').join('\n');
6590  }
6591  toSourceMapGenerator(genFilePath, startsAtLine = 0) {
6592    const map = new SourceMapGenerator(genFilePath);
6593    let firstOffsetMapped = false;
6594    const mapFirstOffsetIfNeeded = () => {
6595      if (!firstOffsetMapped) {
6596        // Add a single space so that tools won't try to load the file from disk.
6597        // Note: We are using virtual urls like `ng:///`, so we have to
6598        // provide a content here.
6599        map.addSource(genFilePath, ' ').addMapping(0, genFilePath, 0, 0);
6600        firstOffsetMapped = true;
6601      }
6602    };
6603    for (let i = 0; i < startsAtLine; i++) {
6604      map.addLine();
6605      mapFirstOffsetIfNeeded();
6606    }
6607    this.sourceLines.forEach((line, lineIdx) => {
6608      map.addLine();
6609      const spans = line.srcSpans;
6610      const parts = line.parts;
6611      let col0 = line.indent * _INDENT_WITH.length;
6612      let spanIdx = 0;
6613      // skip leading parts without source spans
6614      while (spanIdx < spans.length && !spans[spanIdx]) {
6615        col0 += parts[spanIdx].length;
6616        spanIdx++;
6617      }
6618      if (spanIdx < spans.length && lineIdx === 0 && col0 === 0) {
6619        firstOffsetMapped = true;
6620      } else {
6621        mapFirstOffsetIfNeeded();
6622      }
6623      while (spanIdx < spans.length) {
6624        const span = spans[spanIdx];
6625        const source = span.start.file;
6626        const sourceLine = span.start.line;
6627        const sourceCol = span.start.col;
6628        map.addSource(source.url, source.content).addMapping(col0, source.url, sourceLine, sourceCol);
6629        col0 += parts[spanIdx].length;
6630        spanIdx++;
6631        // assign parts without span or the same span to the previous segment
6632        while (spanIdx < spans.length && (span === spans[spanIdx] || !spans[spanIdx])) {
6633          col0 += parts[spanIdx].length;
6634          spanIdx++;
6635        }
6636      }
6637    });
6638    return map;
6639  }
6640  spanOf(line, column) {
6641    const emittedLine = this._lines[line];
6642    if (emittedLine) {
6643      let columnsLeft = column - _createIndent(emittedLine.indent).length;
6644      for (let partIndex = 0; partIndex < emittedLine.parts.length; partIndex++) {
6645        const part = emittedLine.parts[partIndex];
6646        if (part.length > columnsLeft) {
6647          return emittedLine.srcSpans[partIndex];
6648        }
6649        columnsLeft -= part.length;
6650      }
6651    }
6652    return null;
6653  }
6654  /**
6655   * @internal strip this from published d.ts files due to
6656   * https://github.com/microsoft/TypeScript/issues/36216
6657   */
6658  get sourceLines() {
6659    if (this._lines.length && this._lines[this._lines.length - 1].parts.length === 0) {
6660      return this._lines.slice(0, -1);
6661    }
6662    return this._lines;
6663  }
6664}
6665class AbstractEmitterVisitor {
6666  constructor(_escapeDollarInStrings) {
6667    this._escapeDollarInStrings = _escapeDollarInStrings;
6668  }
6669  printLeadingComments(stmt, ctx) {
6670    if (stmt.leadingComments === undefined) {
6671      return;
6672    }
6673    for (const comment of stmt.leadingComments) {
6674      if (comment instanceof JSDocComment) {
6675        ctx.print(stmt, `/*${comment.toString()}*/`, comment.trailingNewline);
6676      } else {
6677        if (comment.multiline) {
6678          ctx.print(stmt, `/* ${comment.text} */`, comment.trailingNewline);
6679        } else {
6680          comment.text.split('\n').forEach(line => {
6681            ctx.println(stmt, `// ${line}`);
6682          });
6683        }
6684      }
6685    }
6686  }
6687  visitExpressionStmt(stmt, ctx) {
6688    this.printLeadingComments(stmt, ctx);
6689    stmt.expr.visitExpression(this, ctx);
6690    ctx.println(stmt, ';');
6691    return null;
6692  }
6693  visitReturnStmt(stmt, ctx) {
6694    this.printLeadingComments(stmt, ctx);
6695    ctx.print(stmt, `return `);
6696    stmt.value.visitExpression(this, ctx);
6697    ctx.println(stmt, ';');
6698    return null;
6699  }
6700  visitIfStmt(stmt, ctx) {
6701    this.printLeadingComments(stmt, ctx);
6702    ctx.print(stmt, `if (`);
6703    stmt.condition.visitExpression(this, ctx);
6704    ctx.print(stmt, `) {`);
6705    const hasElseCase = stmt.falseCase != null && stmt.falseCase.length > 0;
6706    if (stmt.trueCase.length <= 1 && !hasElseCase) {
6707      ctx.print(stmt, ` `);
6708      this.visitAllStatements(stmt.trueCase, ctx);
6709      ctx.removeEmptyLastLine();
6710      ctx.print(stmt, ` `);
6711    } else {
6712      ctx.println();
6713      ctx.incIndent();
6714      this.visitAllStatements(stmt.trueCase, ctx);
6715      ctx.decIndent();
6716      if (hasElseCase) {
6717        ctx.println(stmt, `} else {`);
6718        ctx.incIndent();
6719        this.visitAllStatements(stmt.falseCase, ctx);
6720        ctx.decIndent();
6721      }
6722    }
6723    ctx.println(stmt, `}`);
6724    return null;
6725  }
6726  visitWriteVarExpr(expr, ctx) {
6727    const lineWasEmpty = ctx.lineIsEmpty();
6728    if (!lineWasEmpty) {
6729      ctx.print(expr, '(');
6730    }
6731    ctx.print(expr, `${expr.name} = `);
6732    expr.value.visitExpression(this, ctx);
6733    if (!lineWasEmpty) {
6734      ctx.print(expr, ')');
6735    }
6736    return null;
6737  }
6738  visitWriteKeyExpr(expr, ctx) {
6739    const lineWasEmpty = ctx.lineIsEmpty();
6740    if (!lineWasEmpty) {
6741      ctx.print(expr, '(');
6742    }
6743    expr.receiver.visitExpression(this, ctx);
6744    ctx.print(expr, `[`);
6745    expr.index.visitExpression(this, ctx);
6746    ctx.print(expr, `] = `);
6747    expr.value.visitExpression(this, ctx);
6748    if (!lineWasEmpty) {
6749      ctx.print(expr, ')');
6750    }
6751    return null;
6752  }
6753  visitWritePropExpr(expr, ctx) {
6754    const lineWasEmpty = ctx.lineIsEmpty();
6755    if (!lineWasEmpty) {
6756      ctx.print(expr, '(');
6757    }
6758    expr.receiver.visitExpression(this, ctx);
6759    ctx.print(expr, `.${expr.name} = `);
6760    expr.value.visitExpression(this, ctx);
6761    if (!lineWasEmpty) {
6762      ctx.print(expr, ')');
6763    }
6764    return null;
6765  }
6766  visitInvokeFunctionExpr(expr, ctx) {
6767    const shouldParenthesize = expr.fn instanceof ArrowFunctionExpr;
6768    if (shouldParenthesize) {
6769      ctx.print(expr.fn, '(');
6770    }
6771    expr.fn.visitExpression(this, ctx);
6772    if (shouldParenthesize) {
6773      ctx.print(expr.fn, ')');
6774    }
6775    ctx.print(expr, `(`);
6776    this.visitAllExpressions(expr.args, ctx, ',');
6777    ctx.print(expr, `)`);
6778    return null;
6779  }
6780  visitTaggedTemplateExpr(expr, ctx) {
6781    expr.tag.visitExpression(this, ctx);
6782    ctx.print(expr, '`' + expr.template.elements[0].rawText);
6783    for (let i = 1; i < expr.template.elements.length; i++) {
6784      ctx.print(expr, '${');
6785      expr.template.expressions[i - 1].visitExpression(this, ctx);
6786      ctx.print(expr, `}${expr.template.elements[i].rawText}`);
6787    }
6788    ctx.print(expr, '`');
6789    return null;
6790  }
6791  visitWrappedNodeExpr(ast, ctx) {
6792    throw new Error('Abstract emitter cannot visit WrappedNodeExpr.');
6793  }
6794  visitTypeofExpr(expr, ctx) {
6795    ctx.print(expr, 'typeof ');
6796    expr.expr.visitExpression(this, ctx);
6797  }
6798  visitReadVarExpr(ast, ctx) {
6799    ctx.print(ast, ast.name);
6800    return null;
6801  }
6802  visitInstantiateExpr(ast, ctx) {
6803    ctx.print(ast, `new `);
6804    ast.classExpr.visitExpression(this, ctx);
6805    ctx.print(ast, `(`);
6806    this.visitAllExpressions(ast.args, ctx, ',');
6807    ctx.print(ast, `)`);
6808    return null;
6809  }
6810  visitLiteralExpr(ast, ctx) {
6811    const value = ast.value;
6812    if (typeof value === 'string') {
6813      ctx.print(ast, escapeIdentifier(value, this._escapeDollarInStrings));
6814    } else {
6815      ctx.print(ast, `${value}`);
6816    }
6817    return null;
6818  }
6819  visitLocalizedString(ast, ctx) {
6820    const head = ast.serializeI18nHead();
6821    ctx.print(ast, '$localize `' + head.raw);
6822    for (let i = 1; i < ast.messageParts.length; i++) {
6823      ctx.print(ast, '${');
6824      ast.expressions[i - 1].visitExpression(this, ctx);
6825      ctx.print(ast, `}${ast.serializeI18nTemplatePart(i).raw}`);
6826    }
6827    ctx.print(ast, '`');
6828    return null;
6829  }
6830  visitConditionalExpr(ast, ctx) {
6831    ctx.print(ast, `(`);
6832    ast.condition.visitExpression(this, ctx);
6833    ctx.print(ast, '? ');
6834    ast.trueCase.visitExpression(this, ctx);
6835    ctx.print(ast, ': ');
6836    ast.falseCase.visitExpression(this, ctx);
6837    ctx.print(ast, `)`);
6838    return null;
6839  }
6840  visitDynamicImportExpr(ast, ctx) {
6841    ctx.print(ast, `import(${ast.url})`);
6842  }
6843  visitNotExpr(ast, ctx) {
6844    ctx.print(ast, '!');
6845    ast.condition.visitExpression(this, ctx);
6846    return null;
6847  }
6848  visitUnaryOperatorExpr(ast, ctx) {
6849    let opStr;
6850    switch (ast.operator) {
6851      case UnaryOperator.Plus:
6852        opStr = '+';
6853        break;
6854      case UnaryOperator.Minus:
6855        opStr = '-';
6856        break;
6857      default:
6858        throw new Error(`Unknown operator ${ast.operator}`);
6859    }
6860    if (ast.parens) ctx.print(ast, `(`);
6861    ctx.print(ast, opStr);
6862    ast.expr.visitExpression(this, ctx);
6863    if (ast.parens) ctx.print(ast, `)`);
6864    return null;
6865  }
6866  visitBinaryOperatorExpr(ast, ctx) {
6867    let opStr;
6868    switch (ast.operator) {
6869      case BinaryOperator.Equals:
6870        opStr = '==';
6871        break;
6872      case BinaryOperator.Identical:
6873        opStr = '===';
6874        break;
6875      case BinaryOperator.NotEquals:
6876        opStr = '!=';
6877        break;
6878      case BinaryOperator.NotIdentical:
6879        opStr = '!==';
6880        break;
6881      case BinaryOperator.And:
6882        opStr = '&&';
6883        break;
6884      case BinaryOperator.BitwiseOr:
6885        opStr = '|';
6886        break;
6887      case BinaryOperator.BitwiseAnd:
6888        opStr = '&';
6889        break;
6890      case BinaryOperator.Or:
6891        opStr = '||';
6892        break;
6893      case BinaryOperator.Plus:
6894        opStr = '+';
6895        break;
6896      case BinaryOperator.Minus:
6897        opStr = '-';
6898        break;
6899      case BinaryOperator.Divide:
6900        opStr = '/';
6901        break;
6902      case BinaryOperator.Multiply:
6903        opStr = '*';
6904        break;
6905      case BinaryOperator.Modulo:
6906        opStr = '%';
6907        break;
6908      case BinaryOperator.Lower:
6909        opStr = '<';
6910        break;
6911      case BinaryOperator.LowerEquals:
6912        opStr = '<=';
6913        break;
6914      case BinaryOperator.Bigger:
6915        opStr = '>';
6916        break;
6917      case BinaryOperator.BiggerEquals:
6918        opStr = '>=';
6919        break;
6920      case BinaryOperator.NullishCoalesce:
6921        opStr = '??';
6922        break;
6923      default:
6924        throw new Error(`Unknown operator ${ast.operator}`);
6925    }
6926    if (ast.parens) ctx.print(ast, `(`);
6927    ast.lhs.visitExpression(this, ctx);
6928    ctx.print(ast, ` ${opStr} `);
6929    ast.rhs.visitExpression(this, ctx);
6930    if (ast.parens) ctx.print(ast, `)`);
6931    return null;
6932  }
6933  visitReadPropExpr(ast, ctx) {
6934    ast.receiver.visitExpression(this, ctx);
6935    ctx.print(ast, `.`);
6936    ctx.print(ast, ast.name);
6937    return null;
6938  }
6939  visitReadKeyExpr(ast, ctx) {
6940    ast.receiver.visitExpression(this, ctx);
6941    ctx.print(ast, `[`);
6942    ast.index.visitExpression(this, ctx);
6943    ctx.print(ast, `]`);
6944    return null;
6945  }
6946  visitLiteralArrayExpr(ast, ctx) {
6947    ctx.print(ast, `[`);
6948    this.visitAllExpressions(ast.entries, ctx, ',');
6949    ctx.print(ast, `]`);
6950    return null;
6951  }
6952  visitLiteralMapExpr(ast, ctx) {
6953    ctx.print(ast, `{`);
6954    this.visitAllObjects(entry => {
6955      ctx.print(ast, `${escapeIdentifier(entry.key, this._escapeDollarInStrings, entry.quoted)}:`);
6956      entry.value.visitExpression(this, ctx);
6957    }, ast.entries, ctx, ',');
6958    ctx.print(ast, `}`);
6959    return null;
6960  }
6961  visitCommaExpr(ast, ctx) {
6962    ctx.print(ast, '(');
6963    this.visitAllExpressions(ast.parts, ctx, ',');
6964    ctx.print(ast, ')');
6965    return null;
6966  }
6967  visitAllExpressions(expressions, ctx, separator) {
6968    this.visitAllObjects(expr => expr.visitExpression(this, ctx), expressions, ctx, separator);
6969  }
6970  visitAllObjects(handler, expressions, ctx, separator) {
6971    let incrementedIndent = false;
6972    for (let i = 0; i < expressions.length; i++) {
6973      if (i > 0) {
6974        if (ctx.lineLength() > 80) {
6975          ctx.print(null, separator, true);
6976          if (!incrementedIndent) {
6977            // continuation are marked with double indent.
6978            ctx.incIndent();
6979            ctx.incIndent();
6980            incrementedIndent = true;
6981          }
6982        } else {
6983          ctx.print(null, separator, false);
6984        }
6985      }
6986      handler(expressions[i]);
6987    }
6988    if (incrementedIndent) {
6989      // continuation are marked with double indent.
6990      ctx.decIndent();
6991      ctx.decIndent();
6992    }
6993  }
6994  visitAllStatements(statements, ctx) {
6995    statements.forEach(stmt => stmt.visitStatement(this, ctx));
6996  }
6997}
6998function escapeIdentifier(input, escapeDollar, alwaysQuote = true) {
6999  if (input == null) {
7000    return null;
7001  }
7002  const body = input.replace(_SINGLE_QUOTE_ESCAPE_STRING_RE, (...match) => {
7003    if (match[0] == '$') {
7004      return escapeDollar ? '\\$' : '$';
7005    } else if (match[0] == '\n') {
7006      return '\\n';
7007    } else if (match[0] == '\r') {
7008      return '\\r';
7009    } else {
7010      return `\\${match[0]}`;
7011    }
7012  });
7013  const requiresQuotes = alwaysQuote || !_LEGAL_IDENTIFIER_RE.test(body);
7014  return requiresQuotes ? `'${body}'` : body;
7015}
7016function _createIndent(count) {
7017  let res = '';
7018  for (let i = 0; i < count; i++) {
7019    res += _INDENT_WITH;
7020  }
7021  return res;
7022}
7023function typeWithParameters(type, numParams) {
7024  if (numParams === 0) {
7025    return expressionType(type);
7026  }
7027  const params = [];
7028  for (let i = 0; i < numParams; i++) {
7029    params.push(DYNAMIC_TYPE);
7030  }
7031  return expressionType(type, undefined, params);
7032}
7033const ANIMATE_SYMBOL_PREFIX = '@';
7034function prepareSyntheticPropertyName(name) {
7035  return `${ANIMATE_SYMBOL_PREFIX}${name}`;
7036}
7037function prepareSyntheticListenerName(name, phase) {
7038  return `${ANIMATE_SYMBOL_PREFIX}${name}.${phase}`;
7039}
7040function getSafePropertyAccessString(accessor, name) {
7041  const escapedName = escapeIdentifier(name, false, false);
7042  return escapedName !== name ? `${accessor}[${escapedName}]` : `${accessor}.${name}`;
7043}
7044function prepareSyntheticListenerFunctionName(name, phase) {
7045  return `animation_${name}_${phase}`;
7046}
7047function jitOnlyGuardedExpression(expr) {
7048  return guardedExpression('ngJitMode', expr);
7049}
7050function devOnlyGuardedExpression(expr) {
7051  return guardedExpression('ngDevMode', expr);
7052}
7053function guardedExpression(guard, expr) {
7054  const guardExpr = new ExternalExpr({
7055    name: guard,
7056    moduleName: null
7057  });
7058  const guardNotDefined = new BinaryOperatorExpr(BinaryOperator.Identical, new TypeofExpr(guardExpr), literal('undefined'));
7059  const guardUndefinedOrTrue = new BinaryOperatorExpr(BinaryOperator.Or, guardNotDefined, guardExpr, /* type */undefined, /* sourceSpan */undefined, true);
7060  return new BinaryOperatorExpr(BinaryOperator.And, guardUndefinedOrTrue, expr);
7061}
7062function wrapReference(value) {
7063  const wrapped = new WrappedNodeExpr(value);
7064  return {
7065    value: wrapped,
7066    type: wrapped
7067  };
7068}
7069function refsToArray(refs, shouldForwardDeclare) {
7070  const values = literalArr(refs.map(ref => ref.value));
7071  return shouldForwardDeclare ? arrowFn([], values) : values;
7072}
7073function createMayBeForwardRefExpression(expression, forwardRef) {
7074  return {
7075    expression,
7076    forwardRef
7077  };
7078}
7079/**
7080 * Convert a `MaybeForwardRefExpression` to an `Expression`, possibly wrapping its expression in a
7081 * `forwardRef()` call.
7082 *
7083 * If `MaybeForwardRefExpression.forwardRef` is `ForwardRefHandling.Unwrapped` then the expression
7084 * was originally wrapped in a `forwardRef()` call to prevent the value from being eagerly evaluated
7085 * in the code.
7086 *
7087 * See `packages/compiler-cli/src/ngtsc/annotations/src/injectable.ts` and
7088 * `packages/compiler/src/jit_compiler_facade.ts` for more information.
7089 */
7090function convertFromMaybeForwardRefExpression({
7091  expression,
7092  forwardRef
7093}) {
7094  switch (forwardRef) {
7095    case 0 /* ForwardRefHandling.None */:
7096    case 1 /* ForwardRefHandling.Wrapped */:
7097      return expression;
7098    case 2 /* ForwardRefHandling.Unwrapped */:
7099      return generateForwardRef(expression);
7100  }
7101}
7102/**
7103 * Generate an expression that has the given `expr` wrapped in the following form:
7104 *
7105 * ```
7106 * forwardRef(() => expr)
7107 * ```
7108 */
7109function generateForwardRef(expr) {
7110  return importExpr(Identifiers.forwardRef).callFn([arrowFn([], expr)]);
7111}
7112var R3FactoryDelegateType;
7113(function (R3FactoryDelegateType) {
7114  R3FactoryDelegateType[R3FactoryDelegateType["Class"] = 0] = "Class";
7115  R3FactoryDelegateType[R3FactoryDelegateType["Function"] = 1] = "Function";
7116})(R3FactoryDelegateType || (R3FactoryDelegateType = {}));
7117var FactoryTarget$1;
7118(function (FactoryTarget) {
7119  FactoryTarget[FactoryTarget["Directive"] = 0] = "Directive";
7120  FactoryTarget[FactoryTarget["Component"] = 1] = "Component";
7121  FactoryTarget[FactoryTarget["Injectable"] = 2] = "Injectable";
7122  FactoryTarget[FactoryTarget["Pipe"] = 3] = "Pipe";
7123  FactoryTarget[FactoryTarget["NgModule"] = 4] = "NgModule";
7124})(FactoryTarget$1 || (FactoryTarget$1 = {}));
7125/**
7126 * Construct a factory function expression for the given `R3FactoryMetadata`.
7127 */
7128function compileFactoryFunction(meta) {
7129  const t = variable('t');
7130  let baseFactoryVar = null;
7131  // The type to instantiate via constructor invocation. If there is no delegated factory, meaning
7132  // this type is always created by constructor invocation, then this is the type-to-create
7133  // parameter provided by the user (t) if specified, or the current type if not. If there is a
7134  // delegated factory (which is used to create the current type) then this is only the type-to-
7135  // create parameter (t).
7136  const typeForCtor = !isDelegatedFactoryMetadata(meta) ? new BinaryOperatorExpr(BinaryOperator.Or, t, meta.type.value) : t;
7137  let ctorExpr = null;
7138  if (meta.deps !== null) {
7139    // There is a constructor (either explicitly or implicitly defined).
7140    if (meta.deps !== 'invalid') {
7141      ctorExpr = new InstantiateExpr(typeForCtor, injectDependencies(meta.deps, meta.target));
7142    }
7143  } else {
7144    // There is no constructor, use the base class' factory to construct typeForCtor.
7145    baseFactoryVar = variable(`ɵ${meta.name}_BaseFactory`);
7146    ctorExpr = baseFactoryVar.callFn([typeForCtor]);
7147  }
7148  const body = [];
7149  let retExpr = null;
7150  function makeConditionalFactory(nonCtorExpr) {
7151    const r = variable('r');
7152    body.push(r.set(NULL_EXPR).toDeclStmt());
7153    const ctorStmt = ctorExpr !== null ? r.set(ctorExpr).toStmt() : importExpr(Identifiers.invalidFactory).callFn([]).toStmt();
7154    body.push(ifStmt(t, [ctorStmt], [r.set(nonCtorExpr).toStmt()]));
7155    return r;
7156  }
7157  if (isDelegatedFactoryMetadata(meta)) {
7158    // This type is created with a delegated factory. If a type parameter is not specified, call
7159    // the factory instead.
7160    const delegateArgs = injectDependencies(meta.delegateDeps, meta.target);
7161    // Either call `new delegate(...)` or `delegate(...)` depending on meta.delegateType.
7162    const factoryExpr = new (meta.delegateType === R3FactoryDelegateType.Class ? InstantiateExpr : InvokeFunctionExpr)(meta.delegate, delegateArgs);
7163    retExpr = makeConditionalFactory(factoryExpr);
7164  } else if (isExpressionFactoryMetadata(meta)) {
7165    // TODO(alxhub): decide whether to lower the value here or in the caller
7166    retExpr = makeConditionalFactory(meta.expression);
7167  } else {
7168    retExpr = ctorExpr;
7169  }
7170  if (retExpr === null) {
7171    // The expression cannot be formed so render an `ɵɵinvalidFactory()` call.
7172    body.push(importExpr(Identifiers.invalidFactory).callFn([]).toStmt());
7173  } else if (baseFactoryVar !== null) {
7174    // This factory uses a base factory, so call `ɵɵgetInheritedFactory()` to compute it.
7175    const getInheritedFactoryCall = importExpr(Identifiers.getInheritedFactory).callFn([meta.type.value]);
7176    // Memoize the base factoryFn: `baseFactory || (baseFactory = ɵɵgetInheritedFactory(...))`
7177    const baseFactory = new BinaryOperatorExpr(BinaryOperator.Or, baseFactoryVar, baseFactoryVar.set(getInheritedFactoryCall));
7178    body.push(new ReturnStatement(baseFactory.callFn([typeForCtor])));
7179  } else {
7180    // This is straightforward factory, just return it.
7181    body.push(new ReturnStatement(retExpr));
7182  }
7183  let factoryFn = fn([new FnParam('t', DYNAMIC_TYPE)], body, INFERRED_TYPE, undefined, `${meta.name}_Factory`);
7184  if (baseFactoryVar !== null) {
7185    // There is a base factory variable so wrap its declaration along with the factory function into
7186    // an IIFE.
7187    factoryFn = arrowFn([], [new DeclareVarStmt(baseFactoryVar.name), new ReturnStatement(factoryFn)]).callFn([], /* sourceSpan */undefined, /* pure */true);
7188  }
7189  return {
7190    expression: factoryFn,
7191    statements: [],
7192    type: createFactoryType(meta)
7193  };
7194}
7195function createFactoryType(meta) {
7196  const ctorDepsType = meta.deps !== null && meta.deps !== 'invalid' ? createCtorDepsType(meta.deps) : NONE_TYPE;
7197  return expressionType(importExpr(Identifiers.FactoryDeclaration, [typeWithParameters(meta.type.type, meta.typeArgumentCount), ctorDepsType]));
7198}
7199function injectDependencies(deps, target) {
7200  return deps.map((dep, index) => compileInjectDependency(dep, target, index));
7201}
7202function compileInjectDependency(dep, target, index) {
7203  // Interpret the dependency according to its resolved type.
7204  if (dep.token === null) {
7205    return importExpr(Identifiers.invalidFactoryDep).callFn([literal(index)]);
7206  } else if (dep.attributeNameType === null) {
7207    // Build up the injection flags according to the metadata.
7208    const flags = 0 /* InjectFlags.Default */ | (dep.self ? 2 /* InjectFlags.Self */ : 0) | (dep.skipSelf ? 4 /* InjectFlags.SkipSelf */ : 0) | (dep.host ? 1 /* InjectFlags.Host */ : 0) | (dep.optional ? 8 /* InjectFlags.Optional */ : 0) | (target === FactoryTarget$1.Pipe ? 16 /* InjectFlags.ForPipe */ : 0);
7209    // If this dependency is optional or otherwise has non-default flags, then additional
7210    // parameters describing how to inject the dependency must be passed to the inject function
7211    // that's being used.
7212    let flagsParam = flags !== 0 /* InjectFlags.Default */ || dep.optional ? literal(flags) : null;
7213    // Build up the arguments to the injectFn call.
7214    const injectArgs = [dep.token];
7215    if (flagsParam) {
7216      injectArgs.push(flagsParam);
7217    }
7218    const injectFn = getInjectFn(target);
7219    return importExpr(injectFn).callFn(injectArgs);
7220  } else {
7221    // The `dep.attributeTypeName` value is defined, which indicates that this is an `@Attribute()`
7222    // type dependency. For the generated JS we still want to use the `dep.token` value in case the
7223    // name given for the attribute is not a string literal. For example given `@Attribute(foo())`,
7224    // we want to generate `ɵɵinjectAttribute(foo())`.
7225    //
7226    // The `dep.attributeTypeName` is only actually used (in `createCtorDepType()`) to generate
7227    // typings.
7228    return importExpr(Identifiers.injectAttribute).callFn([dep.token]);
7229  }
7230}
7231function createCtorDepsType(deps) {
7232  let hasTypes = false;
7233  const attributeTypes = deps.map(dep => {
7234    const type = createCtorDepType(dep);
7235    if (type !== null) {
7236      hasTypes = true;
7237      return type;
7238    } else {
7239      return literal(null);
7240    }
7241  });
7242  if (hasTypes) {
7243    return expressionType(literalArr(attributeTypes));
7244  } else {
7245    return NONE_TYPE;
7246  }
7247}
7248function createCtorDepType(dep) {
7249  const entries = [];
7250  if (dep.attributeNameType !== null) {
7251    entries.push({
7252      key: 'attribute',
7253      value: dep.attributeNameType,
7254      quoted: false
7255    });
7256  }
7257  if (dep.optional) {
7258    entries.push({
7259      key: 'optional',
7260      value: literal(true),
7261      quoted: false
7262    });
7263  }
7264  if (dep.host) {
7265    entries.push({
7266      key: 'host',
7267      value: literal(true),
7268      quoted: false
7269    });
7270  }
7271  if (dep.self) {
7272    entries.push({
7273      key: 'self',
7274      value: literal(true),
7275      quoted: false
7276    });
7277  }
7278  if (dep.skipSelf) {
7279    entries.push({
7280      key: 'skipSelf',
7281      value: literal(true),
7282      quoted: false
7283    });
7284  }
7285  return entries.length > 0 ? literalMap(entries) : null;
7286}
7287function isDelegatedFactoryMetadata(meta) {
7288  return meta.delegateType !== undefined;
7289}
7290function isExpressionFactoryMetadata(meta) {
7291  return meta.expression !== undefined;
7292}
7293function getInjectFn(target) {
7294  switch (target) {
7295    case FactoryTarget$1.Component:
7296    case FactoryTarget$1.Directive:
7297    case FactoryTarget$1.Pipe:
7298      return Identifiers.directiveInject;
7299    case FactoryTarget$1.NgModule:
7300    case FactoryTarget$1.Injectable:
7301    default:
7302      return Identifiers.inject;
7303  }
7304}
7305var TagContentType;
7306(function (TagContentType) {
7307  TagContentType[TagContentType["RAW_TEXT"] = 0] = "RAW_TEXT";
7308  TagContentType[TagContentType["ESCAPABLE_RAW_TEXT"] = 1] = "ESCAPABLE_RAW_TEXT";
7309  TagContentType[TagContentType["PARSABLE_DATA"] = 2] = "PARSABLE_DATA";
7310})(TagContentType || (TagContentType = {}));
7311function splitNsName(elementName, fatal = true) {
7312  if (elementName[0] != ':') {
7313    return [null, elementName];
7314  }
7315  const colonIndex = elementName.indexOf(':', 1);
7316  if (colonIndex === -1) {
7317    if (fatal) {
7318      throw new Error(`Unsupported format "${elementName}" expecting ":namespace:name"`);
7319    } else {
7320      return [null, elementName];
7321    }
7322  }
7323  return [elementName.slice(1, colonIndex), elementName.slice(colonIndex + 1)];
7324}
7325// `<ng-container>` tags work the same regardless the namespace
7326function isNgContainer(tagName) {
7327  return splitNsName(tagName)[1] === 'ng-container';
7328}
7329// `<ng-content>` tags work the same regardless the namespace
7330function isNgContent(tagName) {
7331  return splitNsName(tagName)[1] === 'ng-content';
7332}
7333// `<ng-template>` tags work the same regardless the namespace
7334function isNgTemplate(tagName) {
7335  return splitNsName(tagName)[1] === 'ng-template';
7336}
7337function getNsPrefix(fullName) {
7338  return fullName === null ? null : splitNsName(fullName)[0];
7339}
7340function mergeNsAndName(prefix, localName) {
7341  return prefix ? `:${prefix}:${localName}` : localName;
7342}
7343
7344/**
7345 * This is an R3 `Node`-like wrapper for a raw `html.Comment` node. We do not currently
7346 * require the implementation of a visitor for Comments as they are only collected at
7347 * the top-level of the R3 AST, and only if `Render3ParseOptions['collectCommentNodes']`
7348 * is true.
7349 */
7350class Comment$1 {
7351  constructor(value, sourceSpan) {
7352    this.value = value;
7353    this.sourceSpan = sourceSpan;
7354  }
7355  visit(_visitor) {
7356    throw new Error('visit() not implemented for Comment');
7357  }
7358}
7359class Text$3 {
7360  constructor(value, sourceSpan) {
7361    this.value = value;
7362    this.sourceSpan = sourceSpan;
7363  }
7364  visit(visitor) {
7365    return visitor.visitText(this);
7366  }
7367}
7368class BoundText {
7369  constructor(value, sourceSpan, i18n) {
7370    this.value = value;
7371    this.sourceSpan = sourceSpan;
7372    this.i18n = i18n;
7373  }
7374  visit(visitor) {
7375    return visitor.visitBoundText(this);
7376  }
7377}
7378/**
7379 * Represents a text attribute in the template.
7380 *
7381 * `valueSpan` may not be present in cases where there is no value `<div a></div>`.
7382 * `keySpan` may also not be present for synthetic attributes from ICU expansions.
7383 */
7384class TextAttribute {
7385  constructor(name, value, sourceSpan, keySpan, valueSpan, i18n) {
7386    this.name = name;
7387    this.value = value;
7388    this.sourceSpan = sourceSpan;
7389    this.keySpan = keySpan;
7390    this.valueSpan = valueSpan;
7391    this.i18n = i18n;
7392  }
7393  visit(visitor) {
7394    return visitor.visitTextAttribute(this);
7395  }
7396}
7397class BoundAttribute {
7398  constructor(name, type, securityContext, value, unit, sourceSpan, keySpan, valueSpan, i18n) {
7399    this.name = name;
7400    this.type = type;
7401    this.securityContext = securityContext;
7402    this.value = value;
7403    this.unit = unit;
7404    this.sourceSpan = sourceSpan;
7405    this.keySpan = keySpan;
7406    this.valueSpan = valueSpan;
7407    this.i18n = i18n;
7408  }
7409  static fromBoundElementProperty(prop, i18n) {
7410    if (prop.keySpan === undefined) {
7411      throw new Error(`Unexpected state: keySpan must be defined for bound attributes but was not for ${prop.name}: ${prop.sourceSpan}`);
7412    }
7413    return new BoundAttribute(prop.name, prop.type, prop.securityContext, prop.value, prop.unit, prop.sourceSpan, prop.keySpan, prop.valueSpan, i18n);
7414  }
7415  visit(visitor) {
7416    return visitor.visitBoundAttribute(this);
7417  }
7418}
7419class BoundEvent {
7420  constructor(name, type, handler, target, phase, sourceSpan, handlerSpan, keySpan) {
7421    this.name = name;
7422    this.type = type;
7423    this.handler = handler;
7424    this.target = target;
7425    this.phase = phase;
7426    this.sourceSpan = sourceSpan;
7427    this.handlerSpan = handlerSpan;
7428    this.keySpan = keySpan;
7429  }
7430  static fromParsedEvent(event) {
7431    const target = event.type === 0 /* ParsedEventType.Regular */ ? event.targetOrPhase : null;
7432    const phase = event.type === 1 /* ParsedEventType.Animation */ ? event.targetOrPhase : null;
7433    if (event.keySpan === undefined) {
7434      throw new Error(`Unexpected state: keySpan must be defined for bound event but was not for ${event.name}: ${event.sourceSpan}`);
7435    }
7436    return new BoundEvent(event.name, event.type, event.handler, target, phase, event.sourceSpan, event.handlerSpan, event.keySpan);
7437  }
7438  visit(visitor) {
7439    return visitor.visitBoundEvent(this);
7440  }
7441}
7442class Element$1 {
7443  constructor(name, attributes, inputs, outputs, children, references, sourceSpan, startSourceSpan, endSourceSpan, i18n) {
7444    this.name = name;
7445    this.attributes = attributes;
7446    this.inputs = inputs;
7447    this.outputs = outputs;
7448    this.children = children;
7449    this.references = references;
7450    this.sourceSpan = sourceSpan;
7451    this.startSourceSpan = startSourceSpan;
7452    this.endSourceSpan = endSourceSpan;
7453    this.i18n = i18n;
7454  }
7455  visit(visitor) {
7456    return visitor.visitElement(this);
7457  }
7458}
7459class DeferredTrigger {
7460  constructor(nameSpan, sourceSpan, prefetchSpan, whenOrOnSourceSpan) {
7461    this.nameSpan = nameSpan;
7462    this.sourceSpan = sourceSpan;
7463    this.prefetchSpan = prefetchSpan;
7464    this.whenOrOnSourceSpan = whenOrOnSourceSpan;
7465  }
7466  visit(visitor) {
7467    return visitor.visitDeferredTrigger(this);
7468  }
7469}
7470class BoundDeferredTrigger extends DeferredTrigger {
7471  constructor(value, sourceSpan, prefetchSpan, whenSourceSpan) {
7472    // BoundDeferredTrigger is for 'when' triggers. These aren't really "triggers" and don't have a
7473    // nameSpan. Trigger names are the built in event triggers like hover, interaction, etc.
7474    super( /** nameSpan */null, sourceSpan, prefetchSpan, whenSourceSpan);
7475    this.value = value;
7476  }
7477}
7478class IdleDeferredTrigger extends DeferredTrigger {}
7479class ImmediateDeferredTrigger extends DeferredTrigger {}
7480class HoverDeferredTrigger extends DeferredTrigger {
7481  constructor(reference, nameSpan, sourceSpan, prefetchSpan, onSourceSpan) {
7482    super(nameSpan, sourceSpan, prefetchSpan, onSourceSpan);
7483    this.reference = reference;
7484  }
7485}
7486class TimerDeferredTrigger extends DeferredTrigger {
7487  constructor(delay, nameSpan, sourceSpan, prefetchSpan, onSourceSpan) {
7488    super(nameSpan, sourceSpan, prefetchSpan, onSourceSpan);
7489    this.delay = delay;
7490  }
7491}
7492class InteractionDeferredTrigger extends DeferredTrigger {
7493  constructor(reference, nameSpan, sourceSpan, prefetchSpan, onSourceSpan) {
7494    super(nameSpan, sourceSpan, prefetchSpan, onSourceSpan);
7495    this.reference = reference;
7496  }
7497}
7498class ViewportDeferredTrigger extends DeferredTrigger {
7499  constructor(reference, nameSpan, sourceSpan, prefetchSpan, onSourceSpan) {
7500    super(nameSpan, sourceSpan, prefetchSpan, onSourceSpan);
7501    this.reference = reference;
7502  }
7503}
7504class BlockNode {
7505  constructor(nameSpan, sourceSpan, startSourceSpan, endSourceSpan) {
7506    this.nameSpan = nameSpan;
7507    this.sourceSpan = sourceSpan;
7508    this.startSourceSpan = startSourceSpan;
7509    this.endSourceSpan = endSourceSpan;
7510  }
7511}
7512class DeferredBlockPlaceholder extends BlockNode {
7513  constructor(children, minimumTime, nameSpan, sourceSpan, startSourceSpan, endSourceSpan, i18n) {
7514    super(nameSpan, sourceSpan, startSourceSpan, endSourceSpan);
7515    this.children = children;
7516    this.minimumTime = minimumTime;
7517    this.i18n = i18n;
7518  }
7519  visit(visitor) {
7520    return visitor.visitDeferredBlockPlaceholder(this);
7521  }
7522}
7523class DeferredBlockLoading extends BlockNode {
7524  constructor(children, afterTime, minimumTime, nameSpan, sourceSpan, startSourceSpan, endSourceSpan, i18n) {
7525    super(nameSpan, sourceSpan, startSourceSpan, endSourceSpan);
7526    this.children = children;
7527    this.afterTime = afterTime;
7528    this.minimumTime = minimumTime;
7529    this.i18n = i18n;
7530  }
7531  visit(visitor) {
7532    return visitor.visitDeferredBlockLoading(this);
7533  }
7534}
7535class DeferredBlockError extends BlockNode {
7536  constructor(children, nameSpan, sourceSpan, startSourceSpan, endSourceSpan, i18n) {
7537    super(nameSpan, sourceSpan, startSourceSpan, endSourceSpan);
7538    this.children = children;
7539    this.i18n = i18n;
7540  }
7541  visit(visitor) {
7542    return visitor.visitDeferredBlockError(this);
7543  }
7544}
7545class DeferredBlock extends BlockNode {
7546  constructor(children, triggers, prefetchTriggers, placeholder, loading, error, nameSpan, sourceSpan, mainBlockSpan, startSourceSpan, endSourceSpan, i18n) {
7547    super(nameSpan, sourceSpan, startSourceSpan, endSourceSpan);
7548    this.children = children;
7549    this.placeholder = placeholder;
7550    this.loading = loading;
7551    this.error = error;
7552    this.mainBlockSpan = mainBlockSpan;
7553    this.i18n = i18n;
7554    this.triggers = triggers;
7555    this.prefetchTriggers = prefetchTriggers;
7556    // We cache the keys since we know that they won't change and we
7557    // don't want to enumarate them every time we're traversing the AST.
7558    this.definedTriggers = Object.keys(triggers);
7559    this.definedPrefetchTriggers = Object.keys(prefetchTriggers);
7560  }
7561  visit(visitor) {
7562    return visitor.visitDeferredBlock(this);
7563  }
7564  visitAll(visitor) {
7565    this.visitTriggers(this.definedTriggers, this.triggers, visitor);
7566    this.visitTriggers(this.definedPrefetchTriggers, this.prefetchTriggers, visitor);
7567    visitAll$1(visitor, this.children);
7568    const remainingBlocks = [this.placeholder, this.loading, this.error].filter(x => x !== null);
7569    visitAll$1(visitor, remainingBlocks);
7570  }
7571  visitTriggers(keys, triggers, visitor) {
7572    visitAll$1(visitor, keys.map(k => triggers[k]));
7573  }
7574}
7575class SwitchBlock extends BlockNode {
7576  constructor(expression, cases,
7577  /**
7578   * These blocks are only captured to allow for autocompletion in the language service. They
7579   * aren't meant to be processed in any other way.
7580   */
7581  unknownBlocks, sourceSpan, startSourceSpan, endSourceSpan, nameSpan) {
7582    super(nameSpan, sourceSpan, startSourceSpan, endSourceSpan);
7583    this.expression = expression;
7584    this.cases = cases;
7585    this.unknownBlocks = unknownBlocks;
7586  }
7587  visit(visitor) {
7588    return visitor.visitSwitchBlock(this);
7589  }
7590}
7591class SwitchBlockCase extends BlockNode {
7592  constructor(expression, children, sourceSpan, startSourceSpan, endSourceSpan, nameSpan, i18n) {
7593    super(nameSpan, sourceSpan, startSourceSpan, endSourceSpan);
7594    this.expression = expression;
7595    this.children = children;
7596    this.i18n = i18n;
7597  }
7598  visit(visitor) {
7599    return visitor.visitSwitchBlockCase(this);
7600  }
7601}
7602class ForLoopBlock extends BlockNode {
7603  constructor(item, expression, trackBy, trackKeywordSpan, contextVariables, children, empty, sourceSpan, mainBlockSpan, startSourceSpan, endSourceSpan, nameSpan, i18n) {
7604    super(nameSpan, sourceSpan, startSourceSpan, endSourceSpan);
7605    this.item = item;
7606    this.expression = expression;
7607    this.trackBy = trackBy;
7608    this.trackKeywordSpan = trackKeywordSpan;
7609    this.contextVariables = contextVariables;
7610    this.children = children;
7611    this.empty = empty;
7612    this.mainBlockSpan = mainBlockSpan;
7613    this.i18n = i18n;
7614  }
7615  visit(visitor) {
7616    return visitor.visitForLoopBlock(this);
7617  }
7618}
7619class ForLoopBlockEmpty extends BlockNode {
7620  constructor(children, sourceSpan, startSourceSpan, endSourceSpan, nameSpan, i18n) {
7621    super(nameSpan, sourceSpan, startSourceSpan, endSourceSpan);
7622    this.children = children;
7623    this.i18n = i18n;
7624  }
7625  visit(visitor) {
7626    return visitor.visitForLoopBlockEmpty(this);
7627  }
7628}
7629class IfBlock extends BlockNode {
7630  constructor(branches, sourceSpan, startSourceSpan, endSourceSpan, nameSpan) {
7631    super(nameSpan, sourceSpan, startSourceSpan, endSourceSpan);
7632    this.branches = branches;
7633  }
7634  visit(visitor) {
7635    return visitor.visitIfBlock(this);
7636  }
7637}
7638class IfBlockBranch extends BlockNode {
7639  constructor(expression, children, expressionAlias, sourceSpan, startSourceSpan, endSourceSpan, nameSpan, i18n) {
7640    super(nameSpan, sourceSpan, startSourceSpan, endSourceSpan);
7641    this.expression = expression;
7642    this.children = children;
7643    this.expressionAlias = expressionAlias;
7644    this.i18n = i18n;
7645  }
7646  visit(visitor) {
7647    return visitor.visitIfBlockBranch(this);
7648  }
7649}
7650class UnknownBlock {
7651  constructor(name, sourceSpan, nameSpan) {
7652    this.name = name;
7653    this.sourceSpan = sourceSpan;
7654    this.nameSpan = nameSpan;
7655  }
7656  visit(visitor) {
7657    return visitor.visitUnknownBlock(this);
7658  }
7659}
7660class Template {
7661  constructor(
7662  // tagName is the name of the container element, if applicable.
7663  // `null` is a special case for when there is a structural directive on an `ng-template` so
7664  // the renderer can differentiate between the synthetic template and the one written in the
7665  // file.
7666  tagName, attributes, inputs, outputs, templateAttrs, children, references, variables, sourceSpan, startSourceSpan, endSourceSpan, i18n) {
7667    this.tagName = tagName;
7668    this.attributes = attributes;
7669    this.inputs = inputs;
7670    this.outputs = outputs;
7671    this.templateAttrs = templateAttrs;
7672    this.children = children;
7673    this.references = references;
7674    this.variables = variables;
7675    this.sourceSpan = sourceSpan;
7676    this.startSourceSpan = startSourceSpan;
7677    this.endSourceSpan = endSourceSpan;
7678    this.i18n = i18n;
7679  }
7680  visit(visitor) {
7681    return visitor.visitTemplate(this);
7682  }
7683}
7684class Content {
7685  constructor(selector, attributes, sourceSpan, i18n) {
7686    this.selector = selector;
7687    this.attributes = attributes;
7688    this.sourceSpan = sourceSpan;
7689    this.i18n = i18n;
7690    this.name = 'ng-content';
7691  }
7692  visit(visitor) {
7693    return visitor.visitContent(this);
7694  }
7695}
7696class Variable {
7697  constructor(name, value, sourceSpan, keySpan, valueSpan) {
7698    this.name = name;
7699    this.value = value;
7700    this.sourceSpan = sourceSpan;
7701    this.keySpan = keySpan;
7702    this.valueSpan = valueSpan;
7703  }
7704  visit(visitor) {
7705    return visitor.visitVariable(this);
7706  }
7707}
7708class Reference {
7709  constructor(name, value, sourceSpan, keySpan, valueSpan) {
7710    this.name = name;
7711    this.value = value;
7712    this.sourceSpan = sourceSpan;
7713    this.keySpan = keySpan;
7714    this.valueSpan = valueSpan;
7715  }
7716  visit(visitor) {
7717    return visitor.visitReference(this);
7718  }
7719}
7720class Icu$1 {
7721  constructor(vars, placeholders, sourceSpan, i18n) {
7722    this.vars = vars;
7723    this.placeholders = placeholders;
7724    this.sourceSpan = sourceSpan;
7725    this.i18n = i18n;
7726  }
7727  visit(visitor) {
7728    return visitor.visitIcu(this);
7729  }
7730}
7731class RecursiveVisitor$1 {
7732  visitElement(element) {
7733    visitAll$1(this, element.attributes);
7734    visitAll$1(this, element.inputs);
7735    visitAll$1(this, element.outputs);
7736    visitAll$1(this, element.children);
7737    visitAll$1(this, element.references);
7738  }
7739  visitTemplate(template) {
7740    visitAll$1(this, template.attributes);
7741    visitAll$1(this, template.inputs);
7742    visitAll$1(this, template.outputs);
7743    visitAll$1(this, template.children);
7744    visitAll$1(this, template.references);
7745    visitAll$1(this, template.variables);
7746  }
7747  visitDeferredBlock(deferred) {
7748    deferred.visitAll(this);
7749  }
7750  visitDeferredBlockPlaceholder(block) {
7751    visitAll$1(this, block.children);
7752  }
7753  visitDeferredBlockError(block) {
7754    visitAll$1(this, block.children);
7755  }
7756  visitDeferredBlockLoading(block) {
7757    visitAll$1(this, block.children);
7758  }
7759  visitSwitchBlock(block) {
7760    visitAll$1(this, block.cases);
7761  }
7762  visitSwitchBlockCase(block) {
7763    visitAll$1(this, block.children);
7764  }
7765  visitForLoopBlock(block) {
7766    const blockItems = [block.item, ...Object.values(block.contextVariables), ...block.children];
7767    block.empty && blockItems.push(block.empty);
7768    visitAll$1(this, blockItems);
7769  }
7770  visitForLoopBlockEmpty(block) {
7771    visitAll$1(this, block.children);
7772  }
7773  visitIfBlock(block) {
7774    visitAll$1(this, block.branches);
7775  }
7776  visitIfBlockBranch(block) {
7777    const blockItems = block.children;
7778    block.expressionAlias && blockItems.push(block.expressionAlias);
7779    visitAll$1(this, blockItems);
7780  }
7781  visitContent(content) {}
7782  visitVariable(variable) {}
7783  visitReference(reference) {}
7784  visitTextAttribute(attribute) {}
7785  visitBoundAttribute(attribute) {}
7786  visitBoundEvent(attribute) {}
7787  visitText(text) {}
7788  visitBoundText(text) {}
7789  visitIcu(icu) {}
7790  visitDeferredTrigger(trigger) {}
7791  visitUnknownBlock(block) {}
7792}
7793function visitAll$1(visitor, nodes) {
7794  const result = [];
7795  if (visitor.visit) {
7796    for (const node of nodes) {
7797      visitor.visit(node) || node.visit(visitor);
7798    }
7799  } else {
7800    for (const node of nodes) {
7801      const newNode = node.visit(visitor);
7802      if (newNode) {
7803        result.push(newNode);
7804      }
7805    }
7806  }
7807  return result;
7808}
7809class Message {
7810  /**
7811   * @param nodes message AST
7812   * @param placeholders maps placeholder names to static content and their source spans
7813   * @param placeholderToMessage maps placeholder names to messages (used for nested ICU messages)
7814   * @param meaning
7815   * @param description
7816   * @param customId
7817   */
7818  constructor(nodes, placeholders, placeholderToMessage, meaning, description, customId) {
7819    this.nodes = nodes;
7820    this.placeholders = placeholders;
7821    this.placeholderToMessage = placeholderToMessage;
7822    this.meaning = meaning;
7823    this.description = description;
7824    this.customId = customId;
7825    /** The ids to use if there are no custom id and if `i18nLegacyMessageIdFormat` is not empty */
7826    this.legacyIds = [];
7827    this.id = this.customId;
7828    this.messageString = serializeMessage(this.nodes);
7829    if (nodes.length) {
7830      this.sources = [{
7831        filePath: nodes[0].sourceSpan.start.file.url,
7832        startLine: nodes[0].sourceSpan.start.line + 1,
7833        startCol: nodes[0].sourceSpan.start.col + 1,
7834        endLine: nodes[nodes.length - 1].sourceSpan.end.line + 1,
7835        endCol: nodes[0].sourceSpan.start.col + 1
7836      }];
7837    } else {
7838      this.sources = [];
7839    }
7840  }
7841}
7842class Text$2 {
7843  constructor(value, sourceSpan) {
7844    this.value = value;
7845    this.sourceSpan = sourceSpan;
7846  }
7847  visit(visitor, context) {
7848    return visitor.visitText(this, context);
7849  }
7850}
7851// TODO(vicb): do we really need this node (vs an array) ?
7852class Container {
7853  constructor(children, sourceSpan) {
7854    this.children = children;
7855    this.sourceSpan = sourceSpan;
7856  }
7857  visit(visitor, context) {
7858    return visitor.visitContainer(this, context);
7859  }
7860}
7861class Icu {
7862  constructor(expression, type, cases, sourceSpan, expressionPlaceholder) {
7863    this.expression = expression;
7864    this.type = type;
7865    this.cases = cases;
7866    this.sourceSpan = sourceSpan;
7867    this.expressionPlaceholder = expressionPlaceholder;
7868  }
7869  visit(visitor, context) {
7870    return visitor.visitIcu(this, context);
7871  }
7872}
7873class TagPlaceholder {
7874  constructor(tag, attrs, startName, closeName, children, isVoid,
7875  // TODO sourceSpan should cover all (we need a startSourceSpan and endSourceSpan)
7876  sourceSpan, startSourceSpan, endSourceSpan) {
7877    this.tag = tag;
7878    this.attrs = attrs;
7879    this.startName = startName;
7880    this.closeName = closeName;
7881    this.children = children;
7882    this.isVoid = isVoid;
7883    this.sourceSpan = sourceSpan;
7884    this.startSourceSpan = startSourceSpan;
7885    this.endSourceSpan = endSourceSpan;
7886  }
7887  visit(visitor, context) {
7888    return visitor.visitTagPlaceholder(this, context);
7889  }
7890}
7891class Placeholder {
7892  constructor(value, name, sourceSpan) {
7893    this.value = value;
7894    this.name = name;
7895    this.sourceSpan = sourceSpan;
7896  }
7897  visit(visitor, context) {
7898    return visitor.visitPlaceholder(this, context);
7899  }
7900}
7901class IcuPlaceholder {
7902  constructor(value, name, sourceSpan) {
7903    this.value = value;
7904    this.name = name;
7905    this.sourceSpan = sourceSpan;
7906  }
7907  visit(visitor, context) {
7908    return visitor.visitIcuPlaceholder(this, context);
7909  }
7910}
7911class BlockPlaceholder {
7912  constructor(name, parameters, startName, closeName, children, sourceSpan, startSourceSpan, endSourceSpan) {
7913    this.name = name;
7914    this.parameters = parameters;
7915    this.startName = startName;
7916    this.closeName = closeName;
7917    this.children = children;
7918    this.sourceSpan = sourceSpan;
7919    this.startSourceSpan = startSourceSpan;
7920    this.endSourceSpan = endSourceSpan;
7921  }
7922  visit(visitor, context) {
7923    return visitor.visitBlockPlaceholder(this, context);
7924  }
7925}
7926// Clone the AST
7927class CloneVisitor {
7928  visitText(text, context) {
7929    return new Text$2(text.value, text.sourceSpan);
7930  }
7931  visitContainer(container, context) {
7932    const children = container.children.map(n => n.visit(this, context));
7933    return new Container(children, container.sourceSpan);
7934  }
7935  visitIcu(icu, context) {
7936    const cases = {};
7937    Object.keys(icu.cases).forEach(key => cases[key] = icu.cases[key].visit(this, context));
7938    const msg = new Icu(icu.expression, icu.type, cases, icu.sourceSpan, icu.expressionPlaceholder);
7939    return msg;
7940  }
7941  visitTagPlaceholder(ph, context) {
7942    const children = ph.children.map(n => n.visit(this, context));
7943    return new TagPlaceholder(ph.tag, ph.attrs, ph.startName, ph.closeName, children, ph.isVoid, ph.sourceSpan, ph.startSourceSpan, ph.endSourceSpan);
7944  }
7945  visitPlaceholder(ph, context) {
7946    return new Placeholder(ph.value, ph.name, ph.sourceSpan);
7947  }
7948  visitIcuPlaceholder(ph, context) {
7949    return new IcuPlaceholder(ph.value, ph.name, ph.sourceSpan);
7950  }
7951  visitBlockPlaceholder(ph, context) {
7952    const children = ph.children.map(n => n.visit(this, context));
7953    return new BlockPlaceholder(ph.name, ph.parameters, ph.startName, ph.closeName, children, ph.sourceSpan, ph.startSourceSpan, ph.endSourceSpan);
7954  }
7955}
7956// Visit all the nodes recursively
7957class RecurseVisitor {
7958  visitText(text, context) {}
7959  visitContainer(container, context) {
7960    container.children.forEach(child => child.visit(this));
7961  }
7962  visitIcu(icu, context) {
7963    Object.keys(icu.cases).forEach(k => {
7964      icu.cases[k].visit(this);
7965    });
7966  }
7967  visitTagPlaceholder(ph, context) {
7968    ph.children.forEach(child => child.visit(this));
7969  }
7970  visitPlaceholder(ph, context) {}
7971  visitIcuPlaceholder(ph, context) {}
7972  visitBlockPlaceholder(ph, context) {
7973    ph.children.forEach(child => child.visit(this));
7974  }
7975}
7976/**
7977 * Serialize the message to the Localize backtick string format that would appear in compiled code.
7978 */
7979function serializeMessage(messageNodes) {
7980  const visitor = new LocalizeMessageStringVisitor();
7981  const str = messageNodes.map(n => n.visit(visitor)).join('');
7982  return str;
7983}
7984class LocalizeMessageStringVisitor {
7985  visitText(text) {
7986    return text.value;
7987  }
7988  visitContainer(container) {
7989    return container.children.map(child => child.visit(this)).join('');
7990  }
7991  visitIcu(icu) {
7992    const strCases = Object.keys(icu.cases).map(k => `${k} {${icu.cases[k].visit(this)}}`);
7993    return `{${icu.expressionPlaceholder}, ${icu.type}, ${strCases.join(' ')}}`;
7994  }
7995  visitTagPlaceholder(ph) {
7996    const children = ph.children.map(child => child.visit(this)).join('');
7997    return `{$${ph.startName}}${children}{$${ph.closeName}}`;
7998  }
7999  visitPlaceholder(ph) {
8000    return `{$${ph.name}}`;
8001  }
8002  visitIcuPlaceholder(ph) {
8003    return `{$${ph.name}}`;
8004  }
8005  visitBlockPlaceholder(ph) {
8006    const children = ph.children.map(child => child.visit(this)).join('');
8007    return `{$${ph.startName}}${children}{$${ph.closeName}}`;
8008  }
8009}
8010class Serializer {
8011  // Creates a name mapper, see `PlaceholderMapper`
8012  // Returning `null` means that no name mapping is used.
8013  createNameMapper(message) {
8014    return null;
8015  }
8016}
8017/**
8018 * A simple mapper that take a function to transform an internal name to a public name
8019 */
8020class SimplePlaceholderMapper extends RecurseVisitor {
8021  // create a mapping from the message
8022  constructor(message, mapName) {
8023    super();
8024    this.mapName = mapName;
8025    this.internalToPublic = {};
8026    this.publicToNextId = {};
8027    this.publicToInternal = {};
8028    message.nodes.forEach(node => node.visit(this));
8029  }
8030  toPublicName(internalName) {
8031    return this.internalToPublic.hasOwnProperty(internalName) ? this.internalToPublic[internalName] : null;
8032  }
8033  toInternalName(publicName) {
8034    return this.publicToInternal.hasOwnProperty(publicName) ? this.publicToInternal[publicName] : null;
8035  }
8036  visitText(text, context) {
8037    return null;
8038  }
8039  visitTagPlaceholder(ph, context) {
8040    this.visitPlaceholderName(ph.startName);
8041    super.visitTagPlaceholder(ph, context);
8042    this.visitPlaceholderName(ph.closeName);
8043  }
8044  visitPlaceholder(ph, context) {
8045    this.visitPlaceholderName(ph.name);
8046  }
8047  visitBlockPlaceholder(ph, context) {
8048    this.visitPlaceholderName(ph.startName);
8049    super.visitBlockPlaceholder(ph, context);
8050    this.visitPlaceholderName(ph.closeName);
8051  }
8052  visitIcuPlaceholder(ph, context) {
8053    this.visitPlaceholderName(ph.name);
8054  }
8055  // XMB placeholders could only contains A-Z, 0-9 and _
8056  visitPlaceholderName(internalName) {
8057    if (!internalName || this.internalToPublic.hasOwnProperty(internalName)) {
8058      return;
8059    }
8060    let publicName = this.mapName(internalName);
8061    if (this.publicToInternal.hasOwnProperty(publicName)) {
8062      // Create a new XMB when it has already been used
8063      const nextId = this.publicToNextId[publicName];
8064      this.publicToNextId[publicName] = nextId + 1;
8065      publicName = `${publicName}_${nextId}`;
8066    } else {
8067      this.publicToNextId[publicName] = 1;
8068    }
8069    this.internalToPublic[internalName] = publicName;
8070    this.publicToInternal[publicName] = internalName;
8071  }
8072}
8073class _Visitor$2 {
8074  visitTag(tag) {
8075    const strAttrs = this._serializeAttributes(tag.attrs);
8076    if (tag.children.length == 0) {
8077      return `<${tag.name}${strAttrs}/>`;
8078    }
8079    const strChildren = tag.children.map(node =>
8079 node.visit(this));
8080    return `<${tag.name}${strAttrs}>${strChildren.join('')}</${tag.name}>`;
8081  }
8082  visitText(text) {
8083    return text.value;
8084  }
8085  visitDeclaration(decl) {
8086    return `<?xml${this._serializeAttributes(decl.attrs)} ?>`;
8087  }
8088  _serializeAttributes(attrs) {
8089    const strAttrs = Object.keys(attrs).map(name => `${name}="${attrs[name]}"`).join(' ');
8090    return strAttrs.length > 0 ? ' ' + strAttrs : '';
8091  }
8092  visitDoctype(doctype) {
8093    return `<!DOCTYPE ${doctype.rootTag} [\n${doctype.dtd}\n]>`;
8094  }
8095}
8096const _visitor = new _Visitor$2();
8097function serialize(nodes) {
8098  return nodes.map(node => node.visit(_visitor)).join('');
8099}
8100class Declaration {
8101  constructor(unescapedAttrs) {
8102    this.attrs = {};
8103    Object.keys(unescapedAttrs).forEach(k => {
8104      this.attrs[k] = escapeXml(unescapedAttrs[k]);
8105    });
8106  }
8107  visit(visitor) {
8108    return visitor.visitDeclaration(this);
8109  }
8110}
8111class Doctype {
8112  constructor(rootTag, dtd) {
8113    this.rootTag = rootTag;
8114    this.dtd = dtd;
8115  }
8116  visit(visitor) {
8117    return visitor.visitDoctype(this);
8118  }
8119}
8120class Tag {
8121  constructor(name, unescapedAttrs = {}, children = []) {
8122    this.name = name;
8123    this.children = children;
8124    this.attrs = {};
8125    Object.keys(unescapedAttrs).forEach(k => {
8126      this.attrs[k] = escapeXml(unescapedAttrs[k]);
8127    });
8128  }
8129  visit(visitor) {
8130    return visitor.visitTag(this);
8131  }
8132}
8133class Text$1 {
8134  constructor(unescapedValue) {
8135    this.value = escapeXml(unescapedValue);
8136  }
8137  visit(visitor) {
8138    return visitor.visitText(this);
8139  }
8140}
8141class CR extends Text$1 {
8142  constructor(ws = 0) {
8143    super(`\n${new Array(ws + 1).join(' ')}`);
8144  }
8145}
8146const _ESCAPED_CHARS = [[/&/g, '&amp;'], [/"/g, '&quot;'], [/'/g, '&apos;'], [/</g, '&lt;'], [/>/g, '&gt;']];
8147// Escape `_ESCAPED_CHARS` characters in the given text with encoded entities
8148function escapeXml(text) {
8149  return _ESCAPED_CHARS.reduce((text, entry) => text.replace(entry[0], entry[1]), text);
8150}
8151const _MESSAGES_TAG = 'messagebundle';
8152const _MESSAGE_TAG = 'msg';
8153const _PLACEHOLDER_TAG$3 = 'ph';
8154const _EXAMPLE_TAG = 'ex';
8155const _SOURCE_TAG$2 = 'source';
8156const _DOCTYPE = `<!ELEMENT messagebundle (msg)*>
8157<!ATTLIST messagebundle class CDATA #IMPLIED>
8158
8159<!ELEMENT msg (#PCDATA|ph|source)*>
8160<!ATTLIST msg id CDATA #IMPLIED>
8161<!ATTLIST msg seq CDATA #IMPLIED>
8162<!ATTLIST msg name CDATA #IMPLIED>
8163<!ATTLIST msg desc CDATA #IMPLIED>
8164<!ATTLIST msg meaning CDATA #IMPLIED>
8165<!ATTLIST msg obsolete (obsolete) #IMPLIED>
8166<!ATTLIST msg xml:space (default|preserve) "default">
8167<!ATTLIST msg is_hidden CDATA #IMPLIED>
8168
8169<!ELEMENT source (#PCDATA)>
8170
8171<!ELEMENT ph (#PCDATA|ex)*>
8172<!ATTLIST ph name CDATA #REQUIRED>
8173
8174<!ELEMENT ex (#PCDATA)>`;
8175class Xmb extends Serializer {
8176  write(messages, locale) {
8177    const exampleVisitor = new ExampleVisitor();
8178    const visitor = new _Visitor$1();
8179    let rootNode = new Tag(_MESSAGES_TAG);
8180    messages.forEach(message => {
8181      const attrs = {
8182        id: message.id
8183      };
8184      if (message.description) {
8185        attrs['desc'] = message.description;
8186      }
8187      if (message.meaning) {
8188        attrs['meaning'] = message.meaning;
8189      }
8190      let sourceTags = [];
8191      message.sources.forEach(source => {
8192        sourceTags.push(new Tag(_SOURCE_TAG$2, {}, [new Text$1(`${source.filePath}:${source.startLine}${source.endLine !== source.startLine ? ',' + source.endLine : ''}`)]));
8193      });
8194      rootNode.children.push(new CR(2), new Tag(_MESSAGE_TAG, attrs, [...sourceTags, ...visitor.serialize(message.nodes)]));
8195    });
8196    rootNode.children.push(new CR());
8197    return serialize([new Declaration({
8198      version: '1.0',
8199      encoding: 'UTF-8'
8200    }), new CR(), new Doctype(_MESSAGES_TAG, _DOCTYPE), new CR(), exampleVisitor.addDefaultExamples(rootNode), new CR()]);
8201  }
8202  load(content, url) {
8203    throw new Error('Unsupported');
8204  }
8205  digest(message) {
8206    return digest(message);
8207  }
8208  createNameMapper(message) {
8209    return new SimplePlaceholderMapper(message, toPublicName);
8210  }
8211}
8212class _Visitor$1 {
8213  visitText(text, context) {
8214    return [new Text$1(text.value)];
8215  }
8216  visitContainer(container, context) {
8217    const nodes = [];
8218    container.children.forEach(node => nodes.push(...node.visit(this)));
8219    return nodes;
8220  }
8221  visitIcu(icu, context) {
8222    const nodes = [new Text$1(`{${icu.expressionPlaceholder}, ${icu.type}, `)];
8223    Object.keys(icu.cases).forEach(c => {
8224      nodes.push(new Text$1(`${c} {`), ...icu.cases[c].visit(this), new Text$1(`} `));
8225    });
8226    nodes.push(new Text$1(`}`));
8227    return nodes;
8228  }
8229  visitTagPlaceholder(ph, context) {
8230    const startTagAsText = new Text$1(`<${ph.tag}>`);
8231    const startEx = new Tag(_EXAMPLE_TAG, {}, [startTagAsText]);
8232    // TC requires PH to have a non empty EX, and uses the text node to show the "original" value.
8233    const startTagPh = new Tag(_PLACEHOLDER_TAG$3, {
8234      name: ph.startName
8235    }, [startEx, startTagAsText]);
8236    if (ph.isVoid) {
8237      // void tags have no children nor closing tags
8238      return [startTagPh];
8239    }
8240    const closeTagAsText = new Text$1(`</${ph.tag}>`);
8241    const closeEx = new Tag(_EXAMPLE_TAG, {}, [closeTagAsText]);
8242    // TC requires PH to have a non empty EX, and uses the text node to show the "original" value.
8243    const closeTagPh = new Tag(_PLACEHOLDER_TAG$3, {
8244      name: ph.closeName
8245    }, [closeEx, closeTagAsText]);
8246    return [startTagPh, ...this.serialize(ph.children), closeTagPh];
8247  }
8248  visitPlaceholder(ph, context) {
8249    const interpolationAsText = new Text$1(`{{${ph.value}}}`);
8250    // Example tag needs to be not-empty for TC.
8251    const exTag = new Tag(_EXAMPLE_TAG, {}, [interpolationAsText]);
8252    return [
8253    // TC requires PH to have a non empty EX, and uses the text node to show the "original" value.
8254    new Tag(_PLACEHOLDER_TAG$3, {
8255      name: ph.name
8256    }, [exTag, interpolationAsText])];
8257  }
8258  visitBlockPlaceholder(ph, context) {
8259    const startAsText = new Text$1(`@${ph.name}`);
8260    const startEx = new Tag(_EXAMPLE_TAG, {}, [startAsText]);
8261    // TC requires PH to have a non empty EX, and uses the text node to show the "original" value.
8262    const startTagPh = new Tag(_PLACEHOLDER_TAG$3, {
8263      name: ph.startName
8264    }, [startEx, startAsText]);
8265    const closeAsText = new Text$1(`}`);
8266    const closeEx = new Tag(_EXAMPLE_TAG, {}, [closeAsText]);
8267    // TC requires PH to have a non empty EX, and uses the text node to show the "original" value.
8268    const closeTagPh = new Tag(_PLACEHOLDER_TAG$3, {
8269      name: ph.closeName
8270    }, [closeEx, closeAsText]);
8271    return [startTagPh, ...this.serialize(ph.children), closeTagPh];
8272  }
8273  visitIcuPlaceholder(ph, context) {
8274    const icuExpression = ph.value.expression;
8275    const icuType = ph.value.type;
8276    const icuCases = Object.keys(ph.value.cases).map(value => value + ' {...}').join(' ');
8277    const icuAsText = new Text$1(`{${icuExpression}, ${icuType}, ${icuCases}}`);
8278    const exTag = new Tag(_EXAMPLE_TAG, {}, [icuAsText]);
8279    return [
8280    // TC requires PH to have a non empty EX, and uses the text node to show the "original" value.
8281    new Tag(_PLACEHOLDER_TAG$3, {
8282      name: ph.name
8283    }, [exTag, icuAsText])];
8284  }
8285  serialize(nodes) {
8286    return [].concat(...nodes.map(node => node.visit(this)));
8287  }
8288}
8289function digest(message) {
8290  return decimalDigest(message);
8291}
8292// TC requires at least one non-empty example on placeholders
8293class ExampleVisitor {
8294  addDefaultExamples(node) {
8295    node.visit(this);
8296    return node;
8297  }
8298  visitTag(tag) {
8299    if (tag.name === _PLACEHOLDER_TAG$3) {
8300      if (!tag.children || tag.children.length == 0) {
8301        const exText = new Text$1(tag.attrs['name'] || '...');
8302        tag.children = [new Tag(_EXAMPLE_TAG, {}, [exText])];
8303      }
8304    } else if (tag.children) {
8305      tag.children.forEach(node => node.visit(this));
8306    }
8307  }
8308  visitText(text) {}
8309  visitDeclaration(decl) {}
8310  visitDoctype(doctype) {}
8311}
8312// XMB/XTB placeholders can only contain A-Z, 0-9 and _
8313function toPublicName(internalName) {
8314  return internalName.toUpperCase().replace(/[^A-Z0-9_]/g, '_');
8315}
8316
8317/* Closure variables holding messages must be named `MSG_[A-Z0-9]+` */
8318const CLOSURE_TRANSLATION_VAR_PREFIX = 'MSG_';
8319/**
8320 * Prefix for non-`goog.getMsg` i18n-related vars.
8321 * Note: the prefix uses lowercase characters intentionally due to a Closure behavior that
8322 * considers variables like `I18N_0` as constants and throws an error when their value changes.
8323 */
8324const TRANSLATION_VAR_PREFIX$1 = 'i18n_';
8325/** Name of the i18n attributes **/
8326const I18N_ATTR = 'i18n';
8327const I18N_ATTR_PREFIX = 'i18n-';
8328/** Prefix of var expressions used in ICUs */
8329const I18N_ICU_VAR_PREFIX = 'VAR_';
8330/** Prefix of ICU expressions for post processing */
8331const I18N_ICU_MAPPING_PREFIX$1 = 'I18N_EXP_';
8332/** Placeholder wrapper for i18n expressions **/
8333const I18N_PLACEHOLDER_SYMBOL = '�';
8334function isI18nAttribute(name) {
8335  return name === I18N_ATTR || name.startsWith(I18N_ATTR_PREFIX);
8336}
8337function isI18nRootNode(meta) {
8338  return meta instanceof Message;
8339}
8340function isSingleI18nIcu(meta) {
8341  return isI18nRootNode(meta) && meta.nodes.length === 1 && meta.nodes[0] instanceof Icu;
8342}
8343function hasI18nMeta(node) {
8344  return !!node.i18n;
8345}
8346function hasI18nAttrs(element) {
8347  return element.attrs.some(attr => isI18nAttribute(attr.name));
8348}
8349function icuFromI18nMessage(message) {
8350  return message.nodes[0];
8351}
8352function wrapI18nPlaceholder(content, contextId = 0) {
8353  const blockId = contextId > 0 ? `:${contextId}` : '';
8354  return `${I18N_PLACEHOLDER_SYMBOL}${content}${blockId}${I18N_PLACEHOLDER_SYMBOL}`;
8355}
8356function assembleI18nBoundString(strings, bindingStartIndex = 0, contextId = 0) {
8357  if (!strings.length) return '';
8358  let acc = '';
8359  const lastIdx = strings.length - 1;
8360  for (let i = 0; i < lastIdx; i++) {
8361    acc += `${strings[i]}${wrapI18nPlaceholder(bindingStartIndex + i, contextId)}`;
8362  }
8363  acc += strings[lastIdx];
8364  return acc;
8365}
8366function getSeqNumberGenerator(startsAt = 0) {
8367  let current = startsAt;
8368  return () => current++;
8369}
8370function placeholdersToParams(placeholders) {
8371  const params = {};
8372  placeholders.forEach((values, key) => {
8373    params[key] = literal(values.length > 1 ? `[${values.join('|')}]` : values[0]);
8374  });
8375  return params;
8376}
8377function updatePlaceholderMap(map, name, ...values) {
8378  const current = map.get(name) || [];
8379  current.push(...values);
8380  map.set(name, current);
8381}
8382function assembleBoundTextPlaceholders(meta, bindingStartIndex = 0, contextId = 0) {
8383  const startIdx = bindingStartIndex;
8384  const placeholders = new Map();
8385  const node = meta instanceof Message ? meta.nodes.find(node => node instanceof Container) : meta;
8386  if (node) {
8387    node.children.filter(child => child instanceof Placeholder).forEach((child, idx) => {
8388      const content = wrapI18nPlaceholder(startIdx + idx, contextId);
8389      updatePlaceholderMap(placeholders, child.name, content);
8390    });
8391  }
8392  return placeholders;
8393}
8394/**
8395 * Format the placeholder names in a map of placeholders to expressions.
8396 *
8397 * The placeholder names are converted from "internal" format (e.g. `START_TAG_DIV_1`) to "external"
8398 * format (e.g. `startTagDiv_1`).
8399 *
8400 * @param params A map of placeholder names to expressions.
8401 * @param useCamelCase whether to camelCase the placeholder name when formatting.
8402 * @returns A new map of formatted placeholder names to expressions.
8403 */
8404function formatI18nPlaceholderNamesInMap(params = {}, useCamelCase) {
8405  const _params = {};
8406  if (params && Object.keys(params).length) {
8407    Object.keys(params).forEach(key => _params[formatI18nPlaceholderName(key, useCamelCase)] = params[key]);
8408  }
8409  return _params;
8410}
8411/**
8412 * Converts internal placeholder names to public-facing format
8413 * (for example to use in goog.getMsg call).
8414 * Example: `START_TAG_DIV_1` is converted to `startTagDiv_1`.
8415 *
8416 * @param name The placeholder name that should be formatted
8417 * @returns Formatted placeholder name
8418 */
8419function formatI18nPlaceholderName(name, useCamelCase = true) {
8420  const publicName = toPublicName(name);
8421  if (!useCamelCase) {
8422    return publicName;
8423  }
8424  const chunks = publicName.split('_');
8425  if (chunks.length === 1) {
8426    // if no "_" found - just lowercase the value
8427    return name.toLowerCase();
8428  }
8429  let postfix;
8430  // eject last element if it's a number
8431  if (/^\d+$/.test(chunks[chunks.length - 1])) {
8432    postfix = chunks.pop();
8433  }
8434  let raw = chunks.shift().toLowerCase();
8435  if (chunks.length) {
8436    raw += chunks.map(c => c.charAt(0).toUpperCase() + c.slice(1).toLowerCase()).join('');
8437  }
8438  return postfix ? `${raw}_${postfix}` : raw;
8439}
8440/**
8441 * Generates a prefix for translation const name.
8442 *
8443 * @param extra Additional local prefix that should be injected into translation var name
8444 * @returns Complete translation const prefix
8445 */
8446function getTranslationConstPrefix(extra) {
8447  return `${CLOSURE_TRANSLATION_VAR_PREFIX}${extra}`.toUpperCase();
8448}
8449/**
8450 * Generate AST to declare a variable. E.g. `var I18N_1;`.
8451 * @param variable the name of the variable to declare.
8452 */
8453function declareI18nVariable(variable) {
8454  return new DeclareVarStmt(variable.name, undefined, INFERRED_TYPE, undefined, variable.sourceSpan);
8455}
8456
8457/**
8458 * Checks whether an object key contains potentially unsafe chars, thus the key should be wrapped in
8459 * quotes. Note: we do not wrap all keys into quotes, as it may have impact on minification and may
8460 * not work in some cases when object keys are mangled by a minifier.
8461 *
8462 * TODO(FW-1136): this is a temporary solution, we need to come up with a better way of working with
8463 * inputs that contain potentially unsafe chars.
8464 */
8465const UNSAFE_OBJECT_KEY_NAME_REGEXP = /[-.]/;
8466/** Name of the temporary to use during data binding */
8467const TEMPORARY_NAME = '_t';
8468/** Name of the context parameter passed into a template function */
8469const CONTEXT_NAME = 'ctx';
8470/** Name of the RenderFlag passed into a template function */
8471const RENDER_FLAGS = 'rf';
8472/** The prefix reference variables */
8473const REFERENCE_PREFIX = '_r';
8474/** The name of the implicit context reference */
8475const IMPLICIT_REFERENCE = '$implicit';
8476/** Non bindable attribute name **/
8477const NON_BINDABLE_ATTR = 'ngNonBindable';
8478/** Name for the variable keeping track of the context returned by `ɵɵrestoreView`. */
8479const RESTORED_VIEW_CONTEXT_NAME = 'restoredCtx';
8480/** Special value representing a direct access to a template's context. */
8481const DIRECT_CONTEXT_REFERENCE = '#context';
8482/**
8483 * Maximum length of a single instruction chain. Because our output AST uses recursion, we're
8484 * limited in how many expressions we can nest before we reach the call stack limit. This
8485 * length is set very conservatively in order to reduce the chance of problems.
8486 */
8487const MAX_CHAIN_LENGTH = 500;
8488/** Instructions that support chaining. */
8489const CHAINABLE_INSTRUCTIONS = new Set([Identifiers.element, Identifiers.elementStart, Identifiers.elementEnd, Identifiers.elementContainer, Identifiers.elementContainerStart, Identifiers.elementContainerEnd, Identifiers.i18nExp, Identifiers.listener, Identifiers.classProp, Identifiers.syntheticHostListener, Identifiers.hostProperty, Identifiers.syntheticHostProperty, Identifiers.property, Identifiers.propertyInterpolate1, Identifiers.propertyInterpolate2, Identifiers.propertyInterpolate3, Identifiers.propertyInterpolate4, Identifiers.propertyInterpolate5, Identifiers.propertyInterpolate6, Identifiers.propertyInterpolate7, Identifiers.propertyInterpolate8, Identifiers.propertyInterpolateV, Identifiers.attribute, Identifiers.attributeInterpolate1, Identifiers.attributeInterpolate2, Identifiers.attributeInterpolate3, Identifiers.attributeInterpolate4, Identifiers.attributeInterpolate5, Identifiers.attributeInterpolate6, Identifiers.attributeInterpolate7, Identifiers.attributeInterpolate8, Identifiers.attributeInterpolateV, Identifiers.styleProp, Identifiers.stylePropInterpolate1, Identifiers.stylePropInterpolate2, Identifiers.stylePropInterpolate3, Identifiers.stylePropInterpolate4, Identifiers.stylePropInterpolate5, Identifiers.stylePropInterpolate6, Identifiers.stylePropInterpolate7, Identifiers.stylePropInterpolate8, Identifiers.stylePropInterpolateV, Identifiers.textInterpolate, Identifiers.textInterpolate1, Identifiers.textInterpolate2, Identifiers.textInterpolate3, Identifiers.textInterpolate4, Identifiers.textInterpolate5, Identifiers.textInterpolate6, Identifiers.textInterpolate7, Identifiers.textInterpolate8, Identifiers.textInterpolateV, Identifiers.templateCreate, Identifiers.twoWayProperty, Identifiers.twoWayListener]);
8490/** Generates a call to a single instruction. */
8491function invokeInstruction(span, reference, params) {
8492  return importExpr(reference, null, span).callFn(params, span);
8493}
8494/**
8495 * Creates an allocator for a temporary variable.
8496 *
8497 * A variable declaration is added to the statements the first time the allocator is invoked.
8498 */
8499function temporaryAllocator(pushStatement, name) {
8500  let temp = null;
8501  return () => {
8502    if (!temp) {
8503      pushStatement(new DeclareVarStmt(TEMPORARY_NAME, undefined, DYNAMIC_TYPE));
8504      temp = variable(name);
8505    }
8506    return temp;
8507  };
8508}
8509function invalid(arg) {
8510  throw new Error(`Invalid state: Visitor ${this.constructor.name} doesn't handle ${arg.constructor.name}`);
8511}
8512function asLiteral(value) {
8513  if (Array.isArray(value)) {
8514    return literalArr(value.map(asLiteral));
8515  }
8516  return literal(value, INFERRED_TYPE);
8517}
8518/**
8519 * Serializes inputs and outputs for `defineDirective` and `defineComponent`.
8520 *
8521 * This will attempt to generate optimized data structures to minimize memory or
8522 * file size of fully compiled applications.
8523 */
8524function conditionallyCreateDirectiveBindingLiteral(map, forInputs) {
8525  const keys = Object.getOwnPropertyNames(map);
8526  if (keys.length === 0) {
8527    return null;
8528  }
8529  return literalMap(keys.map(key => {
8530    const value = map[key];
8531    let declaredName;
8532    let publicName;
8533    let minifiedName;
8534    let expressionValue;
8535    if (typeof value === 'string') {
8536      // canonical syntax: `dirProp: publicProp`
8537      declaredName = key;
8538      minifiedName = key;
8539      publicName = value;
8540      expressionValue = asLiteral(publicName);
8541    } else {
8542      minifiedName = key;
8543      declaredName = value.classPropertyName;
8544      publicName = value.bindingPropertyName;
8545      const differentDeclaringName = publicName !== declaredName;
8546      const hasDecoratorInputTransform = value.transformFunction !== null;
8547      // Build up input flags
8548      let flags = null;
8549      if (value.isSignal) {
8550        flags = bitwiseOrInputFlagsExpr(InputFlags.SignalBased, flags);
8551      }
8552      if (hasDecoratorInputTransform) {
8553        flags = bitwiseOrInputFlagsExpr(InputFlags.HasDecoratorInputTransform, flags);
8554      }
8555      // Inputs, compared to outputs, will track their declared name (for `ngOnChanges`), support
8556      // decorator input transform functions, or store flag information if there is any.
8557      if (forInputs && (differentDeclaringName || hasDecoratorInputTransform || flags !== null)) {
8558        const flagsExpr = flags ?? importExpr(Identifiers.InputFlags).prop(InputFlags[InputFlags.None]);
8559        const result = [flagsExpr, asLiteral(publicName)];
8560        if (differentDeclaringName || hasDecoratorInputTransform) {
8561          result.push(asLiteral(declaredName));
8562          if (hasDecoratorInputTransform) {
8563            result.push(value.transformFunction);
8564          }
8565        }
8566        expressionValue = literalArr(result);
8567      } else {
8568        expressionValue = asLiteral(publicName);
8569      }
8570    }
8571    return {
8572      key: minifiedName,
8573      // put quotes around keys that contain potentially unsafe characters
8574      quoted: UNSAFE_OBJECT_KEY_NAME_REGEXP.test(minifiedName),
8575      value: expressionValue
8576    };
8577  }));
8578}
8579/** Gets an output AST expression referencing the given flag. */
8580function getInputFlagExpr(flag) {
8581  return importExpr(Identifiers.InputFlags).prop(InputFlags[flag]);
8582}
8583/** Combines a given input flag with an existing flag expression, if present. */
8584function bitwiseOrInputFlagsExpr(flag, expr) {
8585  if (expr === null) {
8586    return getInputFlagExpr(flag);
8587  }
8588  return getInputFlagExpr(flag).bitwiseOr(expr);
8589}
8590/**
8591 *  Remove trailing null nodes as they are implied.
8592 */
8593function trimTrailingNulls(parameters) {
8594  while (isNull(parameters[parameters.length - 1])) {
8595    parameters.pop();
8596  }
8597  return parameters;
8598}
8599/**
8600 * A representation for an object literal used during codegen of definition objects. The generic
8601 * type `T` allows to reference a documented type of the generated structure, such that the
8602 * property names that are set can be resolved to their documented declaration.
8603 */
8604class DefinitionMap {
8605  constructor() {
8606    this.values = [];
8607  }
8608  set(key, value) {
8609    if (value) {
8610      const existing = this.values.find(value => value.key === key);
8611      if (existing) {
8612        existing.value = value;
8613      } else {
8614        this.values.push({
8615          key: key,
8616          value,
8617          quoted: false
8618        });
8619      }
8620    }
8621  }
8622  toLiteralMap() {
8623    return literalMap(this.values);
8624  }
8625}
8626/**
8627 * Creates a `CssSelector` from an AST node.
8628 */
8629function createCssSelectorFromNode(node) {
8630  const elementName = node instanceof Element$1 ? node.name : 'ng-template';
8631  const attributes = getAttrsForDirectiveMatching(node);
8632  const cssSelector = new CssSelector();
8633  const elementNameNoNs = splitNsName(elementName)[1];
8634  cssSelector.setElement(elementNameNoNs);
8635  Object.getOwnPropertyNames(attributes).forEach(name => {
8636    const nameNoNs = splitNsName(name)[1];
8637    const value = attributes[name];
8638    cssSelector.addAttribute(nameNoNs, value);
8639    if (name.toLowerCase() === 'class') {
8640      const classes = value.trim().split(/\s+/);
8641      classes.forEach(className => cssSelector.addClassName(className));
8642    }
8643  });
8644  return cssSelector;
8645}
8646/**
8647 * Extract a map of properties to values for a given element or template node, which can be used
8648 * by the directive matching machinery.
8649 *
8650 * @param elOrTpl the element or template in question
8651 * @return an object set up for directive matching. For attributes on the element/template, this
8652 * object maps a property name to its (static) value. For any bindings, this map simply maps the
8653 * property name to an empty string.
8654 */
8655function getAttrsForDirectiveMatching(elOrTpl) {
8656  const attributesMap = {};
8657  if (elOrTpl instanceof Template && elOrTpl.tagName !== 'ng-template') {
8658    elOrTpl.templateAttrs.forEach(a => attributesMap[a.name] = '');
8659  } else {
8660    elOrTpl.attributes.forEach(a => {
8661      if (!isI18nAttribute(a.name)) {
8662        attributesMap[a.name] = a.value;
8663      }
8664    });
8665    elOrTpl.inputs.forEach(i => {
8666      if (i.type === 0 /* BindingType.Property */ || i.type === 5 /* BindingType.TwoWay */) {
8667        attributesMap[i.name] = '';
8668      }
8669    });
8670    elOrTpl.outputs.forEach(o => {
8671      attributesMap[o.name] = '';
8672    });
8673  }
8674  return attributesMap;
8675}
8676/**
8677 * Gets the number of arguments expected to be passed to a generated instruction in the case of
8678 * interpolation instructions.
8679 * @param interpolation An interpolation ast
8680 */
8681function getInterpolationArgsLength(interpolation) {
8682  const {
8683    expressions,
8684    strings
8685  } = interpolation;
8686  if (expressions.length === 1 && strings.length === 2 && strings[0] === '' && strings[1] === '') {
8687    // If the interpolation has one interpolated value, but the prefix and suffix are both empty
8688    // strings, we only pass one argument, to a special instruction like `propertyInterpolate` or
8689    // `textInterpolate`.
8690    return 1;
8691  } else {
8692    return expressions.length + strings.length;
8693  }
8694}
8695/**
8696 * Generates the final instruction call statements based on the passed in configuration.
8697 * Will try to chain instructions as much as possible, if chaining is supported.
8698 */
8699function getInstructionStatements(instructions) {
8700  const statements = [];
8701  let pendingExpression = null;
8702  let pendingExpressionType = null;
8703  let chainLength = 0;
8704  for (const current of instructions) {
8705    const resolvedParams = (typeof current.paramsOrFn === 'function' ? current.paramsOrFn() : current.paramsOrFn) ?? [];
8706    const params = Array.isArray(resolvedParams) ? resolvedParams : [resolvedParams];
8707    // If the current instruction is the same as the previous one
8708    // and it can be chained, add another call to the chain.
8709    if (chainLength < MAX_CHAIN_LENGTH && pendingExpressionType === current.reference && CHAINABLE_INSTRUCTIONS.has(pendingExpressionType)) {
8710      // We'll always have a pending expression when there's a pending expression type.
8711      pendingExpression = pendingExpression.callFn(params, pendingExpression.sourceSpan);
8712      chainLength++;
8713    } else {
8714      if (pendingExpression !== null) {
8715        statements.push(pendingExpression.toStmt());
8716      }
8717      pendingExpression = invokeInstruction(current.span, current.reference, params);
8718      pendingExpressionType = current.reference;
8719      chainLength = 0;
8720    }
8721  }
8722  // Since the current instruction adds the previous one to the statements,
8723  // we may be left with the final one at the end that is still pending.
8724  if (pendingExpression !== null) {
8725    statements.push(pendingExpression.toStmt());
8726  }
8727  return statements;
8728}
8729function compileInjectable(meta, resolveForwardRefs) {
8730  let result = null;
8731  const factoryMeta = {
8732    name: meta.name,
8733    type: meta.type,
8734    typeArgumentCount: meta.typeArgumentCount,
8735    deps: [],
8736    target: FactoryTarget$1.Injectable
8737  };
8738  if (meta.useClass !== undefined) {
8739    // meta.useClass has two modes of operation. Either deps are specified, in which case `new` is
8740    // used to instantiate the class with dependencies injected, or deps are not specified and
8741    // the factory of the class is used to instantiate it.
8742    //
8743    // A special case exists for useClass: Type where Type is the injectable type itself and n
8743o
8744    // deps are specified, in which case 'useClass' is effectively ignored.
8745    const useClassOnSelf = meta.useClass.expression.isEquivalent(meta.type.value);
8746    let deps = undefined;
8747    if (meta.deps !== undefined) {
8748      deps = meta.deps;
8749    }
8750    if (deps !== undefined) {
8751      // factory: () => new meta.useClass(...deps)
8752      result = compileFactoryFunction({
8753        ...factoryMeta,
8754        delegate: meta.useClass.expression,
8755        delegateDeps: deps,
8756        delegateType: R3FactoryDelegateType.Class
8757      });
8758    } else if (useClassOnSelf) {
8759      result = compileFactoryFunction(factoryMeta);
8760    } else {
8761      result = {
8762        statements: [],
8763        expression: delegateToFactory(meta.type.value, meta.useClass.expression, resolveForwardRefs)
8764      };
8765    }
8766  } else if (meta.useFactory !== undefined) {
8767    if (meta.deps !== undefined) {
8768      result = compileFactoryFunction({
8769        ...factoryMeta,
8770        delegate: meta.useFactory,
8771        delegateDeps: meta.deps || [],
8772        delegateType: R3FactoryDelegateType.Function
8773      });
8774    } else {
8775      result = {
8776        statements: [],
8777        expression: arrowFn([], meta.useFactory.callFn([]))
8778      };
8779    }
8780  } else if (meta.useValue !== undefined) {
8781    // Note: it's safe to use `meta.useValue` instead of the `USE_VALUE in meta` check used for
8782    // client code because meta.useValue is an Expression which will be defined even if the actual
8783    // value is undefined.
8784    result = compileFactoryFunction({
8785      ...factoryMeta,
8786      expression: meta.useValue.expression
8787    });
8788  } else if (meta.useExisting !== undefined) {
8789    // useExisting is an `inject` call on the existing token.
8790    result = compileFactoryFunction({
8791      ...factoryMeta,
8792      expression: importExpr(Identifiers.inject).callFn([meta.useExisting.expression])
8793    });
8794  } else {
8795    result = {
8796      statements: [],
8797      expression: delegateToFactory(meta.type.value, meta.type.value, resolveForwardRefs)
8798    };
8799  }
8800  const token = meta.type.value;
8801  const injectableProps = new DefinitionMap();
8802  injectableProps.set('token', token);
8803  injectableProps.set('factory', result.expression);
8804  // Only generate providedIn property if it has a non-null value
8805  if (meta.providedIn.expression.value !== null) {
8806    injectableProps.set('providedIn', convertFromMaybeForwardRefExpression(meta.providedIn));
8807  }
8808  const expression = importExpr(Identifiers.ɵɵdefineInjectable).callFn([injectableProps.toLiteralMap()], undefined, true);
8809  return {
8810    expression,
8811    type: createInjectableType(meta),
8812    statements: result.statements
8813  };
8814}
8815function createInjectableType(meta) {
8816  return new ExpressionType(importExpr(Identifiers.InjectableDeclaration, [typeWithParameters(meta.type.type, meta.typeArgumentCount)]));
8817}
8818function delegateToFactory(type, useType, unwrapForwardRefs) {
8819  if (type.node === useType.node) {
8820    // The types are the same, so we can simply delegate directly to the type's factory.
8821    // ```
8822    // factory: type.ɵfac
8823    // ```
8824    return useType.prop('ɵfac');
8825  }
8826  if (!unwrapForwardRefs) {
8827    // The type is not wrapped in a `forwardRef()`, so we create a simple factory function that
8828    // accepts a sub-type as an argument.
8829    // ```
8830    // factory: function(t) { return useType.ɵfac(t); }
8831    // ```
8832    return createFactoryFunction(useType);
8833  }
8834  // The useType is actually wrapped in a `forwardRef()` so we need to resolve that before
8835  // calling its factory.
8836  // ```
8837  // factory: function(t) { return core.resolveForwardRef(type).ɵfac(t); }
8838  // ```
8839  const unwrappedType = importExpr(Identifiers.resolveForwardRef).callFn([useType]);
8840  return createFactoryFunction(unwrappedType);
8841}
8842function createFactoryFunction(type) {
8843  return arrowFn([new FnParam('t', DYNAMIC_TYPE)], type.prop('ɵfac').callFn([variable('t')]));
8844}
8845const UNUSABLE_INTERPOLATION_REGEXPS = [/^\s*$/,
8846// empty
8847/[<>]/,
8848// html tag
8849/^[{}]$/,
8850// i18n expansion
8851/&(#|[a-z])/i,
8852// character reference,
8853/^\/\// // comment
8854];
8855function assertInterpolationSymbols(identifier, value) {
8856  if (value != null && !(Array.isArray(value) && value.length == 2)) {
8857    throw new Error(`Expected '${identifier}' to be an array, [start, end].`);
8858  } else if (value != null) {
8859    const start = value[0];
8860    const end = value[1];
8861    // Check for unusable interpolation symbols
8862    UNUSABLE_INTERPOLATION_REGEXPS.forEach(regexp => {
8863      if (regexp.test(start) || regexp.test(end)) {
8864        throw new Error(`['${start}', '${end}'] contains unusable interpolation symbol.`);
8865      }
8866    });
8867  }
8868}
8869class InterpolationConfig {
8870  static fromArray(markers) {
8871    if (!markers) {
8872      return DEFAULT_INTERPOLATION_CONFIG;
8873    }
8874    assertInterpolationSymbols('interpolation', markers);
8875    return new InterpolationConfig(markers[0], markers[1]);
8876  }
8877  constructor(start, end) {
8878    this.start = start;
8879    this.end = end;
8880  }
8881}
8882const DEFAULT_INTERPOLATION_CONFIG = new InterpolationConfig('{{', '}}');
8883const DEFAULT_CONTAINER_BLOCKS = new Set(['switch']);
8884const $EOF = 0;
8885const $BSPACE = 8;
8886const $TAB = 9;
8887const $LF = 10;
8888const $VTAB = 11;
8889const $FF = 12;
8890const $CR = 13;
8891const $SPACE = 32;
8892const $BANG = 33;
8893const $DQ = 34;
8894const $HASH = 35;
8895const $$ = 36;
8896const $PERCENT = 37;
8897const $AMPERSAND = 38;
8898const $SQ = 39;
8899const $LPAREN = 40;
8900const $RPAREN = 41;
8901const $STAR = 42;
8902const $PLUS = 43;
8903const $COMMA = 44;
8904const $MINUS = 45;
8905const $PERIOD = 46;
8906const $SLASH = 47;
8907const $COLON = 58;
8908const $SEMICOLON = 59;
8909const $LT = 60;
8910const $EQ = 61;
8911const $GT = 62;
8912const $QUESTION = 63;
8913const $0 = 48;
8914const $7 = 55;
8915const $9 = 57;
8916const $A = 65;
8917const $E = 69;
8918const $F = 70;
8919const $X = 88;
8920const $Z = 90;
8921const $LBRACKET = 91;
8922const $BACKSLASH = 92;
8923const $RBRACKET = 93;
8924const $CARET = 94;
8925const $_ = 95;
8926const $a = 97;
8927const $b = 98;
8928const $e = 101;
8929const $f = 102;
8930const $n = 110;
8931const $r = 114;
8932const $t = 116;
8933const $u = 117;
8934const $v = 118;
8935const $x = 120;
8936const $z = 122;
8937const $LBRACE = 123;
8938const $BAR = 124;
8939const $RBRACE = 125;
8940const $NBSP = 160;
8941const $PIPE = 124;
8942const $TILDA = 126;
8943const $AT = 64;
8944const $BT = 96;
8945function isWhitespace(code) {
8946  return code >= $TAB && code <= $SPACE || code == $NBSP;
8947}
8948function isDigit(code) {
8949  return $0 <= code && code <= $9;
8950}
8951function isAsciiLetter(code) {
8952  return code >= $a && code <= $z || code >= $A && code <= $Z;
8953}
8954function isAsciiHexDigit(code) {
8955  return code >= $a && code <= $f || code >= $A && code <= $F || isDigit(code);
8956}
8957function isNewLine(code) {
8958  return code === $LF || code === $CR;
8959}
8960function isOctalDigit(code) {
8961  return $0 <= code && code <= $7;
8962}
8963function isQuote(code) {
8964  return code === $SQ || code === $DQ || code === $BT;
8965}
8966class ParseLocation {
8967  constructor(file, offset, line, col) {
8968    this.file = file;
8969    this.offset = offset;
8970    this.line = line;
8971    this.col = col;
8972  }
8973  toString() {
8974    return this.offset != null ? `${this.file.url}@${this.line}:${this.col}` : this.file.url;
8975  }
8976  moveBy(delta) {
8977    const source = this.file.content;
8978    const len = source.length;
8979    let offset = this.offset;
8980    let line = this.line;
8981    let col = this.col;
8982    while (offset > 0 && delta < 0) {
8983      offset--;
8984      delta++;
8985      const ch = source.charCodeAt(offset);
8986      if (ch == $LF) {
8987        line--;
8988        const priorLine = source.substring(0, offset - 1).lastIndexOf(String.fromCharCode($LF));
8989        col = priorLine > 0 ? offset - priorLine : offset;
8990      } else {
8991        col--;
8992      }
8993    }
8994    while (offset < len && delta > 0) {
8995      const ch = source.charCodeAt(offset);
8996      offset++;
8997      delta--;
8998      if (ch == $LF) {
8999        line++;
9000        col = 0;
9001      } else {
9002        col++;
9003      }
9004    }
9005    return new ParseLocation(this.file, offset, line, col);
9006  }
9007  // Return the source around the location
9008  // Up to `maxChars` or `maxLines` on each side of the location
9009  getContext(maxChars, maxLines) {
9010    const content = this.file.content;
9011    let startOffset = this.offset;
9012    if (startOffset != null) {
9013      if (startOffset > content.length - 1) {
9014        startOffset = content.length - 1;
9015      }
9016      let endOffset = startOffset;
9017      let ctxChars = 0;
9018      let ctxLines = 0;
9019      while (ctxChars < maxChars && startOffset > 0) {
9020        startOffset--;
9021        ctxChars++;
9022        if (content[startOffset] == '\n') {
9023          if (++ctxLines == maxLines) {
9024            break;
9025          }
9026        }
9027      }
9028      ctxChars = 0;
9029      ctxLines = 0;
9030      while (ctxChars < maxChars && endOffset < content.length - 1) {
9031        endOffset++;
9032        ctxChars++;
9033        if (content[endOffset] == '\n') {
9034          if (++ctxLines == maxLines) {
9035            break;
9036          }
9037        }
9038      }
9039      return {
9040        before: content.substring(startOffset, this.offset),
9041        after: content.substring(this.offset, endOffset + 1)
9042      };
9043    }
9044    return null;
9045  }
9046}
9047class ParseSourceFile {
9048  constructor(content, url) {
9049    this.content = content;
9050    this.url = url;
9051  }
9052}
9053class ParseSourceSpan {
9054  /**
9055   * Create an object that holds information about spans of tokens/nodes captured during
9056   * lexing/parsing of text.
9057   *
9058   * @param start
9059   * The location of the start of the span (having skipped leading trivia).
9060   * Skipping leading trivia makes source-spans more "user friendly", since things like HTML
9061   * elements will appear to begin at the start of the opening tag, rather than at the start of any
9062   * leading trivia, which could include newlines.
9063   *
9064   * @param end
9065   * The location of the end of the span.
9066   *
9067   * @param fullStart
9068   * The start of the token without skipping the leading trivia.
9069   * This is used by tooling that splits tokens further, such as extracting Angular interpolations
9070   * from text tokens. Such tooling creates new source-spans relative to the original token's
9071   * source-span. If leading trivia characters have been skipped then the new source-spans may be
9072   * incorrectly offset.
9073   *
9074   * @param details
9075   * Additional information (such as identifier names) that should be associated with the span.
9076   */
9077  constructor(start, end, fullStart = start, details = null) {
9078    this.start = start;
9079    this.end = end;
9080    this.fullStart = fullStart;
9081    this.details = details;
9082  }
9083  toString() {
9084    return this.start.file.content.substring(this.start.offset, this.end.offset);
9085  }
9086}
9087var ParseErrorLevel;
9088(function (ParseErrorLevel) {
9089  ParseErrorLevel[ParseErrorLevel["WARNING"] = 0] = "WARNING";
9090  ParseErrorLevel[ParseErrorLevel["ERROR"] = 1] = "ERROR";
9091})(ParseErrorLevel || (ParseErrorLevel = {}));
9092class ParseError {
9093  constructor(span, msg, level = ParseErrorLevel.ERROR) {
9094    this.span = span;
9095    this.msg = msg;
9096    this.level = level;
9097  }
9098  contextualMessage() {
9099    const ctx = this.span.start.getContext(100, 3);
9100    return ctx ? `${this.msg} ("${ctx.before}[${ParseErrorLevel[this.level]} ->]${ctx.after}")` : this.msg;
9101  }
9102  toString() {
9103    const details = this.span.details ? `, ${this.span.details}` : '';
9104    return `${this.contextualMessage()}: ${this.span.start}${details}`;
9105  }
9106}
9107/**
9108 * Generates Source Span object for a given R3 Type for JIT mode.
9109 *
9110 * @param kind Component or Directive.
9111 * @param typeName name of the Component or Directive.
9112 * @param sourceUrl reference to Component or Directive source.
9113 * @returns instance of ParseSourceSpan that represent a given Component or Directive.
9114 */
9115function r3JitTypeSourceSpan(kind, typeName, sourceUrl) {
9116  const sourceFileName = `in ${kind} ${typeName} in ${sourceUrl}`;
9117  const sourceFile = new ParseSourceFile('', sourceFileName);
9118  return new ParseSourceSpan(new ParseLocation(sourceFile, -1, -1, -1), new ParseLocation(sourceFile, -1, -1, -1));
9119}
9120let _anonymousTypeIndex = 0;
9121function identifierName(compileIdentifier) {
9122  if (!compileIdentifier || !compileIdentifier.reference) {
9123    return null;
9124  }
9125  const ref = compileIdentifier.reference;
9126  if (ref['__anonymousType']) {
9127    return ref['__anonymousType'];
9128  }
9129  if (ref['__forward_ref__']) {
9130    // We do not want to try to stringify a `forwardRef()` function because that would cause the
9131    // inner function to be evaluated too early, defeating the whole point of the `forwardRef`.
9132    return '__forward_ref__';
9133  }
9134  let identifier = stringify(ref);
9135  if (identifier.indexOf('(') >= 0) {
9136    // case: anonymous functions!
9137    identifier = `anonymous_${_anonymousTypeIndex++}`;
9138    ref['__anonymousType'] = identifier;
9139  } else {
9140    identifier = sanitizeIdentifier(identifier);
9141  }
9142  return identifier;
9143}
9144function sanitizeIdentifier(name) {
9145  return name.replace(/\W/g, '_');
9146}
9147
9148/**
9149 * In TypeScript, tagged template functions expect a "template object", which is an array of
9150 * "cooked" strings plus a `raw` property that contains an array of "raw" strings. This is
9151 * typically constructed with a function called `__makeTemplateObject(cooked, raw)`, but it may not
9152 * be available in all environments.
9153 *
9154 * This is a JavaScript polyfill that uses __makeTemplateObject when it's available, but otherwise
9155 * creates an inline helper with the same functionality.
9156 *
9157 * In the inline function, if `Object.defineProperty` is available we use that to attach the `raw`
9158 * array.
9159 */
9160const makeTemplateObjectPolyfill = '(this&&this.__makeTemplateObject||function(e,t){return Object.defineProperty?Object.defineProperty(e,"raw",{value:t}):e.raw=t,e})';
9161class AbstractJsEmitterVisitor extends AbstractEmitterVisitor {
9162  constructor() {
9163    super(false);
9164  }
9165  visitWrappedNodeExpr(ast, ctx) {
9166    throw new Error('Cannot emit a WrappedNodeExpr in Javascript.');
9167  }
9168  visitDeclareVarStmt(stmt, ctx) {
9169    ctx.print(stmt, `var ${stmt.name}`);
9170    if (stmt.value) {
9171      ctx.print(stmt, ' = ');
9172      stmt.value.visitExpression(this, ctx);
9173    }
9174    ctx.println(stmt, `;`);
9175    return null;
9176  }
9177  visitTaggedTemplateExpr(ast, ctx) {
9178    // The following convoluted piece of code is effectively the downlevelled equivalent of
9179    // ```
9180    // tag`...`
9181    // ```
9182    // which is effectively like:
9183    // ```
9184    // tag(__makeTemplateObject(cooked, raw), expression1, expression2, ...);
9185    // ```
9186    const elements = ast.template.elements;
9187    ast.tag.visitExpression(this, ctx);
9188    ctx.print(ast, `(${makeTemplateObjectPolyfill}(`);
9189    ctx.print(ast, `[${elements.map(part => escapeIdentifier(part.text, false)).join(', ')}], `);
9190    ctx.print(ast, `[${elements.map(part => escapeIdentifier(part.rawText, false)).join(', ')}])`);
9191    ast.template.expressions.forEach(expression => {
9192      ctx.print(ast, ', ');
9193      expression.visitExpression(this, ctx);
9194    });
9195    ctx.print(ast, ')');
9196    return null;
9197  }
9198  visitFunctionExpr(ast, ctx) {
9199    ctx.print(ast, `function${ast.name ? ' ' + ast.name : ''}(`);
9200    this._visitParams(ast.params, ctx);
9201    ctx.println(ast, `) {`);
9202    ctx.incIndent();
9203    this.visitAllStatements(ast.statements, ctx);
9204    ctx.decIndent();
9205    ctx.print(ast, `}`);
9206    return null;
9207  }
9208  visitArrowFunctionExpr(ast, ctx) {
9209    ctx.print(ast, '(');
9210    this._visitParams(ast.params, ctx);
9211    ctx.print(ast, ') =>');
9212    if (Array.isArray(ast.body)) {
9213      ctx.println(ast, `{`);
9214      ctx.incIndent();
9215      this.visitAllStatements(ast.body, ctx);
9216      ctx.decIndent();
9217      ctx.print(ast, `}`);
9218    } else {
9219      const isObjectLiteral = ast.body instanceof LiteralMapExpr;
9220      if (isObjectLiteral) {
9221        ctx.print(ast, '(');
9222      }
9223      ast.body.visitExpression(this, ctx);
9224      if (isObjectLiteral) {
9225        ctx.print(ast, ')');
9226      }
9227    }
9228    return null;
9229  }
9230  visitDeclareFunctionStmt(stmt, ctx) {
9231    ctx.print(stmt, `function ${stmt.name}(`);
9232    this._visitParams(stmt.params, ctx);
9233    ctx.println(stmt, `) {`);
9234    ctx.incIndent();
9235    this.visitAllStatements(stmt.statements, ctx);
9236    ctx.decIndent();
9237    ctx.println(stmt, `}`);
9238    return null;
9239  }
9240  visitLocalizedString(ast, ctx) {
9241    // The following convoluted piece of code is effectively the downlevelled equivalent of
9242    // ```
9243    // $localize `...`
9244    // ```
9245    // which is effectively like:
9246    // ```
9247    // $localize(__makeTemplateObject(cooked, raw), expression1, expression2, ...);
9248    // ```
9249    ctx.print(ast, `$localize(${makeTemplateObjectPolyfill}(`);
9250    const parts = [ast.serializeI18nHead()];
9251    for (let i = 1; i < ast.messageParts.length; i++) {
9252      parts.push(ast.serializeI18nTemplatePart(i));
9253    }
9254    ctx.print(ast, `[${parts.map(part => escapeIdentifier(part.cooked, false)).join(', ')}], `);
9255    ctx.print(ast, `[${parts.map(part => escapeIdentifier(part.raw, false)).join(', ')}])`);
9256    ast.expressions.forEach(expression => {
9257      ctx.print(ast, ', ');
9258      expression.visitExpression(this, ctx);
9259    });
9260    ctx.print(ast, ')');
9261    return null;
9262  }
9263  _visitParams(params, ctx) {
9264    this.visitAllObjects(param => ctx.print(null, param.name), params, ctx, ',');
9265  }
9266}
9267
9268/**
9269 * @fileoverview
9270 * A module to facilitate use of a Trusted Types policy within the JIT
9271 * compiler. It lazily constructs the Trusted Types policy, providing helper
9272 * utilities for promoting strings to Trusted Types. When Trusted Types are not
9273 * available, strings are used as a fallback.
9274 * @security All use of this module is security-sensitive and should go through
9275 * security review.
9276 */
9277/**
9278 * The Trusted Types policy, or null if Trusted Types are not
9279 * enabled/supported, or undefined if the policy has not been created yet.
9280 */
9281let policy;
9282/**
9283 * Returns the Trusted Types policy, or null if Trusted Types are not
9284 * enabled/supported. The first call to this function will create the policy.
9285 */
9286function getPolicy() {
9287  if (policy === undefined) {
9288    const trustedTypes = _global['trustedTypes'];
9289    policy = null;
9290    if (trustedTypes) {
9291      try {
9292        policy = trustedTypes.createPolicy('angular#unsafe-jit', {
9293          createScript: s => s
9294        });
9295      } catch {
9296        // trustedTypes.createPolicy throws if called with a name that is
9297        // already registered, even in report-only mode. Until the API changes,
9298        // catch the error not to break the applications functionally. In such
9299        // cases, the code will fall back to using strings.
9300      }
9301    }
9302  }
9303  return policy;
9304}
9305/**
9306 * Unsafely promote a string to a TrustedScript, falling back to strings when
9307 * Trusted Types are not available.
9308 * @security In particular, it must be assured that the provided string will
9309 * never cause an XSS vulnerability if used in a context that will be
9310 * interpreted and executed as a script by a browser, e.g. when calling eval.
9311 */
9312function trustedScriptFromString(script) {
9313  return getPolicy()?.createScript(script) || script;
9314}
9315/**
9316 * Unsafely call the Function constructor with the given string arguments.
9317 * @security This is a security-sensitive function; any use of this function
9318 * must go through security review. In particular, it must be assured that it
9319 * is only called from the JIT compiler, as use in other code can lead to XSS
9320 * vulnerabilities.
9321 */
9322function newTrustedFunctionForJIT(...args) {
9323  if (!_global['trustedTypes']) {
9324    // In environments that don't support Trusted Types, fall back to the most
9325    // straightforward implementation:
9326    return new Function(...args);
9327  }
9328  // Chrome currently does not support passing TrustedScript to the Function
9329  // constructor. The following implements the workaround proposed on the page
9330  // below, where the Chromium bug is also referenced:
9331  // https://github.com/w3c/webappsec-trusted-types/wiki/Trusted-Types-for-function-constructor
9332  const fnArgs = args.slice(0, -1).join(',');
9333  const fnBody = args[args.length - 1];
9334  const body = `(function anonymous(${fnArgs}
9335) { ${fnBody}
9336})`;
9337  // Using eval directly confuses the compiler and prevents this module from
9338  // being stripped out of JS binaries even if not used. The global['eval']
9339  // indirection fixes that.
9340  const fn = _global['eval'](trustedScriptFromString(body));
9341  if (fn.bind === undefined) {
9342    // Workaround for a browser bug that only exists in Chrome 83, where passing
9343    // a TrustedScript to eval just returns the TrustedScript back without
9344    // evaluating it. In that case, fall back to the most straightforward
9345    // implementation:
9346    return new Function(...args);
9347  }
9348  // To completely mimic the behavior of calling "new Function", two more
9349  // things need to happen:
9350  // 1. Stringifying the resulting function should return its source code
9351  fn.toString = () => body;
9352  // 2. When calling the resulting function, `this` should refer to `global`
9353  return fn.bind(_global);
9354  // When Trusted Types support in Function constructors is widely available,
9355  // the implementation of this function can be simplified to:
9356  // return new Function(...args.map(a => trustedScriptFromString(a)));
9357}
9358
9359/**
9360 * A helper class to manage the evaluation of JIT generated code.
9361 */
9362class JitEvaluator {
9363  /**
9364   *
9365   * @param sourceUrl The URL of the generated code.
9366   * @param statements An array of Angular statement AST nodes to be evaluated.
9367   * @param refResolver Resolves `o.ExternalReference`s into values.
9368   * @param createSourceMaps If true then create a source-map for the generated code and include it
9369   * inline as a source-map comment.
9370   * @returns A map of all the variables in the generated code.
9371   */
9372  evaluateStatements(sourceUrl, statements, refResolver, createSourceMaps) {
9373    const converter = new JitEmitterVisitor(refResolver);
9374    const ctx = EmitterVisitorContext.createRoot();
9375    // Ensure generated code is in strict mode
9376    if (statements.length >
9376 0 && !isUseStrictStatement(statements[0])) {
9377      statements = [literal('use strict').toStmt(), ...statements];
9378    }
9379    converter.visitAllStatements(statements, ctx);
9380    converter.createReturnStmt(ctx);
9381    return this.evaluateCode(sourceUrl, ctx, converter.getArgs(), createSourceMaps);
9382  }
9383  /**
9384   * Evaluate a piece of JIT generated code.
9385   * @param sourceUrl The URL of this generated code.
9386   * @param ctx A context object that contains an AST of the code to be evaluated.
9387   * @param vars A map containing the names and values of variables that the evaluated code might
9388   * reference.
9389   * @param createSourceMap If true then create a source-map for the generated code and include it
9390   * inline as a source-map comment.
9391   * @returns The result of evaluating the code.
9392   */
9393  evaluateCode(sourceUrl, ctx, vars, createSourceMap) {
9394    let fnBody = `"use strict";${ctx.toSource()}\n//# sourceURL=${sourceUrl}`;
9395    const fnArgNames = [];
9396    const fnArgValues = [];
9397    for (const argName in vars) {
9398      fnArgValues.push(vars[argName]);
9399      fnArgNames.push(argName);
9400    }
9401    if (createSourceMap) {
9402      // using `new Function(...)` generates a header, 1 line of no arguments, 2 lines otherwise
9403      // E.g. ```
9404      // function anonymous(a,b,c
9405      // /**/) { ... }```
9406      // We don't want to hard code this fact, so we auto detect it via an empty function first.
9407      const emptyFn = newTrustedFunctionForJIT(...fnArgNames.concat('return null;')).toString();
9408      const headerLines = emptyFn.slice(0, emptyFn.indexOf('return null;')).split('\n').length - 1;
9409      fnBody += `\n${ctx.toSourceMapGenerator(sourceUrl, headerLines).toJsComment()}`;
9410    }
9411    const fn = newTrustedFunctionForJIT(...fnArgNames.concat(fnBody));
9412    return this.executeFunction(fn, fnArgValues);
9413  }
9414  /**
9415   * Execute a JIT generated function by calling it.
9416   *
9417   * This method can be overridden in tests to capture the functions that are generated
9418   * by this `JitEvaluator` class.
9419   *
9420   * @param fn A function to execute.
9421   * @param args The arguments to pass to the function being executed.
9422   * @returns The return value of the executed function.
9423   */
9424  executeFunction(fn, args) {
9425    return fn(...args);
9426  }
9427}
9428/**
9429 * An Angular AST visitor that converts AST nodes into executable JavaScript code.
9430 */
9431class JitEmitterVisitor extends AbstractJsEmitterVisitor {
9432  constructor(refResolver) {
9433    super();
9434    this.refResolver = refResolver;
9435    this._evalArgNames = [];
9436    this._evalArgValues = [];
9437    this._evalExportedVars = [];
9438  }
9439  createReturnStmt(ctx) {
9440    const stmt = new ReturnStatement(new LiteralMapExpr(this._evalExportedVars.map(resultVar => new LiteralMapEntry(resultVar, variable(resultVar), false))));
9441    stmt.visitStatement(this, ctx);
9442  }
9443  getArgs() {
9444    const result = {};
9445    for (let i = 0; i < this._evalArgNames.length; i++) {
9446      result[this._evalArgNames[i]] = this._evalArgValues[i];
9447    }
9448    return result;
9449  }
9450  visitExternalExpr(ast, ctx) {
9451    this._emitReferenceToExternal(ast, this.refResolver.resolveExternalReference(ast.value), ctx);
9452    return null;
9453  }
9454  visitWrappedNodeExpr(ast, ctx) {
9455    this._emitReferenceToExternal(ast, ast.node, ctx);
9456    return null;
9457  }
9458  visitDeclareVarStmt(stmt, ctx) {
9459    if (stmt.hasModifier(StmtModifier.Exported)) {
9460      this._evalExportedVars.push(stmt.name);
9461    }
9462    return super.visitDeclareVarStmt(stmt, ctx);
9463  }
9464  visitDeclareFunctionStmt(stmt, ctx) {
9465    if (stmt.hasModifier(StmtModifier.Exported)) {
9466      this._evalExportedVars.push(stmt.name);
9467    }
9468    return super.visitDeclareFunctionStmt(stmt, ctx);
9469  }
9470  _emitReferenceToExternal(ast, value, ctx) {
9471    let id = this._evalArgValues.indexOf(value);
9472    if (id === -1) {
9473      id = this._evalArgValues.length;
9474      this._evalArgValues.push(value);
9475      const name = identifierName({
9476        reference: value
9477      }) || 'val';
9478      this._evalArgNames.push(`jit_${name}_${id}`);
9479    }
9480    ctx.print(ast, this._evalArgNames[id]);
9481  }
9482}
9483function isUseStrictStatement(statement) {
9484  return statement.isEquivalent(literal('use strict').toStmt());
9485}
9486function compileInjector(meta) {
9487  const definitionMap = new DefinitionMap();
9488  if (meta.providers !== null) {
9489    definitionMap.set('providers', meta.providers);
9490  }
9491  if (meta.imports.length > 0) {
9492    definitionMap.set('imports', literalArr(meta.imports));
9493  }
9494  const expression = importExpr(Identifiers.defineInjector).callFn([definitionMap.toLiteralMap()], undefined, true);
9495  const type = createInjectorType(meta);
9496  return {
9497    expression,
9498    type,
9499    statements: []
9500  };
9501}
9502function createInjectorType(meta) {
9503  return new ExpressionType(importExpr(Identifiers.InjectorDeclaration, [new ExpressionType(meta.type.type)]));
9504}
9505
9506/**
9507 * Implementation of `CompileReflector` which resolves references to @angular/core
9508 * symbols at runtime, according to a consumer-provided mapping.
9509 *
9510 * Only supports `resolveExternalReference`, all other methods throw.
9511 */
9512class R3JitReflector {
9513  constructor(context) {
9514    this.context = context;
9515  }
9516  resolveExternalReference(ref) {
9517    // This reflector only handles @angular/core imports.
9518    if (ref.moduleName !== '@angular/core') {
9519      throw new Error(`Cannot resolve external reference to ${ref.moduleName}, only references to @angular/core are supported.`);
9520    }
9521    if (!this.context.hasOwnProperty(ref.name)) {
9522      throw new Error(`No value provided for @angular/core symbol '${ref.name}'.`);
9523    }
9524    return this.context[ref.name];
9525  }
9526}
9527
9528/**
9529 * How the selector scope of an NgModule (its declarations, imports, and exports) should be emitted
9530 * as a part of the NgModule definition.
9531 */
9532var R3SelectorScopeMode;
9533(function (R3SelectorScopeMode) {
9534  /**
9535   * Emit the declarations inline into the module definition.
9536   *
9537   * This option is useful in certain contexts where it's known that JIT support is required. The
9538   * tradeoff here is that this emit style prevents directives and pipes from being tree-shaken if
9539   * they are unused, but the NgModule is used.
9540   */
9541  R3SelectorScopeMode[R3SelectorScopeMode["Inline"] = 0] = "Inline";
9542  /**
9543   * Emit the declarations using a side effectful function call, `ɵɵsetNgModuleScope`, that is
9544   * guarded with the `ngJitMode` flag.
9545   *
9546   * This form of emit supports JIT and can be optimized away if the `ngJitMode` flag is set to
9547   * false, which allows unused directives and pipes to be tree-shaken.
9548   */
9549  R3SelectorScopeMode[R3SelectorScopeMode["SideEffect"] = 1] = "SideEffect";
9550  /**
9551   * Don't generate selector scopes at all.
9552   *
9553   * This is useful for contexts where JIT support is known to be unnecessary.
9554   */
9555  R3SelectorScopeMode[R3SelectorScopeMode["Omit"] = 2] = "Omit";
9556})(R3SelectorScopeMode || (R3SelectorScopeMode = {}));
9557/**
9558 * The type of the NgModule meta data.
9559 * - Global: Used for full and partial compilation modes which mainly includes R3References.
9560 * - Local: Used for the local compilation mode which mainly includes the raw expressions as appears
9561 * in the NgModule decorator.
9562 */
9563var R3NgModuleMetadataKind;
9564(function (R3NgModuleMetadataKind) {
9565  R3NgModuleMetadataKind[R3NgModuleMetadataKind["Global"] = 0] = "Global";
9566  R3NgModuleMetadataKind[R3NgModuleMetadataKind["Local"] = 1] = "Local";
9567})(R3NgModuleMetadataKind || (R3NgModuleMetadataKind = {}));
9568/**
9569 * Construct an `R3NgModuleDef` for the given `R3NgModuleMetadata`.
9570 */
9571function compileNgModule(meta) {
9572  const statements = [];
9573  const definitionMap = new DefinitionMap();
9574  definitionMap.set('type', meta.type.value);
9575  // Assign bootstrap definition. In local compilation mode (i.e., for
9576  // `R3NgModuleMetadataKind.LOCAL`) we assign the bootstrap field using the runtime
9577  // `ɵɵsetNgModuleScope`.
9578  if (meta.kind === R3NgModuleMetadataKind.Global && meta.bootstrap.length > 0) {
9579    definitionMap.set('bootstrap', refsToArray(meta.bootstrap, meta.containsForwardDecls));
9580  }
9581  if (meta.selectorScopeMode === R3SelectorScopeMode.Inline) {
9582    // If requested to emit scope information inline, pass the `declarations`, `imports` and
9583    // `exports` to the `ɵɵdefineNgModule()` call directly.
9584    if (meta.declarations.length > 0) {
9585      definitionMap.set('declarations', refsToArray(meta.declarations, meta.containsForwardDecls));
9586    }
9587    if (meta.imports.length > 0) {
9588      definitionMap.set('imports', refsToArray(meta.imports, meta.containsForwardDecls));
9589    }
9590    if (meta.exports.length > 0) {
9591      definitionMap.set('exports', refsToArray(meta.exports, meta.containsForwardDecls));
9592    }
9593  } else if (meta.selectorScopeMode === R3SelectorScopeMode.SideEffect) {
9594    // In this mode, scope information is not passed into `ɵɵdefineNgModule` as it
9595    // would prevent tree-shaking of the declarations, imports and exports references. Instead, it's
9596    // patched onto the NgModule definition with a `ɵɵsetNgModuleScope` call that's guarded by the
9597    // `ngJitMode` flag.
9598    const setNgModuleScopeCall = generateSetNgModuleScopeCall(meta);
9599    if (setNgModuleScopeCall !== null) {
9600      statements.push(setNgModuleScopeCall);
9601    }
9602  } else {
9603    // Selector scope emit was not requested, so skip it.
9604  }
9605  if (meta.schemas !== null && meta.schemas.length > 0) {
9606    definitionMap.set('schemas', literalArr(meta.schemas.map(ref => ref.value)));
9607  }
9608  if (meta.id !== null) {
9609    definitionMap.set('id', meta.id);
9610    // Generate a side-effectful call to register this NgModule by its id, as per the semantics of
9611    // NgModule ids.
9612    statements.push(importExpr(Identifiers.registerNgModuleType).callFn([meta.type.value, meta.id]).toStmt());
9613  }
9614  const expression = importExpr(Identifiers.defineNgModule).callFn([definitionMap.toLiteralMap()], undefined, true);
9615  const type = createNgModuleType(meta);
9616  return {
9617    expression,
9618    type,
9619    statements
9620  };
9621}
9622/**
9623 * This function is used in JIT mode to generate the call to `ɵɵdefineNgModule(
9623)` from a call to
9624 * `ɵɵngDeclareNgModule()`.
9625 */
9626function compileNgModuleDeclarationExpression(meta) {
9627  const definitionMap = new DefinitionMap();
9628  definitionMap.set('type', new WrappedNodeExpr(meta.type));
9629  if (meta.bootstrap !== undefined) {
9630    definitionMap.set('bootstrap', new WrappedNodeExpr(meta.bootstrap));
9631  }
9632  if (meta.declarations !== undefined) {
9633    definitionMap.set('declarations', new WrappedNodeExpr(meta.declarations));
9634  }
9635  if (meta.imports !== undefined) {
9636    definitionMap.set('imports', new WrappedNodeExpr(meta.imports));
9637  }
9638  if (meta.exports !== undefined) {
9639    definitionMap.set('exports', new WrappedNodeExpr(meta.exports));
9640  }
9641  if (meta.schemas !== undefined) {
9642    definitionMap.set('schemas', new WrappedNodeExpr(meta.schemas));
9643  }
9644  if (meta.id !== undefined) {
9645    definitionMap.set('id', new WrappedNodeExpr(meta.id));
9646  }
9647  return importExpr(Identifiers.defineNgModule).callFn([definitionMap.toLiteralMap()]);
9648}
9649function createNgModuleType(meta) {
9650  if (meta.kind === R3NgModuleMetadataKind.Local) {
9651    return new ExpressionType(meta.type.value);
9652  }
9653  const {
9654    type: moduleType,
9655    declarations,
9656    exports,
9657    imports,
9658    includeImportTypes,
9659    publicDeclarationTypes
9660  } = meta;
9661  return new ExpressionType(importExpr(Identifiers.NgModuleDeclaration, [new ExpressionType(moduleType.type), publicDeclarationTypes === null ? tupleTypeOf(declarations) : tupleOfTypes(publicDeclarationTypes), includeImportTypes ? tupleTypeOf(imports) : NONE_TYPE, tupleTypeOf(exports)]));
9662}
9663/**
9664 * Generates a function call to `ɵɵsetNgModuleScope` with all necessary information so that the
9665 * transitive module scope can be computed during runtime in JIT mode. This call is marked pure
9666 * such that the references to declarations, imports and exports may be elided causing these
9667 * symbols to become tree-shakeable.
9668 */
9669function generateSetNgModuleScopeCall(meta) {
9670  const scopeMap = new DefinitionMap();
9671  if (meta.kind === R3NgModuleMetadataKind.Global) {
9672    if (meta.declarations.length > 0) {
9673      scopeMap.set('declarations', refsToArray(meta.declarations, meta.containsForwardDecls));
9674    }
9675  } else {
9676    if (meta.declarationsExpression) {
9677      scopeMap.set('declarations', meta.declarationsExpression);
9678    }
9679  }
9680  if (meta.kind === R3NgModuleMetadataKind.Global) {
9681    if (meta.imports.length > 0) {
9682      scopeMap.set('imports', refsToArray(meta.imports, meta.containsForwardDecls));
9683    }
9684  } else {
9685    if (meta.importsExpression) {
9686      scopeMap.set('imports', meta.importsExpression);
9687    }
9688  }
9689  if (meta.kind === R3NgModuleMetadataKind.Global) {
9690    if (meta.exports.length > 0) {
9691      scopeMap.set('exports', refsToArray(meta.exports, meta.containsForwardDecls));
9692    }
9693  } else {
9694    if (meta.exportsExpression) {
9695      scopeMap.set('exports', meta.exportsExpression);
9696    }
9697  }
9698  if (meta.kind === R3NgModuleMetadataKind.Local && meta.bootstrapExpression) {
9699    scopeMap.set('bootstrap', meta.bootstrapExpression);
9700  }
9701  if (Object.keys(scopeMap.values).length === 0) {
9702    return null;
9703  }
9704  // setNgModuleScope(...)
9705  const fnCall = new InvokeFunctionExpr( /* fn */importExpr(Identifiers.setNgModuleScope), /* args */[meta.type.value, scopeMap.toLiteralMap()]);
9706  // (ngJitMode guard) && setNgModuleScope(...)
9707  const guardedCall = jitOnlyGuardedExpression(fnCall);
9708  // function() { (ngJitMode guard) && setNgModuleScope(...); }
9709  const iife = new FunctionExpr( /* params */[], /* statements */[guardedCall.toStmt()]);
9710  // (function() { (ngJitMode guard) && setNgModuleScope(...); })()
9711  const iifeCall = new InvokeFunctionExpr( /* fn */iife, /* args */[]);
9712  return iifeCall.toStmt();
9713}
9714function tupleTypeOf(exp) {
9715  const types = exp.map(ref => typeofExpr(ref.type));
9716  return exp.length > 0 ? expressionType(literalArr(types)) : NONE_TYPE;
9717}
9718function tupleOfTypes(types) {
9719  const typeofTypes = types.map(type => typeofExpr(type));
9720  return types.length > 0 ? expressionType(literalArr(typeofTypes)) : NONE_TYPE;
9721}
9722function compilePipeFromMetadata(metadata) {
9723  const definitionMapValues = [];
9724  // e.g. `name: 'myPipe'`
9725  definitionMapValues.push({
9726    key: 'name',
9727    value: literal(metadata.pipeName),
9728    quoted: false
9729  });
9730  // e.g. `type: MyPipe`
9731  definitionMapValues.push({
9732    key: 'type',
9733    value: metadata.type.value,
9734    quoted: false
9735  });
9736  // e.g. `pure: true`
9737  definitionMapValues.push({
9738    key: 'pure',
9739    value: literal(metadata.pure),
9740    quoted: false
9741  });
9742  if (metadata.isStandalone) {
9743    definitionMapValues.push({
9744      key: 'standalone',
9745      value: literal(true),
9746      quoted: false
9747    });
9748  }
9749  const expression = importExpr(Identifiers.definePipe).callFn([literalMap(definitionMapValues)], undefined, true);
9750  const type = createPipeType(metadata);
9751  return {
9752    expression,
9753    type,
9754    statements: []
9755  };
9756}
9757function createPipeType(metadata) {
9758  return new ExpressionType(importExpr(Identifiers.PipeDeclaration, [typeWithParameters(metadata.type.type, metadata.typeArgumentCount), new ExpressionType(new LiteralExpr(metadata.pipeName)), new ExpressionType(new LiteralExpr(metadata.isStandalone))]));
9759}
9760var R3TemplateDependencyKind;
9761(function (R3TemplateDependencyKind) {
9762  R3TemplateDependencyKind[R3TemplateDependencyKind["Directive"] = 0] = "Directive";
9763  R3TemplateDependencyKind[R3TemplateDependencyKind["Pipe"] = 1] = "Pipe";
9764  R3TemplateDependencyKind[R3TemplateDependencyKind["NgModule"] = 2] = "NgModule";
9765})(R3TemplateDependencyKind || (R3TemplateDependencyKind = {}));
9766class ParserError {
9767  constructor(message, input, errLocation, ctxLocation) {
9768    this.input = input;
9769    this.errLocation = errLocation;
9770    this.ctxLocation = ctxLocation;
9771    this.message = `Parser Error: ${message} ${errLocation} [${input}] in ${ctxLocation}`;
9772  }
9773}
9774class ParseSpan {
9775  constructor(start, end) {
9776    this.start = start;
9777    this.end = end;
9778  }
9779  toAbsolute(absoluteOffset) {
9780    return new AbsoluteSourceSpan(absoluteOffset + this.start, absoluteOffset + this.end);
9781  }
9782}
9783class AST {
9784  constructor(span,
9785  /**
9786   * Absolute location of the expression AST in a source code file.
9787   */
9788  sourceSpan) {
9789    this.span = span;
9790    this.sourceSpan = sourceSpan;
9791  }
9792  toString() {
9793    return 'AST';
9794  }
9795}
9796class ASTWithName extends AST {
9797  constructor(span, sourceSpan, nameSpan) {
9798    super(span, sourceSpan);
9799    this.nameSpan = nameSpan;
9800  }
9801}
9802class EmptyExpr$1 extends AST {
9803  visit(visitor, context = null) {
9804    // do nothing
9805  }
9806}
9807class ImplicitReceiver extends AST {
9808  visit(visitor, context = null) {
9809    return visitor.visitImplicitReceiver(this, context);
9810  }
9811}
9812/**
9813 * Receiver when something is accessed through `this` (e.g. `this.foo`). Note that this class
9814 * inherits from `ImplicitReceiver`, because accessing something through `this` is treated the
9815 * same as accessing it implicitly inside of an Angular template (e.g. `[attr.title]="this.title"`
9816 * is the same as `[attr.title]="title"`.). Inheriting allows for the `this` accesses to be treated
9817 * the same as implicit ones, except for a couple of exceptions like `$event` and `$any`.
9818 * TODO: we should find a way for this class not to extend from `ImplicitReceiver` in the future.
9819 */
9820class ThisReceiver extends ImplicitReceiver {
9821  visit(visitor, context = null) {
9822    return visitor.visitThisReceiver?.(this, context);
9823  }
9824}
9825/**
9826 * Multiple expressions separated by a semicolon.
9827 */
9828class Chain extends AST {
9829  constructor(span, sourceSpan, expressions) {
9830    super(span, sourceSpan);
9831    this.expressions = expressions;
9832  }
9833  visit(visitor, context = null) {
9834    return visitor.visitChain(this, context);
9835  }
9836}
9837class Conditional extends AST {
9838  constructor(span, sourceSpan, condition, trueExp, falseExp) {
9839    super(span, sourceSpan);
9840    this.condition = condition;
9841    this.trueExp = trueExp;
9842    this.falseExp = falseExp;
9843  }
9844  visit(visitor, context = null) {
9845    return visitor.visitConditional(this, context);
9846  }
9847}
9848class PropertyRead extends ASTWithName {
9849  constructor(span, sourceSpan, nameSpan, receiver, name) {
9850    super(span, sourceSpan, nameSpan);
9851    this.receiver = receiver;
9852    this.name = name;
9853  }
9854  visit(visitor, context = null) {
9855    return visitor.visitPropertyRead(this, context);
9856  }
9857}
9858class PropertyWrite extends ASTWithName {
9859  constructor(span, sourceSpan, nameSpan, receiver, name, value) {
9860    super(span, sourceSpan, nameSpan);
9861    this.receiver = receiver;
9862    this.name = name;
9863    this.value = value;
9864  }
9865  visit(visitor, context = null) {
9866    return visitor.visitPropertyWrite(this, context);
9867  }
9868}
9869class SafePropertyRead extends ASTWithName {
9870  constructor(span, sourceSpan, nameSpan, receiver, name) {
9871    super(span, sourceSpan, nameSpan);
9872    this.receiver = receiver;
9873    this.name = name;
9874  }
9875  visit(visitor, context = null) {
9876    return visitor.visitSafePropertyRead(this, context);
9877  }
9878}
9879class KeyedRead extends AST {
9880  constructor(span, sourceSpan, receiver, key) {
9881    super(span, sourceSpan);
9882    this.receiver = receiver;
9883    this.key = key;
9884  }
9885  visit(visitor, context = null) {
9886    return visitor.visitKeyedRead(this, context);
9887  }
9888}
9889class SafeKeyedRead extends AST {
9890  constructor(span, sourceSpan, receiver, key) {
9891    super(span, sourceSpan);
9892    this.receiver = receiver;
9893    this.key = key;
9894  }
9895  visit(visitor, context = null) {
9896    return visitor.visitSafeKeyedRead(this, context);
9897  }
9898}
9899class KeyedWrite extends AST {
9900  constructor(span, sourceSpan, receiver, key, value) {
9901    super(span, sourceSpan);
9902    this.receiver = receiver;
9903    this.key = key;
9904    this.value = value;
9905  }
9906  visit(visitor, context = null) {
9907    return visitor.visitKeyedWrite(this, context);
9908  }
9909}
9910class BindingPipe extends ASTWithName {
9911  constructor(span, sourceSpan, exp, name, args, nameSpan) {
9912    super(span, sourceSpan, nameSpan);
9913    this.exp = exp;
9914    this.name = name;
9915    this.args = args;
9916  }
9917  visit(visitor, context = null) {
9918    return visitor.visitPipe(this, context);
9919  }
9920}
9921class LiteralPrimitive extends AST {
9922  constructor(span, sourceSpan, value) {
9923    super(span, sourceSpan);
9924    this.value = value;
9925  }
9926  visit(visitor, context = null) {
9927    return visitor.visitLiteralPrimitive(this, context);
9928  }
9929}
9930class LiteralArray extends AST {
9931  constructor(span, sourceSpan, expressions) {
9932    super(span, sourceSpan);
9933    this.expressions = expressions;
9934  }
9935  visit(visitor, context = null) {
9936    return visitor.visitLiteralArray(this, context);
9937  }
9938}
9939class LiteralMap extends AST {
9940  constructor(span, sourceSpan, keys, values) {
9941    super(span, sourceSpan);
9942    this.keys = keys;
9943    this.values = values;
9944  }
9945  visit(visitor, context = null) {
9946    return visitor.visitLiteralMap(this, context);
9947  }
9948}
9949class Interpolation$1 extends AST {
9950  constructor(span, sourceSpan, strings, expressions) {
9951    super(span, sourceSpan);
9952    this.strings = strings;
9953    this.expressions = expressions;
9954  }
9955  visit(visitor, context = null) {
9956    return visitor.visitInterpolation(this, context);
9957  }
9958}
9959class Binary extends AST {
9960  constructor(span, sourceSpan, operation, left, right) {
9961    super(span, sourceSpan);
9962    this.operation = operation;
9963    this.left = left;
9964    this.right = right;
9965  }
9966  visit(visitor, context = null) {
9967    return visitor.visitBinary(this, context);
9968  }
9969}
9970/**
9971 * For backwards compatibility reasons, `Unary` inherits from `Binary` and mimics the binary AST
9972 * node that was originally used. This inheritance relation can be deleted in some future major,
9973 * after consumers have been given a chance to fully support Unary.
9974 */
9975class Unary extends Binary {
9976  /**
9977   * Creates a unary minus expression "-x", represented as `Binary` using "0 - x".
9978   */
9979  static createMinus(span, sourceSpan, expr) {
9980    return new Unary(span, sourceSpan, '-', expr, '-', new LiteralPrimitive(span, sourceSpan, 0), expr);
9981  }
9982  /**
9983   * Creates a unary plus expression "+x", represented as `Binary` using "x - 0".
9984   */
9985  static createPlus(span, sourceSpan, expr) {
9986    return new Unary(span, sourceSpan, '+', expr, '-', expr, new LiteralPrimitive(span, sourceSpan, 0));
9987  }
9988  /**
9989   * During the deprecation period this constructor is private, to avoid consumers from creating
9990   * a `Unary` with the fallback properties for `Binary`.
9991   */
9992  constructor(span, sourceSpan, operator, expr, binaryOp, binaryLeft, binaryRight) {
9993    super(span, sourceSpan, binaryOp, binaryLeft, binaryRight);
9994    this.operator = operator;
9995    this.expr = expr;
9996    // Redeclare the properties that are inherited from `Binary` as `never`, as consumers should not
9997    // depend on these fields when operating on `Unary`.
9998    this.left = null;
9999    this.right = null;
10000    this.operation = null;
10001  }
10002  visit(visitor, context = null) {
10003    if (visitor.visitUnary !== undefined) {
10004      return visitor.visitUnary(this, context);
10005    }
10006    return visitor.visitBinary(this, context);
10007  }
10008}
10009class PrefixNot extends AST {
10010  constructor(span, sourceSpan, expression) {
10011    super(span, sourceSpan);
10012    this.expression = expression;
10013  }
10014  visit(visitor, context = null) {
10015    return visitor.visitPrefixNot(this, context);
10016  }
10017}
10018class NonNullAssert extends AST {
10019  constructor(span, sourceSpan, expression) {
10020    super(span, sourceSpan);
10021    this.expression = expression;
10022  }
10023  visit(visitor, context = null) {
10024    return visitor.visitNonNullAssert(this, context);
10025  }
10026}
10027class Call extends AST {
10028  constructor(span, sourceSpan, receiver, args, argumentSpan) {
10029    super(span, sourceSpan);
10030    this.receiver = receiver;
10031    this.args = args;
10032    this.argumentSpan = argumentSpan;
10033  }
10034  visit(visitor, context = null) {
10035    return visitor.visitCall(this, context);
10036  }
10037}
10038class SafeCall extends AST {
10039  constructor(span, sourceSpan, receiver, args, argumentSpan) {
10040    super(span, sourceSpan);
10041    this.receiver = receiver;
10042    this.args = args;
10043    this.argumentSpan = argumentSpan;
10044  }
10045  visit(visitor, context = null) {
10046    return visitor.visitSafeCall(this, context);
10047  }
10048}
10049/**
10050 * Records the absolute position of a text span in a source file, where `start` and `end` are the
10051 * starting and ending byte offsets, respectively, of the text span in a source file.
10052 */
10053class AbsoluteSourceSpan {
10054  constructor(start, end) {
10055    this.start = start;
10056    this.end = end;
10057  }
10058}
10059class ASTWithSource extends AST {
10060  constructor(ast, source, location, absoluteOffset, errors) {
10061    super(new ParseSpan(0, source === null ? 0 : source.length), new AbsoluteSourceSpan(absoluteOffset, source === null ? absoluteOffset : absoluteOffset + source.length));
10062    this.ast = ast;
10063    this.source = source;
10064    this.location = location;
10065    this.errors = errors;
10066  }
10067  visit(visitor, context = null) {
10068    if (visitor.visitASTWithSource) {
10069      return visitor.visitASTWithSource(this, context);
10070    }
10071    return this.ast.visit(visitor, context);
10072  }
10073  toString() {
10074    return `${this.source} in ${this.location}`;
10075  }
10076}
10077class VariableBinding {
10078  /**
10079   * @param sourceSpan entire span of the binding.
10080   * @param key name of the LHS along with its span.
10081   * @param value optional value for the RHS along with its span.
10082   */
10083  constructor(sourceSpan, key, value) {
10084    this.sourceSpan = sourceSpan;
10085    this.key = key;
10086    this.value = value;
10087  }
10088}
10089class ExpressionBinding {
10090  /**
10091   * @param sourceSpan entire span of the binding.
10092   * @param key binding name, like ngForOf, ngForTrackBy, ngIf, along with its
10093   * span. Note that the length of the span may not be the same as
10094   * `key.source.length`. For example,
10095   * 1. key.source = ngFor, key.span is for "ngFor"
10096   * 2. key.source = ngForOf, key.span is for "of"
10097   * 3. key.source = ngForTrackBy, key.span is for "trackBy"
10098   * @param value optional expression for the RHS.
10099   */
10100  constructor(sourceSpan, key, value) {
10101    this.sourceSpan = sourceSpan;
10102    this.key = key;
10103    this.value = value;
10104  }
10105}
10106class RecursiveAstVisitor {
10107  visit(ast, context) {
10108    // The default implementation just visits every node.
10109    // Classes that extend RecursiveAstVisitor should override this function
10110    // to selectively visit the specified node.
10111    ast.visit(this, context);
10112  }
10113  visitUnary(ast, context) {
10114    this.visit(ast.expr, context);
10115  }
10116  visitBinary(ast, context) {
10117    this.visit(ast.left, context);
10118    this.visit(ast.right, context);
10119  }
10120  visitChain(ast, context) {
10121    this.visitAll(ast.expressions, context);
10122  }
10123  visitConditional(ast, context) {
10124    this.visit(ast.condition, context);
10125    this.visit(ast.trueExp, context);
10126    this.visit(ast.falseExp, context);
10127  }
10128  visitPipe(ast, context) {
10129    this.visit(ast.exp, context);
10130    this.visitAll(ast.args, context);
10131  }
10132  visitImplicitReceiver(ast, context) {}
10133  visitThisReceiver(ast, context) {}
10134  visitInterpolation(ast, context) {
10135    this.visitAll(ast.expressions, context);
10136  }
10137  visitKeyedRead(ast, context) {
10138    this.visit(ast.receiver, context);
10139    this.visit(ast.key, context);
10140  }
10141  visitKeyedWrite(ast, context) {
10142    this.visit(ast.receiver, context);
10143    this.visit(ast.key, context);
10144    this.visit(ast.value, context);
10145  }
10146  visitLiteralArray(ast, context) {
10147    this.visitAll(ast.expressions, context);
10148  }
10149  visitLiteralMap(ast, context) {
10150    this.visitAll(ast.values, context);
10151  }
10152  visitLiteralPrimitive(ast, context) {}
10153  visitPrefixNot(ast, context) {
10154    this.visit(ast.expression, context);
10155  }
10156  visitNonNullAssert(ast, context) {
10157    this.visit(ast.expression, context);
10158  }
10159  visitPropertyRead(ast, context) {
10160    this.visit(ast.receiver, context);
10161  }
10162  visitPropertyWrite(ast, context) {
10163    this.visit(ast.receiver, context);
10164    this.visit(ast.value, context);
10165  }
10166  visitSafePropertyRead(ast, context) {
10167    this.visit(ast.receiver, context);
10168  }
10169  visitSafeKeyedRead(ast, context) {
10170    this.visit(ast.receiver, context);
10171    this.visit(ast.key, context);
10172  }
10173  visitCall(ast, context) {
10174    this.visit(ast.receiver, context);
10175    this.visitAll(ast.args, context);
10176  }
10177  visitSafeCall(ast, context) {
10178    this.visit(ast.receiver, context);
10179    this.visitAll(ast.args, context);
10180  }
10181  // This is not part of the AstVisitor interface, just a helper method
10182  visitAll(asts, context) {
10183    for (const ast of asts) {
10184      this.visit(ast, context);
10185    }
10186  }
10187}
10188class AstTransformer {
10189  visitImplicitReceiver(ast, context) {
10190    return ast;
10191  }
10192  visitThisReceiver(ast, context) {
10193    return ast;
10194  }
10195  visitInterpolation(ast, context) {
10196    return new Interpolation$1(ast.span, ast.sourceSpan, ast.strings, this.visitAll(ast.expressions));
10197  }
10198  visitLiteralPrimitive(ast, context) {
10199    return new LiteralPrimitive(ast.span, ast.sourceSpan, ast.value);
10200  }
10201  visitPropertyRead(ast, context) {
10202    return new PropertyRead(ast.span, ast.sourceSpan, ast.nameSpan, ast.receiver.visit(this), ast.name);
10203  }
10204  visitPropertyWrite(ast, context) {
10205    return new PropertyWrite(ast.span, ast.sourceSpan, ast.nameSpan, ast.receiver.visit(this), ast.name, ast.value.visit(this));
10206  }
10207  visitSafePropertyRead(ast, context) {
10208    return new SafePropertyRead(ast.span, ast.sourceSpan, ast.nameSpan, ast.receiver.visit(this), ast.name);
10209  }
10210  visitLiteralArray(ast, context) {
10211    return new LiteralArray(ast.span, ast.sourceSpan, this.visitAll(ast.expressions));
10212  }
10213  visitLiteralMap(ast, context) {
10214    return new LiteralMap(ast.span, ast.sourceSpan, ast.keys, this.visitAll(ast.values));
10215  }
10216  visitUnary(ast, context) {
10217    switch (ast.operator) {
10218      case '+':
10219        return Unary.createPlus(ast.span, ast.sourceSpan, ast.expr.visit(this));
10220      case '-':
10221        return Unary.createMinus(ast.span, ast.sourceSpan, ast.expr.visit(this));
10222      default:
10223        throw new Error(`Unknown unary operator ${ast.operator}`);
10224    }
10225  }
10226  visitBinary(ast, context) {
10227    return new Binary(ast.span, ast.sourceSpan, ast.operation, ast.left.visit(this), ast.right.visit(this));
10228  }
10229  visitPrefixNot(ast, context) {
10230    return new PrefixNot(ast.span, ast.sourceSpan, ast.expression.visit(this));
10231  }
10232  visitNonNullAssert(ast, context) {
10233    return new NonNullAssert(ast.span, ast.sourceSpan, ast.expression.visit(this));
10234  }
10235  visitConditional(ast, context) {
10236    return new Conditional(ast.span, ast.sourceSpan, ast.condition.visit(this), ast.trueExp.visit(this), ast.falseExp.visit(this));
10237  }
10238  visitPipe(ast, context) {
10239    return new BindingPipe(ast.span, ast.sourceSpan, ast.exp.visit(this), ast.name, this.visitAll(ast.args), ast.nameSpan);
10240  }
10241  visitKeyedRead(ast, context) {
10242    return new KeyedRead(ast.span, ast.sourceSpan, ast.receiver.visit(this), ast.key.visit(this));
10243  }
10244  visitKeyedWrite(ast, context) {
10245    return new KeyedWrite(ast.span, ast.sourceSpan, ast.receiver.visit(this), ast.key.visit(this), ast.value.visit(this));
10246  }
10247  visitCall(ast, context) {
10248    return new Call(ast.span, ast.sourceSpan, ast.receiver.visit(this), this.visitAll(ast.args), ast.argumentSpan);
10249  }
10250  visitSafeCall(ast, context) {
10251    return new SafeCall(ast.span, ast.sourceSpan, ast.receiver.visit(this), this.visitAll(ast.args), ast.argumentSpan);
10252  }
10253  visitAll(asts) {
10254    const res = [];
10255    for (let i = 0; i < asts.length; ++i) {
10256      res[i] = asts[i].visit(this);
10257    }
10258    return res;
10259  }
10260  visitChain(ast, context) {
10261    return new Chain(ast.span, ast.sourceSpan, this.visitAll(ast.expressions));
10262  }
10263  visitSafeKeyedRead(ast, context) {
10264    return new SafeKeyedRead(ast.span, ast.sourceSpan, ast.receiver.visit(this), ast.key.visit(this));
10265  }
10266}
10267// A transformer that only creates new nodes if the transformer makes a change or
10268// a change is made a child node.
10269class AstMemoryEfficientTransformer {
10270  visitImplicitReceiver(ast, context) {
10271    return ast;
10272  }
10273  visitThisReceiver(ast, context) {
10274    return ast;
10275  }
10276  visitInterpolation(ast, context) {
10277    const expressions = this.visitAll(ast.expressions);
10278    if (expressions !== ast.expressions) return new Interpolation$1(ast.span, ast.sourceSpan, ast.strings, expressions);
10279    return ast;
10280  }
10281  visitLiteralPrimitive(ast, context) {
10282    return ast;
10283  }
10284  visitPropertyRead(ast, context) {
10285    const receiver = ast.receiver.visit(this);
10286    if (receiver !== ast.receiver) {
10287      return new PropertyRead(ast.span, ast.sourceSpan, ast.nameSpan, receiver, ast.name);
10288    }
10289    return ast;
10290  }
10291  visitPropertyWrite(ast, context) {
10292    const receiver = ast.receiver.visit(this);
10293    const value = ast.value.visit(this);
10294    if (receiver !== ast.receiver || value !== ast.value) {
10295      return new PropertyWrite(ast.span, ast.sourceSpan, ast.nameSpan, receiver, ast.name, value);
10296    }
10297    return ast;
10298  }
10299  visitSafePropertyRead(ast, context) {
10300    const receiver = ast.receiver.visit(this);
10301    if (receiver !== ast.receiver) {
10302      return new SafePropertyRead(ast.span, ast.sourceSpan, ast.nameSpan, receiver, ast.name);
10303    }
10304    return ast;
10305  }
10306  visitLiteralArray(ast, context) {
10307    const expressions = this.visitAll(ast.expressions);
10308    if (expressions !== ast.expressions) {
10309      return new LiteralArray(ast.span, ast.sourceSpan, expressions);
10310    }
10311    return ast;
10312  }
10313  visitLiteralMap(ast, context) {
10314    const values = this.visitAll(ast.values);
10315    if (values !== ast.values) {
10316      return new LiteralMap(ast.span, ast.sourceSpan, ast.keys, values);
10317    }
10318    return ast;
10319  }
10320  visitUnary(ast, context) {
10321    const expr = ast.expr.visit(this);
10322    if (expr !== ast.expr) {
10323      switch (ast.operator) {
10324        case '+':
10325          return Unary.createPlus(ast.span, ast.sourceSpan, expr);
10326        case '-':
10327          return Unary.createMinus(ast.span, ast.sourceSpan, expr);
10328        default:
10329          throw new Error(`Unknown unary operator ${ast.operator}`);
10330      }
10331    }
10332    return ast;
10333  }
10334  visitBinary(ast, context) {
10335    const left = ast.left.visit(this);
10336    const right = ast.right.visit(this);
10337    if (left !== ast.left || right !== ast.right) {
10338      return new Binary(ast.span, ast.sourceSpan, ast.operation, left, right);
10339    }
10340    return ast;
10341  }
10342  visitPrefixNot(ast, context) {
10343    const expression = ast.expression.visit(this);
10344    if (expression !== ast.expression) {
10345      return new PrefixNot(ast.span, ast.sourceSpan, expression);
10346    }
10347    return ast;
10348  }
10349  visitNonNullAssert(ast, context) {
10350    const expression = ast.expression.visit(this);
10351    if (expression !== ast.expression) {
10352      return new NonNullAssert(ast.span, ast.sourceSpan, expression);
10353    }
10354    return ast;
10355  }
10356  visitConditional(ast, context) {
10357    const condition = ast.condition.visit(this);
10358    const trueExp = ast.trueExp.visit(this);
10359    const falseExp = ast.falseExp.visit(this);
10360    if (condition !== ast.condition || trueExp !== ast.trueExp || falseExp !== ast.falseExp) {
10361      return new Conditional(ast.span, ast.sourceSpan, condition, trueExp, falseExp);
10362    }
10363    return ast;
10364  }
10365  visitPipe(ast, context) {
10366    const exp = ast.exp.visit(this);
10367    const args = this.visitAll(ast.args);
10368    if (exp !== ast.exp || args !== ast.args) {
10369      return new BindingPipe(ast.span, ast.sourceSpan, exp, ast.name, args, ast.nameSpan);
10370    }
10371    return ast;
10372  }
10373  visitKeyedRead(ast, context) {
10374    const obj = ast.receiver.visit(this);
10375    const key = ast.key.visit(this);
10376    if (obj !== ast.receiver || key !== ast.key) {
10377      return new KeyedRead(ast.span, ast.sourceSpan, obj, key);
10378    }
10379    return ast;
10380  }
10381  visitKeyedWrite(ast, context) {
10382    const obj = ast.receiver.visit(this);
10383    const key = ast.key.visit(this);
10384    const value = ast.value.visit(this);
10385    if (obj !== ast.receiver || key !== ast.key || value !== ast.value) {
10386      return new KeyedWrite(ast.span, ast.sourceSpan, obj, key, value);
10387    }
10388    return ast;
10389  }
10390  visitAll(asts) {
10391    const res = [];
10392    let modified = false;
10393    for (let i = 0; i < asts.length; ++i) {
10394      const original = asts[i];
10395      const value = original.visit(this);
10396      res[i] = value;
10397      modified = modified || value !== original;
10398    }
10399    return modified ? res : asts;
10400  }
10401  visitChain(ast, context) {
10402    const expressions = this.visitAll(ast.expressions);
10403    if (expressions !== ast.expressions) {
10404      return new Chain(ast.span, ast.sourceSpan, expressions);
10405    }
10406    return ast;
10407  }
10408  visitCall(ast, context) {
10409    const receiver = ast.receiver.visit(this);
10410    const args = this.visitAll(ast.args);
10411    if (receiver !== ast.receiver || args !== ast.args) {
10412      return new Call(ast.span, ast.sourceSpan, receiver, args, ast.argumentSpan);
10413    }
10414    return ast;
10415  }
10416  visitSafeCall(ast, context) {
10417    const receiver = ast.receiver.visit(this);
10418    const args = this.visitAll(ast.args);
10419    if (receiver !== ast.receiver || args !== ast.args) {
10420      return new SafeCall(ast.span, ast.sourceSpan, receiver, args, ast.argumentSpan);
10421    }
10422    return ast;
10423  }
10424  visitSafeKeyedRead(ast, context) {
10425    const obj = ast.receiver.visit(this);
10426    const key = ast.key.visit(this);
10427    if (obj !== ast.receiver || key !== ast.key) {
10428      return new SafeKeyedRead(ast.span, ast.sourceSpan, obj, key);
10429    }
10430    return ast;
10431  }
10432}
10433// Bindings
10434class ParsedProperty {
10435  constructor(name, expression, type, sourceSpan, keySpan, valueSpan) {
10436    this.name = name;
10437    this.expression = expression;
10438    this.type = type;
10439    this.sourceSpan = sourceSpan;
10440    this.keySpan = keySpan;
10441    this.valueSpan = valueSpan;
10442    this.isLiteral = this.type === ParsedPropertyType.LITERAL_ATTR;
10443    this.isAnimation = this.type === ParsedPropertyType.ANIMATION;
10444  }
10445}
10446var ParsedPropertyType;
10447(function (ParsedPropertyType) {
10448  ParsedPropertyType[ParsedPropertyType["DEFAULT"] = 0] = "DEFAULT";
10449  ParsedPropertyType[ParsedPropertyType["LITERAL_ATTR"] = 1] = "LITERAL_ATTR";
10450  ParsedPropertyType[ParsedPropertyType["ANIMATION"] = 2] = "ANIMATION";
10451  ParsedPropertyType[ParsedPropertyType["TWO_WAY"] = 3] = "TWO_WAY";
10452})(ParsedPropertyType || (ParsedPropertyType = {}));
10453class ParsedEvent {
10454  constructor(name, targetOrPhase, type, handler, sourceSpan, handlerSpan, keySpan) {
10455    this.name = name;
10456    this.targetOrPhase = targetOrPhase;
10457    this.type = type;
10458    this.handler = handler;
10459    this.sourceSpan = sourceSpan;
10460    this.handlerSpan = handlerSpan;
10461    this.keySpan = keySpan;
10462  }
10463}
10464/**
10465 * ParsedVariable represents a variable declaration in a microsyntax expression.
10466 */
10467class ParsedVariable {
10468  constructor(name, value, sourceSpan, keySpan, valueSpan) {
10469    this.name = name;
10470    this.value = value;
10471    this.sourceSpan = sourceSpan;
10472    this.keySpan = keySpan;
10473    this.valueSpan = valueSpan;
10474  }
10475}
10476class BoundElementProperty {
10477  constructor(name, type, securityContext, value, unit, sourceSpan, keySpan, valueSpan) {
10478    this.name = name;
10479    this.type = type;
10480    this.securityContext = securityContext;
10481    this.value = value;
10482    this.unit = unit;
10483    this.sourceSpan = sourceSpan;
10484    this.keySpan = keySpan;
10485    this.valueSpan = valueSpan;
10486  }
10487}
10488class EventHandlerVars {
10489  static #_ = this.event = variable('$event');
10490}
10491/**
10492 * Converts the given expression AST into an executable output AST, assuming the expression is
10493 * used in an action binding (e.g. an event handler).
10494 */
10495function convertActionBinding(localResolver, implicitReceiver, action, bindingId, baseSourceSpan, implicitReceiverAccesses, globals) {
10496  localResolver ??= new DefaultLocalResolver(globals);
10497  const visitor = new _AstToIrVisitor(localResolver, implicitReceiver, bindingId, /* supportsInterpolation */false, baseSourceSpan, implicitReceiverAccesses);
10498  const actionStmts = [];
10499  flattenStatements(convertActionBuiltins(action).visit(visitor, _Mode.Statement), actionStmts);
10500  prependTemporaryDecls(visitor.temporaryCount, bindingId, actionStmts);
10501  if (visitor.usesImplicitReceiver) {
10502    localResolver.notifyImplicitReceiverUse();
10503  }
10504  const lastIndex = actionStmts.length - 1;
10505  if (lastIndex >= 0) {
10506    const lastStatement = actionStmts[lastIndex];
10507    // Ensure that the value of the last expression statement is returned
10508    if (lastStatement instanceof ExpressionStatement) {
10509      actionStmts[lastIndex] = new ReturnStatement(lastStatement.expr);
10510    }
10511  }
10512  return actionStmts;
10513}
10514function convertAssignmentActionBinding(localResolver, implicitReceiver, action, bindingId, baseSourceSpan, implicitReceiverAccesses, globals) {
10515  localResolver ??= new DefaultLocalResolver(globals);
10516  const visitor = new _AstToIrVisitor(localResolver, implicitReceiver, bindingId, /* supportsInterpolation */false, baseSourceSpan, implicitReceiverAccesses);
10517  let convertedAction = convertActionBuiltins(action).visit(visitor, _Mode.Statement);
10518  // This should already have been asserted in the parser, but we verify it here just in case.
10519  if (!(convertedAction instanceof ExpressionStatement)) {
10520    throw new Error(`Illegal state: unsupported expression in two-way action binding.`);
10521  }
10522  // Converts `[(ngModel)]="name"` to `twoWayBindingSet(ctx.name, $event) || (ctx.name = $event)`.
10523  convertedAction = wrapAssignmentAction(convertedAction.expr).toStmt();
10524  const actionStmts = [];
10525  flattenStatements(convertedAction, actionStmts);
10526  prependTemporaryDecls(visitor.temporaryCount, bindingId, actionStmts);
10527  // Assignment events always return `$event`.
10528  actionStmts.push(new ReturnStatement(EventHandlerVars.event));
10529  implicitReceiverAccesses?.add(EventHandlerVars.event.name);
10530  if (visitor.usesImplicitReceiver) {
10531    localResolver.notifyImplicitReceiverUse();
10532  }
10533  return actionStmts;
10534}
10535function wrapAssignmentReadExpression(ast) {
10536  return new ExternalExpr(Identifiers.twoWayBindingSet).callFn([ast, EventHandlerVars.event]).or(ast.set(EventHandlerVars.event));
10537}
10538function isReadExpression$1(value) {
10539  return value instanceof ReadPropExpr || value instanceof ReadKeyExpr;
10540}
10541function wrapAssignmentAction(ast) {
10542  // The only officially supported expressions inside of a two-way binding are read expressions.
10543  if (isReadExpression$1(ast)) {
10544    return wrapAssignmentReadExpression(ast);
10545  }
10546  // However, historically the expression parser was handling two-way events by appending `=$event`
10547  // to the raw string before attempting to parse it. This has led to bugs over the years (see
10548  // #37809) and to unintentionally supporting unassignable events in the two-way binding. The
10549  // logic below aims to emulate the old behavior while still supporting the new output format
10550  // which uses `twoWayBindingSet`. Note that the generated code doesn't necessarily make sense
10551  // based on what the user wrote, for example the event binding for `[(value)]="a ? b : c"`
10552  // would produce `ctx.a ? ctx.b : ctx.c = $event`. We aim to reproduce what the parser used
10553  // to generate before #54154.
10554  if (ast instanceof BinaryOperatorExpr && isReadExpression$1(ast.rhs)) {
10555    // `a && b` -> `ctx.a && twoWayBindingSet(ctx.b, $event) || (ctx.b = $event)`
10556    return new BinaryOperatorExpr(ast.operator, ast.lhs, wrapAssignmentReadExpression(ast.rhs));
10557  }
10558  // Note: this also supports nullish coalescing expressions which
10559  // would've been downleveled to ternary expressions by this point.
10560  if (ast instanceof ConditionalExpr && isReadExpression$1(ast.falseCase)) {
10561    // `a ? b : c` -> `ctx.a ? ctx.b : twoWayBindingSet(ctx.c, $event) || (ctx.c = $event)`
10562    return new ConditionalExpr(ast.condition, ast.trueCase, wrapAssignmentReadExpression(ast.falseCase));
10563  }
10564  // `!!a` -> `twoWayBindingSet(ctx.a, $event) || (ctx.a = $event)`
10565  // Note: previously we'd actually produce `!!(ctx.a = $event)`, but the wrapping
10566  // node doesn't affect the result so we don't need to carry it over.
10567  if (ast instanceof NotExpr) {
10568    let expr = ast.condition;
10569    while (true) {
10570      if (expr instanceof NotExpr) {
10571        expr = expr.condition;
10572      } else {
10573        if (isReadExpression$1(expr)) {
10574          return wrapAssignmentReadExpression(expr);
10575        }
10576        break;
10577      }
10578    }
10579  }
10580  throw new Error(`Illegal state: unsupported expression in two-way action binding.`);
10581}
10582function convertPropertyBindingBuiltins(converterFactory, ast) {
10583  return convertBuiltins(converterFactory, ast);
10584}
10585class ConvertPropertyBindingResult {
10586  constructor(stmts, currValExpr) {
10587    this.stmts = stmts;
10588    this.currValExpr = currValExpr;
10589  }
10590}
10591/**
10592 * Converts the given expression AST into an executable output AST, assuming the expression
10593 * is used in property binding. The expression has to be preprocessed via
10594 * `convertPropertyBindingBuiltins`.
10595 */
10596function convertPropertyBinding(localResolver, implicitReceiver, expressionWithoutBuiltins, bindingId) {
10597  if (!localResolver) {
10598    localResolver = new DefaultLocalResolver();
10599  }
10600  const visitor = new _AstToIrVisitor(localResolver, implicitReceiver, bindingId, /* supportsInterpolation */false);
10601  const outputExpr = expressionWithoutBuiltins.visit(visitor, _Mode.Expression);
10602  const stmts = getStatementsFromVisitor(visitor, bindingId);
10603  if (visitor.usesImplicitReceiver) {
10604    localResolver.notifyImplicitReceiverUse();
10605  }
10606  return new ConvertPropertyBindingResult(stmts, outputExpr);
10607}
10608/** Converts an AST to a pure function that may have access to the component scope. */
10609function convertPureComponentScopeFunction(ast, localResolver, implicitReceiver, bindingId) {
10610  const converted = convertPropertyBindingBuiltins({
10611    createLiteralArrayConverter: () => args => literalArr(args),
10612    createLiteralMapConverter: keys => values => literalMap(keys.map((key, index) => {
10613      return {
10614        key: key.key,
10615        value: values[index],
10616        quoted: key.quoted
10617      };
10618    })),
10619    createPipeConverter: () => {
10620      throw new Error('Illegal State: Pipes are not allowed in this context');
10621    }
10622  }, ast);
10623  const visitor = new _AstToIrVisitor(localResolver, implicitReceiver, bindingId, false);
10624  const statements = [];
10625  flattenStatements(converted.visit(visitor, _Mode.Statement), statements);
10626  return statements;
10627}
10628/**
10629 * Given some expression, such as a binding or interpolation expression, and a context expression to
10630 * look values up on, visit each facet of the given expression resolving values from the context
10631 * expression such that a list of arguments can be derived from the found values that can be used as
10632 * arguments to an external update instruction.
10633 *
10634 * @param localResolver The resolver to use to look up expressions by name appropriately
10635 * @param contextVariableExpression The expression representing the context variable used to create
10636 * the final argument expressions
10637 * @param expressionWithArgumentsToExtract The expression to visit to figure out what values need to
10638 * be resolved and what arguments list to build.
10639 * @param bindingId A name prefix used to create temporary variable names if they're needed for the
10640 * arguments generated
10641 * @returns An array of expressions that can be passed as arguments to instruction expressions like
10642 * `o.importExpr(R3.propertyInterpolate).callFn(result)`
10643 */
10644function convertUpdateArguments(localResolver, contextVariableExpression, expressionWithArgumentsToExtract, bindingId) {
10645  const visitor = new _AstToIrVisitor(localResolver, contextVariableExpression, bindingId, /* supportsInterpolation */true);
10646  const outputExpr = visitor.visitInterpolation(expressionWithArgumentsToExtract, _Mode.Expression);
10647  if (visitor.usesImplicitReceiver) {
10648    localResolver.notifyImplicitReceiverUse();
10649  }
10650  const stmts = getStatementsFromVisitor(visitor, bindingId);
10651  const args = outputExpr.args;
10652  return {
10653    stmts,
10654    args
10655  };
10656}
10657function getStatementsFromVisitor(visitor, bindingId) {
10658  const stmts = [];
10659  for (let i = 0; i < visitor.temporaryCount; i++) {
10660    stmts.push(temporaryDeclaration(bindingId, i));
10661  }
10662  return stmts;
10663}
10664function convertBuiltins(converterFactory, ast) {
10665  const visitor = new _BuiltinAstConverter(converterFactory);
10666  return ast.visit(visitor);
10667}
10668function convertActionBuiltins(action) {
10669  const converterFactory = {
10670    createLiteralArrayConverter: () => {
10671      // Note: no caching for literal arrays in actions.
10672      return args => literalArr(args);
10673    },
10674    createLiteralMapConverter: keys => {
10675      // Note: no caching for literal maps in actions.
10676      return values => {
10677        const entries = keys.map((k, i) => ({
10678          key: k.key,
10679          value: values[i],
10680          quoted: k.quoted
10681        }));
10682        return literalMap(entries);
10683      };
10684    },
10685    createPipeConverter: name => {
10686      throw new Error(`Illegal State: Actions are not allowed to contain pipes. Pipe: ${name}`);
10687    }
10688  };
10689  return convertPropertyBindingBuiltins(converterFactory, action);
10690}
10691function temporaryName(bindingId, temporaryNumber) {
10692  return `tmp_${bindingId}_${temporaryNumber}`;
10693}
10694function temporaryDeclaration(bindingId, temporaryNumber) {
10695  return new DeclareVarStmt(temporaryName(bindingId, temporaryNumber));
10696}
10697function prependTemporaryDecls(temporaryCount, bindingId, statements) {
10698  for (let i = temporaryCount - 1; i >= 0; i--) {
10699    statements.unshift(temporaryDeclaration(bindingId, i));
10700  }
10701}
10702var _Mode;
10703(function (_Mode) {
10704  _Mode[_Mode["Statement"] = 0] = "Statement";
10705  _Mode[_Mode["Expression"] = 1] = "Expression";
10706})(_Mode || (_Mode = {}));
10707function ensureStatementMode(mode, ast) {
10708  if (mode !== _Mode.Statement) {
10709    throw new Error(`Expected a statement, but saw ${ast}`);
10710  }
10711}
10712function ensureExpressionMode(mode, ast) {
10713  if (mode !== _Mode.Expression) {
10714    throw new Error(`Expected an expression, but saw ${ast}`);
10715  }
10716}
10717function convertToStatementIfNeeded(mode, expr) {
10718  if (mode === _Mode.Statement) {
10719    return expr.toStmt();
10720  } else {
10721    return expr;
10722  }
10723}
10724class _BuiltinAstConverter extends AstTransformer {
10725  constructor(_converterFactory) {
10726    super();
10727    this._converterFactory = _converterFactory;
10728  }
10729  visitPipe(ast, context) {
10730    const args = [ast.exp, ...ast.args].map(ast => ast.visit(this, context));
10731    return new BuiltinFunctionCall(ast.span, ast.sourceSpan, args, this._converterFactory.createPipeConverter(ast.name, args.length));
10732  }
10733  visitLiteralArray(ast, context) {
10734    const args = ast.expressions.map(ast => ast.visit(this, context));
10735    return new BuiltinFunctionCall(ast.span, ast.sourceSpan, args, this._converterFactory.createLiteralArrayConverter(ast.expressions.length));
10736  }
10737  visitLiteralMap(ast, context) {
10738    const args = ast.values.map(ast => ast.visit(this, context));
10739    return new BuiltinFunctionCall(ast.span, ast.sourceSpan, args, this._converterFactory.createLiteralMapConverter(ast.keys));
10740  }
10741}
10742class _AstToIrVisitor {
10743  constructor(_localResolver, _implicitReceiver, bindingId, supportsInterpolation, baseSourceSpan, implicitReceiverAccesses) {
10744    this._localResolver = _localResolver;
10745    this._implicitReceiver = _implicitReceiver;
10746    this.bindingId = bindingId;
10747    this.supportsInterpolation = supportsInterpolation;
10748    this.baseSourceSpan = baseSourceSpan;
10749    this.implicitReceiverAccesses = implicitReceiverAccesses;
10750    this._nodeMap = new Map();
10751    this._resultMap = new Map();
10752    this._currentTemporary = 0;
10753    this.temporaryCount = 0;
10754    this.usesImplicitReceiver = false;
10755  }
10756  visitUnary(ast, mode) {
10757    let op;
10758    switch (ast.operator) {
10759      case '+':
10760        op = UnaryOperator.Plus;
10761        break;
10762      case '-':
10763        op = UnaryOperator.Minus;
10764        break;
10765      default:
10766        throw new Error(`Unsupported operator ${ast.operator}`);
10767    }
10768    return convertToStatementIfNeeded(mode, new UnaryOperatorExpr(op, this._visit(ast.expr, _Mode.Expression), undefined, this.convertSourceSpan(ast.span)));
10769  }
10770  visitBinary(ast, mode) {
10771    let op;
10772    switch (ast.operation) {
10773      case '+':
10774        op = BinaryOperator.Plus;
10775        break;
10776      case '-':
10777        op = BinaryOperator.Minus;
10778        break;
10779      case '*':
10780        op = BinaryOperator.Multiply;
10781        break;
10782      case '/':
10783        op = BinaryOperator.Divide;
10784        break;
10785      case '%':
10786        op = BinaryOperator.Modulo;
10787        break;
10788      case '&&':
10789        op = BinaryOperator.And;
10790        break;
10791      case '||':
10792        op = BinaryOperator.Or;
10793        break;
10794      case '==':
10795        op = BinaryOperator.Equals;
10796        break;
10797      case '!=':
10798        op = BinaryOperator.NotEquals;
10799        break;
10800      case '===':
10801        op = BinaryOperator.Identical;
10802        break;
10803      case '!==':
10804        op = BinaryOperator.NotIdentical;
10805        break;
10806      case '<':
10807        op = BinaryOperator.Lower;
10808        break;
10809      case '>':
10810        op = BinaryOperator.Bigger;
10811        break;
10812      case '<=':
10813        op = BinaryOperator.LowerEquals;
10814        break;
10815      case '>=':
10816        op = BinaryOperator.BiggerEquals;
10817        break;
10818      case '??':
10819        return this.convertNullishCoalesce(ast, mode);
10820      default:
10821        throw new Error(`Unsupported operation ${ast.operation}`);
10822    }
10823    return convertToStatementIfNeeded(mode, new BinaryOperatorExpr(op, this._visit(ast.left, _Mode.Expression), this._visit(ast.right, _Mode.Expression), undefined, this.convertSourceSpan(ast.span)));
10824  }
10825  visitChain(ast, mode) {
10826    ensureStatementMode(mode, ast);
10827    return this.visitAll(ast.expressions, mode);
10828  }
10829  visitConditional(ast, mode) {
10830    const value = this._visit(ast.condition, _Mode.Expression);
10831    return convertToStatementIfNeeded(mode, value.conditional(this._visit(ast.trueExp, _Mode.Expression), this._visit(ast.falseExp, _Mode.Expression), this.convertSourceSpan(ast.span)));
10832  }
10833  visitPipe(ast, mode) {
10834    throw new Error(`Illegal state: Pipes should have been converted into functions. Pipe: ${ast.name}`);
10835  }
10836  visitImplicitReceiver(ast, mode) {
10837    ensureExpressionMode(mode, ast);
10838    this.usesImplicitReceiver = true;
10839    return this._implicitReceiver;
10840  }
10841  visitThisReceiver(ast, mode) {
10842    return this.visitImplicitReceiver(ast, mode);
10843  }
10844  visitInterpolation(ast, mode) {
10845    if (!this.supportsInterpolation) {
10846      throw new Error('Unexpected interpolation');
10847    }
10848    ensureExpressionMode(mode, ast);
10849    let args = [];
10850    for (let i = 0; i < ast.strings.length - 1; i++) {
10851      args.push(literal(ast.strings[i]));
10852      args.push(this._visit(ast.expressions[i], _Mode.Expression));
10853    }
10854    args.push(literal(ast.strings[ast.strings.length - 1]));
10855    // If we're dealing with an interpolation of 1 value with an empty prefix and suffix, reduce the
10856    // args returned to just the value, because we're going to pass it to a special instruction.
10857    const strings = ast.strings;
10858    if (strings.length === 2 && strings[0] === '' && strings[1] === '') {
10859      // Single argument interpolate instructions.
10860      args = [args[1]];
10861    } else if (ast.expressions.length >= 9) {
10862      // 9 or more arguments must be passed to the `interpolateV`-style instructions, which accept
10863      // an array of arguments
10864      args = [literalArr(args)];
10865    }
10866    return new InterpolationExpression(args);
10867  }
10868  visitKeyedRead(ast, mode) {
10869    const leftMostSafe = this.leftMostSafeNode(ast);
10870    if (leftMostSafe) {
10871      return this.convertSafeAccess(ast, leftMostSafe, mode);
10872    } else {
10873      return convertToStatementIfNeeded(mode, this._visit(ast.receiver, _Mode.Expression).key(this._visit(ast.key, _Mode.Expression)));
10874    }
10875  }
10876  visitKeyedWrite(ast, mode) {
10877    const obj = this._visit(ast.receiver, _Mode.Expression);
10878    const key = this._visit(ast.key, _Mode.Expression);
10879    const value = this._visit(ast.value, _Mode.Expression);
10880    if (obj === this._implicitReceiver) {
10881      this._localResolver.maybeRestoreView();
10882    }
10883    return convertToStatementIfNeeded(mode, obj.key(key).set(value));
10884  }
10885  visitLiteralArray(ast, mode) {
10886    throw new Error(`Illegal State: literal arrays should have been converted into functions`);
10887  }
10888  visitLiteralMap(ast, mode) {
10889    throw new Error(`Illegal State: literal maps should have been converted into functions`);
10890  }
10891  visitLiteralPrimitive(ast, mode) {
10892    // For literal values of null, undefined, true, or false allow type interference
10893    // to infer the type.
10894    const type = ast.value === null || ast.value === undefined || ast.value === true || ast.value === true ? INFERRED_TYPE : undefined;
10895    return convertToStatementIfNeeded(mode, literal(ast.value, type, this.convertSourceSpan(ast.span)));
10896  }
10897  _getLocal(name, receiver) {
10898    if (this._localResolver.globals?.has(name) && receiver instanceof ThisReceiver) {
10899      return null;
10900    }
10901    return this._localResolver.getLocal(name);
10902  }
10903  visitPrefixNot(ast, mode) {
10904    return convertToStatementIfNeeded(mode, not(this._visit(ast.expression, _Mode.Expression)));
10905  }
10906  visitNonNullAssert(ast, mode) {
10907    return convertToStatementIfNeeded(mode, this._visit(ast.expression, _Mode.Expression));
10908  }
10909  visitPropertyRead(ast, mode) {
10910    const leftMostSafe = this.leftMostSafeNode(ast);
10911    if (leftMostSafe) {
10912      return this.convertSafeAccess(ast, leftMostSafe, mode);
10913    } else {
10914      let result = null;
10915      const prevUsesImplicitReceiver = this.usesImplicitReceiver;
10916      const receiver = this._visit(ast.receiver, _Mode.Expression);
10917      if (receiver === this._implicitReceiver) {
10918        result = this._getLocal(ast.name, ast.receiver);
10919        if (result) {
10920          // Restore the previous "usesImplicitReceiver" state since the implicit
10921          // receiver has been replaced with a resolved local expression.
10922          this.usesImplicitReceiver = prevUsesImplicitReceiver;
10923          this.addImplicitReceiverAccess(ast.name);
10924        }
10925      }
10926      if (result == null) {
10927        result = receiver.prop(ast.name, this.convertSourceSpan(ast.span));
10928      }
10929      return convertToStatementIfNeeded(mode, result);
10930    }
10931  }
10932  visitPropertyWrite(ast, mode) {
10933    const receiver = this._visit(ast.receiver, _Mode.Expression);
10934    const prevUsesImplicitReceiver = this.usesImplicitReceiver;
10935    let varExpr = null;
10936    if (receiver === this._implicitReceiver) {
10937      const localExpr = this._getLocal(ast.name, ast.receiver);
10938      if (localExpr) {
10939        if (localExpr instanceof ReadPropExpr) {
10940          // If the local variable is a property read expression, it's a reference
10941          // to a 'context.property' value and will be used as the target of the
10942          // write expression.
10943          varExpr = localExpr;
10944          // Restore the previous "usesImplicitReceiver" state since the implicit
10945          // receiver has been replaced with a resolved local expression.
10946          this.usesImplicitReceiver = prevUsesImplicitReceiver;
10947          this.addImplicitReceiverAccess(ast.name);
10948        } else {
10949          // Otherwise it's an error.
10950          const receiver = ast.name;
10951          const value = ast.value instanceof PropertyRead ? ast.value.name : undefined;
10952          throw new Error(`Cannot assign value "${value}" to template variable "${receiver}". Template variables are read-only.`);
10953        }
10954      }
10955    }
10956    // If no local expression could be produced, use the original receiver's
10957    // property as the target.
10958    if (varExpr === null) {
10959      varExpr = receiver.prop(ast.name, this.convertSourceSpan(ast.span));
10960    }
10961    return convertToStatementIfNeeded(mode, varExpr.set(this._visit(ast.value, _Mode.Expression)));
10962  }
10963  visitSafePropertyRead(ast, mode) {
10964    return this.convertSafeAccess(ast, this.leftMostSafeNode(ast), mode);
10965  }
10966  visitSafeKeyedRead(ast, mode) {
10967    return this.convertSafeAccess(ast, this.leftMostSafeNode(ast), mode);
10968  }
10969  visitAll(asts, mode) {
10970    return asts.map(ast => this._visit(ast, mode));
10971  }
10972  visitCall(ast, mode) {
10973    const leftMostSafe = this.leftMostSafeNode(ast);
10974    if (leftMostSafe) {
10975      return this.convertSafeAccess(ast, leftMostSafe, mode);
10976    }
10977    const convertedArgs = this.visitAll(ast.args, _Mode.Expression);
10978    if (ast instanceof BuiltinFunctionCall) {
10979      return convertToStatementIfNeeded(mode, ast.converter(convertedArgs));
10980    }
10981    const receiver = ast.receiver;
10982    if (receiver instanceof PropertyRead && receiver.receiver instanceof ImplicitReceiver && !(receiver.receiver instanceof ThisReceiver) && receiver.name === '$any') {
10983      if (convertedArgs.length !== 1) {
10984        throw new Error(`Invalid call to $any, expected 1 argument but received ${convertedArgs.length || 'none'}`);
10985      }
10986      return convertToStatementIfNeeded(mode, convertedArgs[0]);
10987    }
10988    const call = this._visit(receiver, _Mode.Expression).callFn(convertedArgs, this.convertSourceSpan(ast.span));
10989    return convertToStatementIfNeeded(mode, call);
10990  }
10991  visitSafeCall(ast, mode) {
10992    return this.convertSafeAccess(ast, this.leftMostSafeNode(ast), mode);
10993  }
10994  _visit(ast, mode) {
10995    const result = this._resultMap.get(ast);
10996    if (result) return result;
10997    return (this._nodeMap.get(ast) || ast).visit(this, mode);
10998  }
10999  convertSafeAccess(ast, leftMostSafe, mode) {
11000    // If the expression contains a safe access node on the left it needs to be converted to
11001    // an expression that guards the access to the member by checking the receiver for blank. As
11002    // execution proceeds from left to right, the left most part of the expression must be guarded
11003    // first but, because member access is left associative, the right side of the expression is at
11004    // the top of the AST. The desired result requires lifting a copy of the left part of the
11005    // expression up to test it for blank before generating the unguarded version.
11006    // Consider, for example the following expression: a?.b.c?.d.e
11007    // This results in the ast:
11008    //         .
11009    //        / \
11010    //       ?.   e
11011    //      /  \
11012    //     .    d
11013    //    / \
11014    //   ?.  c
11015    //  /  \
11016    // a    b
11017    // The following tree should be generated:
11018    //
11019    //        /---- ? ----\
11020    //       /      |      \
11021    //     a   /--- ? ---\  null
11022    //        /     |     \
11023    //       .      .     null
11024    //      / \    / \
11025    //     .  c   .   e
11026    //    / \    / \
11027    //   a   b  .   d
11028    //         / \
11029    //        .   c
11030    //       / \
11031    //      a   b
11032    //
11033    // Notice that the first guard condition is the left hand of the left most safe access node
11034    // which comes in as leftMostSafe to this routine.
11035    let guardedExpression = this._visit(leftMostSafe.receiver, _Mode.Expression);
11036    let temporary = undefined;
11037    if (this.needsTemporaryInSafeAccess(leftMostSafe.receiver)) {
11038      // If the expression has method calls or pipes then we need to save the result into a
11039      // temporary variable to avoid calling stateful or impure code more than once.
11040      temporary = this.allocateTemporary();
11041      // Preserve the result in the temporary variable
11042      guardedExpression = temporary.set(guardedExpression);
11043      // Ensure all further references to the guarded expression refer to the temporary instead.
11044      this._resultMap.set(leftMostSafe.receiver, temporary);
11045    }
11046    const condition = guardedExpression.isBlank();
11047    // Convert the ast to an unguarded access to the receiver's member. The map will substitute
11048    // leftMostNode with its unguarded version in the call to `this.visit()`.
11049    if (leftMostSafe instanceof SafeCall) {
11050      this._nodeMap.set(leftMostSafe, new Call(leftMostSafe.span, leftMostSafe.sourceSpan, leftMostSafe.receiver, leftMostSafe.args, leftMostSafe.argumentSpan));
11051    } else if (leftMostSafe instanceof SafeKeyedRead) {
11052      this._nodeMap.set(leftMostSafe, new KeyedRead(leftMostSafe.span, leftMostSafe.sourceSpan, leftMostSafe.receiver, leftMostSafe.key));
11053    } else {
11054      this._nodeMap.set(leftMostSafe, new PropertyRead(leftMostSafe.span, leftMostSafe.sourceSpan, leftMostSafe.nameSpan, leftMostSafe.receiver, leftMostSafe.name));
11055    }
11056    // Recursively convert the node now without the guarded member access.
11057    const access = this._visit(ast, _Mode.Expression);
11058    // Remove the mapping. This is not strictly required as the converter only traverses each node
11059    // once but is safer if the conversion is changed to traverse the nodes more than once.
11060    this._nodeMap.delete(leftMostSafe);
11061    // If we allocated a temporary, release it.
11062    if (temporary) {
11063      this.releaseTemporary(temporary);
11064    }
11065    // Produce the conditional
11066    return convertToStatementIfNeeded(mode, condition.conditional(NULL_EXPR, access));
11067  }
11068  convertNullishCoalesce(ast, mode) {
11069    const left = this._visit(ast.left, _Mode.Expression);
11070    const right = this._visit(ast.right, _Mode.Expression);
11071    const temporary = this.allocateTemporary();
11072    this.releaseTemporary(temporary);
11073    // Generate the following expression. It is identical to how TS
11074    // transpiles binary expressions with a nullish coalescing operator.
11075    // let temp;
11076    // (temp = a) !== null && temp !== undefined ? temp : b;
11077    return convertToStatementIfNeeded(mode, temporary.set(left).notIdentical(NULL_EXPR).and(temporary.notIdentical(literal(undefined))).conditional(temporary, right));
11078  }
11079  // Given an expression of the form a?.b.c?.d.e then the left most safe node is
11080  // the (a?.b). The . and ?. are left associative thus can be rewritten as:
11081  // ((((a?.c).b).c)?.d).e. This returns the most deeply nested safe read or
11082  // safe method call as this needs to be transformed initially to:
11083  //   a == null ? null : a.c.b.c?.d.e
11084  // then to:
11085  //   a == null ? null : a.b.c == null ? null : a.b.c.d.e
11086  leftMostSafeNode(ast) {
11087    const visit = (visitor, ast) => {
11088      return (this._nodeMap.get(ast) || ast).visit(visitor);
11089    };
11090    return ast.visit({
11091      visitUnary(ast) {
11092        return null;
11093      },
11094      visitBinary(ast) {
11095        return null;
11096      },
11097      visitChain(ast) {
11098        return null;
11099      },
11100      visitConditional(ast) {
11101        return null;
11102      },
11103      visitCall(ast) {
11104        return visit(this, ast.receiver);
11105      },
11106      visitSafeCall(ast) {
11107        return visit(this, ast.receiver) || ast;
11108      },
11109      visitImplicitReceiver(ast) {
11110        return null;
11111      },
11112      visitThisReceiver(ast) {
11113        return null;
11114      },
11115      visitInterpolation(ast) {
11116        return null;
11117      },
11118      visitKeyedRead(ast) {
11119        return visit(this, ast.receiver);
11120      },
11121      visitKeyedWrite(ast) {
11122        return null;
11123      },
11124      visitLiteralArray(ast) {
11125        return null;
11126      },
11127      visitLiteralMap(ast) {
11128        return null;
11129      },
11130      visitLiteralPrimitive(ast) {
11131        return null;
11132      },
11133      visitPipe(ast) {
11134        return null;
11135      },
11136      visitPrefixNot(ast) {
11137        return null;
11138      },
11139      visitNonNullAssert(ast) {
11140        return visit(this, ast.expression);
11141      },
11142      visitPropertyRead(ast) {
11143        return visit(this, ast.receiver);
11144      },
11145      visitPropertyWrite(ast) {
11146        return null;
11147      },
11148      visitSafePropertyRead(ast) {
11149        return visit(this, ast.receiver) || ast;
11150      },
11151      visitSafeKeyedRead(ast) {
11152        return visit(this, ast.receiver) || ast;
11153      }
11154    });
11155  }
11156  // Returns true of the AST includes a method or a pipe indicating that, if the
11157  // expression is used as the target of a safe property or method access then
11158  // the expression should be stored into a temporary variable.
11159  needsTemporaryInSafeAccess(ast) {
11160    const visit = (visitor, ast) => {
11161      return ast && (this._nodeMap.get(ast) || ast).visit(visitor);
11162    };
11163    const visitSome = (visitor, ast) => {
11164      return ast.some(ast => visit(visitor, ast));
11165    };
11166    return ast.visit({
11167      visitUnary(ast) {
11168        return visit(this, ast.expr);
11169      },
11170      visitBinary(ast) {
11171        return visit(this, ast.left) || visit(this, ast.right);
11172      },
11173      visitChain(ast) {
11174        return false;
11175      },
11176      visitConditional(ast) {
11177        return visit(this, ast.condition) || visit(this, ast.trueExp) || visit(this, ast.falseExp);
11178      },
11179      visitCall(ast) {
11180        return true;
11181      },
11182      visitSafeCall(ast) {
11183        return true;
11184      },
11185      visitImplicitReceiver(ast) {
11186        return false;
11187      },
11188      visitThisReceiver(ast) {
11189        return false;
11190      },
11191      visitInterpolation(ast) {
11192        return visitSome(this, ast.expressions);
11193      },
11194      visitKeyedRead(ast) {
11195        return false;
11196      },
11197      visitKeyedWrite(ast) {
11198        return false;
11199      },
11200      visitLiteralArray(ast) {
11201        return true;
11202      },
11203      visitLiteralMap(ast) {
11204        return true;
11205      },
11206      visitLiteralPrimitive(ast) {
11207        return false;
11208      },
11209      visitPipe(ast) {
11210        return true;
11211      },
11212      visitPrefixNot(ast) {
11213        return visit(this, ast.expression);
11214      },
11215      visitNonNullAssert(ast) {
11216        return visit(this, ast.expression);
11217      },
11218      visitPropertyRead(ast) {
11219        return false;
11220      },
11221      visitPropertyWrite(ast) {
11222        return false;
11223      },
11224      visitSafePropertyRead(ast) {
11225        return false;
11226      },
11227      visitSafeKeyedRead(ast) {
11228        return false;
11229      }
11230    });
11231  }
11232  allocateTemporary() {
11233    const tempNumber = this._currentTemporary++;
11234    this.temporaryCount = Math.max(this._currentTemporary, this.temporaryCount);
11235    return new ReadVarExpr(temporaryName(this.bindingId, tempNumber));
11236  }
11237  releaseTemporary(temporary) {
11238    this._currentTemporary--;
11239    if (temporary.name != temporaryName(this.bindingId, this._currentTemporary)) {
11240      throw new Error(`Temporary ${temporary.name} released out of order`);
11241    }
11242  }
11243  /**
11244   * Creates an absolute `ParseSourceSpan` from the relative `ParseSpan`.
11245   *
11246   * `ParseSpan` objects are relative to the start of the expression.
11247   * This method converts these to full `ParseSourceSpan` objects that
11248   * show where the span is within the overall source file.
11249   *
11250   * @param span the relative span to convert.
11251   * @returns a `ParseSourceSpan` for the given span or null if no
11252   * `baseSourceSpan` was provided to this class.
11253   */
11254  convertSourceSpan(span) {
11255    if (this.baseSourceSpan) {
11256      const start = this.baseSourceSpan.start.moveBy(span.start);
11257      const end = this.baseSourceSpan.start.moveBy(span.end);
11258      const fullStart = this.baseSourceSpan.fullStart.moveBy(span.start);
11259      return new ParseSourceSpan(start, end, fullStart);
11260    } else {
11261      return null;
11262    }
11263  }
11264  /** Adds the name of an AST to the list of implicit receiver accesses. */
11265  addImplicitReceiverAccess(name) {
11266    if (this.implicitReceiverAccesses) {
11267      this.implicitReceiverAccesses.add(name);
11268    }
11269  }
11270}
11271function flattenStatements(arg, output) {
11272  if (Array.isArray(arg)) {
11273    arg.forEach(entry => flattenStatements(entry, output));
11274  } else {
11275    output.push(arg);
11276  }
11277}
11278function unsupported() {
11279  throw new Error('Unsupported operation');
11280}
11281class InterpolationExpression extends Expression {
11282  constructor(args) {
11283    super(null, null);
11284    this.args = args;
11285    this.isConstant = unsupported;
11286    this.isEquivalent = unsupported;
11287    this.visitExpression = unsupported;
11288    this.clone = unsupported;
11289  }
11290}
11291class DefaultLocalResolver {
11292  constructor(globals) {
11293    this.globals = globals;
11294  }
11295  notifyImplicitReceiverUse() {}
11296  maybeRestoreView() {}
11297  getLocal(name) {
11298    if (name === EventHandlerVars.event.name) {
11299      return EventHandlerVars.event;
11300    }
11301    return null;
11302  }
11303}
11304class BuiltinFunctionCall extends Call {
11305  constructor(span, sourceSpan, args, converter) {
11306    super(span, sourceSpan, new EmptyExpr$1(span, sourceSpan), args, null);
11307    this.converter = converter;
11308  }
11309}
11310
11311// =================================================================================================
11312// =================================================================================================
11313// =========== S T O P   -  S T O P   -  S T O P   -  S T O P   -  S T O P   -  S T O P  ===========
11314// =================================================================================================
11315// =================================================================================================
11316//
11317//        DO NOT EDIT THIS LIST OF SECURITY SENSITIVE PROPERTIES WITHOUT A SECURITY REVIEW!
11318//                               Reach out to mprobst for details.
11319//
11320// =================================================================================================
11321/** Map from tagName|propertyName to SecurityContext. Properties applying to all tags use '*'. */
11322let _SECURITY_SCHEMA;
11323function SECURITY_SCHEMA() {
11324  if (!_SECURITY_SCHEMA) {
11325    _SECURITY_SCHEMA = {};
11326    // Case is insignificant below, all element and attribute names are lower-cased for lookup.
11327    registerContext(SecurityContext.HTML, ['iframe|srcdoc', '*|innerHTML', '*|outerHTML']);
11328    registerContext(SecurityContext.STYLE, ['*|style']);
11329    // NB: no SCRIPT contexts here, they are never allowed due to the parser stripping them.
11330    registerContext(SecurityContext.URL, ['*|formAction', 'area|href', 'area|ping', 'audio|src', 'a|href', 'a|ping', 'blockquote|cite', 'body|background', 'del|cite', 'form|action', 'img|src', 'input|src', 'ins|cite', 'q|cite', 'source|src', 'track|src', 'video|poster', 'video|src']);
11331    registerContext(SecurityContext.RESOURCE_URL, ['applet|code', 'applet|codebase', 'base|href', 'embed|src', 'frame|src', 'head|profile', 'html|manifest', 'iframe|src', 'link|href', 'media|src', 'object|codebase', 'object|data', 'script|src']);
11332  }
11333  return _SECURITY_SCHEMA;
11334}
11335function registerContext(ctx, specs) {
11336  for (const spec of specs) _SECURITY_SCHEMA[spec.toLowerCase()] = ctx;
11337}
11338/**
11339 * The set of security-sensitive attributes of an `<iframe>` that *must* be
11340 * applied as a static attribute only. This ensures that all security-sensitive
11341 * attributes are taken into account while creating an instance of an `<iframe>`
11342 * at runtime.
11343 *
11344 * Note: avoid using this set directly, use the `isIframeSecuritySensitiveAttr` function
11345 * in the code instead.
11346 */
11347const IFRAME_SECURITY_SENSITIVE_ATTRS = new Set(['sandbox', 'allow', 'allowfullscreen', 'referrerpolicy', 'csp', 'fetchpriority']);
11348/**
11349 * Checks whether a given attribute name might represent a security-sensitive
11350 * attribute of an <iframe>.
11351 */
11352function isIframeSecuritySensitiveAttr(attrName) {
11353  // The `setAttribute` DOM API is case-insensitive, so we lowercase the value
11354  // before checking it against a known security-sensitive attributes.
11355  return IFRAME_SECURITY_SENSITIVE_ATTRS.has(attrName.toLowerCase());
11356}
11357
11358/**
11359 * The following set contains all keywords that can be used in the animation css shorthand
11360 * property and is used during the scoping of keyframes to make sure such keywords
11361 * are not modified.
11362 */
11363const animationKeywords = new Set([
11364// global values
11365'inherit', 'initial', 'revert', 'unset',
11366// animation-direction
11367'alternate', 'alternate-reverse', 'normal', 'reverse',
11368// animation-fill-mode
11369'backwards', 'both', 'forwards', 'none',
11370// animation-play-state
11371'paused', 'running',
11372// animation-timing-function
11373'ease', 'ease-in', 'ease-in-out', 'ease-out', 'linear', 'step-start', 'step-end',
11374// `steps()` function
11375'end', 'jump-both', 'jump-end', 'jump-none', 'jump-start', 'start']);
11376/**
11377 * The following array contains all of the CSS at-rule identifiers which are scoped.
11378 */
11379const scopedAtRuleIdentifiers = ['@media', '@supports', '@document', '@layer', '@container', '@scope', '@starting-style'];
11380/**
11381 * The following class has its origin from a port of shadowCSS from webcomponents.js to TypeScript.
11382 * It has since diverge in many ways to tailor Angular's needs.
11383 *
11384 * Source:
11385 * https://github.com/webcomponents/webcomponentsjs/blob/4efecd7e0e/src/ShadowCSS/ShadowCSS.js
11386 *
11387 * The original file level comment is reproduced below
11388 */
11389/*
11390  This is a limited shim for ShadowDOM css styling.
11391  https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#styles
11392
11393  The intention here is to support only the styling features which can be
11394  relatively simply implemented. The goal is to allow users to avoid the
11395  most obvious pitfalls and do so without compromising performance significantly.
11396  For ShadowDOM styling that's not covered here, a set of best practices
11397  can be provided that should allow users to accomplish more complex styling.
11398
11399  The following is a list of specific ShadowDOM styling features and a brief
11400  discussion of the approach used to shim.
11401
11402  Shimmed features:
11403
11404  * :host, :host-context: ShadowDOM allows styling of the shadowRoot's host
11405  element using the :host rule. To shim this feature, the :host styles are
11406  reformatted and prefixed with a given scope name and promoted to a
11407  document level stylesheet.
11408  For example, given a scope name of .foo, a rule like this:
11409
11410    :host {
11411        background: red;
11412      }
11413    }
11414
11415  becomes:
11416
11417    .foo {
11418      background: red;
11419    }
11420
11421  * encapsulation: Styles defined within ShadowDOM, apply only to
11422  dom inside the ShadowDOM.
11423  The selectors are scoped by adding an attribute selector suffix to each
11424  simple selector that contains the host element tag name. Each element
11425  in the element's ShadowDOM template is also given the scope attribute.
11426  Thus, these rules match only elements that have the scope attribute.
11427  For example, given a scope name of x-foo, a rule like this:
11428
11429    div {
11430      font-weight: bold;
11431    }
11432
11433  becomes:
11434
11435    div[x-foo] {
11436      font-weight: bold;
11437    }
11438
11439  Note that elements that are dynamically added to a scope must have the scope
11440  selector added to them manually.
11441
11442  * upper/lower bound encapsulation: Styles which are defined outside a
11443  shadowRoot should not cross the ShadowDOM boundary and should not apply
11444  inside a shadowRoot.
11445
11446  This styling behavior is not emulated. Some possible ways to do this that
11447  were rejected due to complexity and/or performance concerns include: (1) reset
11448  every possible property for every possible selector for a given scope name;
11449  (2) re-implement css in javascript.
11450
11451  As an alternative, users should make sure to use selectors
11452  specific to the scope in which they are working.
11453
11454  * ::distributed: This behavior is not emulated. It's often not necessary
11455  to style the contents of a specific insertion point and instead, descendants
11456  of the host element can be styled selectively. Users can also create an
11457  extra node around an insertion point and style that node's contents
11458  via descendent selectors. For example, with a shadowRoot like this:
11459
11460    <style>
11461      ::content(div) {
11462        background: red;
11463      }
11464    </style>
11465    <content></content>
11466
11467  could become:
11468
11469    <style>
11470      / *@polyfill .content-container div * /
11471      ::content(div) {
11472        background: red;
11473      }
11474    </style>
11475    <div class="content-container">
11476      <content></content>
11477    </div>
11478
11479  Note the use of @polyfill in the comment above a ShadowDOM specific style
11480  declaration. This is a directive to the styling shim to use the selector
11481  in comments in lieu of the next selector when running under polyfill.
11482*/
11483class ShadowCss {
11484  constructor() {
11485    /**
11486     * Regular expression used to extrapolate the possible keyframes from an
11487     * animation declaration (with possibly multiple animation definitions)
11488     *
11489     * The regular expression can be divided in three parts
11490     *  - (^|\s+)
11491     *    simply captures how many (if any) leading whitespaces are present
11492     *  - (?:(?:(['"])((?:\\\\|\\\2|(?!\2).)+)\2)|(-?[A-Za-z][\w\-]*))
11493     *    captures two different possible keyframes, ones which are quoted or ones which are valid css
11494     * idents (custom properties excluded)
11495     *  - (?=[,\s;]|$)
11496     *    simply matches the end of the possible keyframe, valid endings are: a comma, a space, a
11497     * semicolon or the end of the string
11498     */
11499    this._animationDeclarationKeyframesRe = /(^|\s+)(?:(?:(['"])((?:\\\\|\\\2|(?!\2).)+)\2)|(-?[A-Za-z][\w\-]*))(?=[,\s]|$)/g;
11500  }
11501  /*
11502   * Shim some cssText with the given selector. Returns cssText that can be included in the document
11503   *
11504   * The selector is the attribute added to all elements inside the host,
11505   * The hostSelector is the attribute added to the host itself.
11506   */
11507  shimCssText(cssText, selector, hostSelector = '') {
11508    // **NOTE**: Do not strip comments as this will cause component sourcemaps to break
11509    // due to shift in lines.
11510    // Collect comments and replace them with a placeholder, this is done to avoid complicating
11511    // the rule parsing RegExp and keep it safer.
11512    const comments = [];
11513    cssText = cssText.replace(_commentRe, m => {
11514      if (m.match(_commentWithHashRe)) {
11515        comments.push(m);
11516      } else {
11517        // Replace non hash comments with empty lines.
11518        // This is done so that we do not leak any senstive data in comments.
11519        const newLinesMatches = m.match(_newLinesRe);
11520        comments.push((newLinesMatches?.join('') ?? '') + '\n');
11521      }
11522      return COMMENT_PLACEHOLDER;
11523    });
11524    cssText = this._insertDirectives(cssText);
11525    const scopedCssText = this._scopeCssText(cssText, selector, hostSelector);
11526    // Add back comments at the original position.
11527    let commentIdx = 0;
11528    return scopedCssText.replace(_commentWithHashPlaceHolderRe, () => comments[commentIdx++]);
11529  }
11530  _insertDirectives(cssText) {
11531    cssText = this._insertPolyfillDirectivesInCssText(cssText);
11532    return this._insertPolyfillRulesInCssText(cssText);
11533  }
11534  /**
11535   * Process styles to add scope to keyframes.
11536   *
11537   * Modify both the names of the keyframes defined in the component styles and also the css
11538   * animation rules using them.
11539   *
11540   * Animation rules using keyframes defined elsewhere are not modified to allow for globally
11541   * defined keyframes.
11542   *
11543   * For example, we convert this css:
11544   *
11545   * ```
11546   * .box {
11547   *   animation: box-animation 1s forwards;
11548   * }
11549   *
11550   * @keyframes box-animation {
11551   *   to {
11552   *     background-color: green;
11553   *   }
11554   * }
11555   * ```
11556   *
11557   * to this:
11558   *
11559   * ```
11560   * .box {
11561   *   animation: scopeName_box-animation 1s forwards;
11562   * }
11563   *
11564   * @keyframes scopeName_box-animation {
11565   *   to {
11566   *     background-color: green;
11567   *   }
11568   * }
11569   * ```
11570   *
11571   * @param cssText the component's css text that needs to be scoped.
11572   * @param scopeSelector the component's scope selector.
11573   *
11574   * @returns the scoped css text.
11575   */
11576  _scopeKeyframesRelatedCss(cssText, scopeSelector) {
11577    const unscopedKeyframesSet = new Set();
11578    const scopedKeyframesCssText = processRules(cssText, rule => this._scopeLocalKeyframeDeclarations(rule, scopeSelector, unscopedKeyframesSet));
11579    return processRules(scopedKeyframesCssText, rule => this._scopeAnimationRule(rule, scopeSelector, unscopedKeyframesSet));
11580  }
11581  /**
11582   * Scopes local keyframes names, returning the updated css rule and it also
11583   * adds the original keyframe name to a provided set to collect all keyframes names
11584   * so that it can later be used to scope the animation rules.
11585   *
11586   * For example, it takes a rule such as:
11587   *
11588   * ```
11589   * @keyframes box-animation {
11590   *   to {
11591   *     background-color: green;
11592   *   }
11593   * }
11594   * ```
11595   *
11596   * and returns:
11597   *
11598   * ```
11599   * @keyframes scopeName_box-animation {
11600   *   to {
11601   *     background-color: green;
11602   *   }
11603   * }
11604   * ```
11605   * and as a side effect it adds "box-animation" to the `unscopedKeyframesSet` set
11606   *
11607   * @param cssRule the css rule to process.
11608   * @param scopeSelector the component's scope selector.
11609   * @param unscopedKeyframesSet the set of unscoped keyframes names (which can be
11610   * modified as a side effect)
11611   *
11612   * @returns the css rule modified with the scoped keyframes name.
11613   */
11614  _scopeLocalKeyframeDeclarations(rule, scopeSelector, unscopedKeyframesSet) {
11615    return {
11616      ...rule,
11617      selector: rule.selector.replace(/(^@(?:-webkit-)?keyframes(?:\s+))(['"]?)(.+)\2(\s*)$/, (_, start, quote, keyframeName, endSpaces) => {
11618        unscopedKeyframesSet.add(unescapeQuotes(keyframeName, quote));
11619        return `${start}${quote}${scopeSelector}_${keyframeName}${quote}${endSpaces}`;
11620      })
11621    };
11622  }
11623  /**
11624   * Function used to scope a keyframes name (obtained from an animation declaration)
11625   * using an existing set of unscopedKeyframes names to discern if the scoping needs to be
11626   * performed (keyframes names of keyframes not defined in the component's css need not to be
11627   * scoped).
11628   *
11629   * @param keyframe the keyframes name to check.
11630   * @param scopeSelector the component's scope selector.
11631   * @param unscopedKeyframesSet the set of unscoped keyframes names.
11632   *
11633   * @returns the scoped name of the keyframe, or the original name is the name need not to be
11634   * scoped.
11635   */
11636  _scopeAnimationKeyframe(keyframe, scopeSelector, unscopedKeyframesSet) {
11637    return keyframe.replace(/^(\s*)(['"]?)(.+?)\2(\s*)$/, (_, spaces1, quote, name, spaces2) => {
11638      name = `${unscopedKeyframesSet.has(unescapeQuotes(name, quote)) ? scopeSelector + '_' : ''}${name}`;
11639      return `${spaces1}${quote}${name}${quote}${spaces2}`;
11640    });
11641  }
11642  /**
11643   * Scope an animation rule so that the keyframes mentioned in such rule
11644   * are scoped if defined in the component's css and left untouched otherwise.
11645   *
11646   * It can scope values of both the 'animation' and 'animation-name' properties.
11647   *
11648   * @param rule css rule to scope.
11649   * @param scopeSelector the component's scope selector.
11650   * @param unscopedKeyframesSet the set of unscoped keyframes names.
11651   *
11652   * @returns the updated css rule.
11653   **/
11654  _scopeAnimationRule(rule, scopeSelector, unscopedKeyframesSet) {
11655    let content = rule.content.replace(/((?:^|\s+|;)(?:-webkit-)?animation(?:\s*):(?:\s*))([^;]+)/g, (_, start, animationDeclarations) => start + animationDeclarations.replace(this._animationDeclarationKeyframesRe, (original, leadingSpaces, quote = '', quotedName, nonQuotedName) => {
11656      if (quotedName) {
11657        return `${leadingSpaces}${this._scopeAnimationKeyframe(`${quote}${quotedName}${quote}`, scopeSelector, unscopedKeyframesSet)}`;
11658      } else {
11659        return animationKeywords.has(nonQuotedName) ? original : `${leadingSpaces}${this._scopeAnimationKeyframe(nonQuotedName, scopeSelector, unscopedKeyframesSet)}`;
11660      }
11661    }));
11662    content = content.replace(/((?:^|\s+|;)(?:-webkit-)?animation-name(?:\s*):(?:\s*))([^;]+)/g, (_match, start, commaSeparatedKeyframes) => `${start}${commaSeparatedKeyframes.split(',').map(keyframe => this._scopeAnimationKeyframe(keyframe, scopeSelector, unscopedKeyframesSet)).join(',')}`);
11663    return {
11664      ...rule,
11665      content
11666    };
11667  }
11668  /*
11669   * Process styles to convert native ShadowDOM rules that will trip
11670   * up the css parser; we rely on decorating the stylesheet with inert rules.
11671   *
11672   * For example, we convert this rule:
11673   *
11674   * polyfill-next-selector { content: ':host menu-item'; }
11675   * ::content menu-item {
11676   *
11677   * to this:
11678   *
11679   * scopeName menu-item {
11680   *
11681   **/
11682  _insertPolyfillDirectivesInCssText(cssText) {
11683    return cssText.replace(_cssContentNextSelectorRe, function (...m) {
11684      return m[2] + '{';
11685    });
11686  }
11687  /*
11688   * Process styles to add rules which will only apply under the polyfill
11689   *
11690   * For example, we convert this rule:
11691   *
11692   * polyfill-rule {
11693   *   content: ':host menu-item';
11694   * ...
11695   * }
11696   *
11697   * to this:
11698   *
11699   * scopeName menu-item {...}
11700   *
11701   **/
11702  _insertPolyfillRulesInCssText(cssText) {
11703    return cssText.replace(_cssContentRuleRe, (...m) => {
11704      const rule = m[0].replace(m[1], '').replace(m[2], '');
11705      return m[4] + rule;
11706    });
11707  }
11708  /* Ensure styles are scoped. Pseudo-scoping takes a rule like:
11709   *
11710   *  .foo {... }
11711   *
11712   *  and converts this to
11713   *
11714   *  scopeName .foo { ... }
11715   */
11716  _scopeCssText(cssText, scopeSelector, hostSelector) {
11717    const unscopedRules = this._extractUnscopedRulesFromCssText(cssText);
11718    // replace :host and :host-context -shadowcsshost and -shadowcsshost respectively
11719    cssText = this._insertPolyfillHostInCssText(cssText);
11720    cssText = this._convertColonHost(cssText);
11721    cssText = this._convertColonHostContext(cssText);
11722    cssText = this._convertShadowDOMSelectors(cssText);
11723    if (scopeSelector) {
11724      cssText = this._scopeKeyframesRelatedCss(cssText, scopeSelector);
11725      cssText = this._scopeSelectors(cssText, scopeSelector, hostSelector);
11726    }
11727    cssText = cssText + '\n' + unscopedRules;
11728    return cssText.trim();
11729  }
11730  /*
11731   * Process styles to add rules which will only apply under the polyfill
11732   * and do not process via CSSOM. (CSSOM is destructive to rules on rare
11733   * occasions, e.g. -webkit-calc on Safari.)
11734   * For example, we convert this rule:
11735   *
11736   * @polyfill-unscoped-rule {
11737   *   content: 'menu-item';
11738   * ... }
11739   *
11740   * to this:
11741   *
11742   * menu-item {...}
11743   *
11744   **/
11745  _extractUnscopedRulesFromCssText(cssText) {
11746    let r = '';
11747    let m;
11748    _cssContentUnscopedRuleRe.lastIndex = 0;
11749    while ((m = _cssContentUnscopedRuleRe.exec(cssText)) !== null) {
11750      const rule = m[0].replace(m[2], '').replace(m[1], m[4]);
11751      r += rule + '\n\n';
11752    }
11753    return r;
11754  }
11755  /*
11756   * convert a rule like :host(.foo) > .bar { }
11757   *
11758   * to
11759   *
11760   * .foo<scopeName> > .bar
11761   */
11762  _convertColonHost(cssText) {
11763    return cssText.replace(_cssColonHostRe, (_, hostSelectors, otherSelectors) => {
11764      if (hostSelectors) {
11765        const convertedSelectors = [];
11766        const hostSelectorArray = hostSelectors.split(',').map(p => p.trim());
11767        for (const hostSelector of hostSelectorArray) {
11768          if (!hostSelector) break;
11769          const convertedSelector = _polyfillHostNoCombinator + hostSelector.replace(_polyfillHost, '') + otherSelectors;
11770          convertedSelectors.push(convertedSelector);
11771        }
11772        return convertedSelectors.join(',');
11773      } else {
11774        return _polyfillHostNoCombinator + otherSelectors;
11775      }
11776    });
11777  }
11778  /*
11779   * convert a rule like :host-context(.foo) > .bar { }
11780   *
11781   * to
11782   *
11783   * .foo<scopeName> > .bar, .foo <scopeName> > .bar { }
11784   *
11785   * and
11786   *
11787   * :host-context(.foo:host) .bar { ... }
11788   *
11789   * to
11790   *
11791   * .foo<scopeName> .bar { ... }
11792   */
11793  _convertColonHostContext(cssText) {
11794    return cssText.replace(_cssColonHostContextReGlobal, selectorText => {
11795      // We have captured a selector that contains a `:host-context` rule.
11796      // For backward compatibility `:host-context` may contain a comma separated list of selectors.
11797      // Each context selector group will contain a list of host-context selectors that must match
11798      // an ancestor of the host.
11799      // (Normally `contextSelectorGroups` will only contain a single array of context selectors.)
11800      const contextSelectorGroups = [[]];
11801      // There may be more than `:host-context` in this selector so `selectorText` could look like:
11802      // `:host-context(.one):host-context(.two)`.
11803      // Execute `_cssColonHostContextRe` over and over until we have extracted all the
11804      // `:host-context` selectors from this selector.
11805      let match;
11806      while (match = _cssColonHostContextRe.exec(selectorText)) {
11807        // `match` = [':host-context(<selectors>)<rest>', <selectors>, <rest>]
11808        // The `<selectors>` could actually be a comma separated list: `:host-context(.one, .two)`.
11809        const newContextSelectors = (match[1] ?? '').trim().split(',').map(m => m.trim()).filter(m => m !== '');
11810        // We must duplicate the current selector group for each of these new selectors.
11811        // For example if the current groups are:
11812        // ```
11813        // [
11814        //   ['a', 'b', 'c'],
11815        //   ['x', 'y', 'z'],
11816        // ]
11817        // ```
11818        // And we have a new set of comma separated selectors: `:host-context(m,n)` then the new
11819        // groups are:
11820        // ```
11821        // [
11822        //   ['a', 'b', 'c', 'm'],
11823        //   ['x', 'y', 'z', 'm'],
11824        //   ['a', 'b', 'c', 'n'],
11825        //   ['x', 'y', 'z', 'n'],
11826        // ]
11827        // ```
11828        const contextSelectorGroupsLength = contextSelectorGroups.length;
11829        repeatGroups(contextSelectorGroups, newContextSelectors.length);
11830        for (let i = 0; i < newContextSelectors.length; i++) {
11831          for (let j = 0; j < contextSelectorGroupsLength; j++) {
11832            contextSelectorGroups[j + i * contextSelectorGroupsLength].push(newContextSelectors[i]);
11833          }
11834        }
11835        // Update the `selectorText` and see repeat to see if there are more `:host-context`s.
11836        selectorText = match[2];
11837      }
11838      // The context selectors now must be combined with each other to capture all the possible
11839      // selectors that `:host-context` can match. See `combineHostContextSelectors()` for more
11840      // info about how this is done.
11841      return contextSelectorGroups.map(contextSelectors => combineHostContextSelectors(contextSelectors, selectorText)).join(', ');
11842    });
11843  }
11844  /*
11845   * Convert combinators like ::shadow and pseudo-elements like ::content
11846   * by replacing with space.
11847   */
11848  _convertShadowDOMSelectors(cssText) {
11849    return _shadowDOMSelectorsRe.reduce((result, pattern) => result.replace(pattern, ' '), cssText);
11850  }
11851  // change a selector like 'div' to 'name div'
11852  _scopeSelectors(cssText, scopeSelector, hostSelector) {
11853    return processRules(cssText, rule => {
11854      let selector = rule.selector;
11855      let content = rule.content;
11856      if (rule.selector[0] !== '@') {
11857        selector = this._scopeSelector(rule.selector, scopeSelector, hostSelector);
11858      } else if (scopedAtRuleIdentifiers.some(atRule => rule.selector.startsWith(atRule))) {
11859        content = this._scopeSelectors(rule.content, scopeSelector, hostSelector);
11860      } else if (rule.selector.startsWith('@font-face') || rule.selector.startsWith('@page')) {
11861        content = this._stripScopingSelectors(rule.content);
11862      }
11863      return new CssRule(selector, content);
11864    });
11865  }
11866  /**
11867   * Handle a css text that is within a rule that should not contain scope selectors by simply
11868   * removing them! An example of such a rule is `@font-face`.
11869   *
11870   * `@font-face` rules cannot contain nested selectors. Nor can they be nested under a selector.
11871   * Normally this would be a syntax error by the author of the styles. But in some rare cases, such
11872   * as importing styles from a library, and applying `:host ::ng-deep` to the imported styles, we
11873   * can end up with broken css if the imported styles happen to contain @font-face rules.
11874   *
11875   * For example:
11876   *
11877   * ```
11878   * :host ::ng-deep {
11879   *   import 'some/lib/containing/font-face';
11880   * }
11881   *
11882   * Similar logic applies to `@page` rules which can contain a particular set of properties,
11883   * as well as some specific at-rules. Since they can't be encapsulated, we have to strip
11884   * any scoping selectors from them. For more information: https://www.w3.org/TR/css-page-3
11885   * ```
11886   */
11887  _stripScopingSelectors(cssText) {
11888    return processRules(cssText, rule => {
11889      const selector = rule.selector.replace(_shadowDeepSelectors, ' ').replace(_polyfillHostNoCombinatorRe, ' ');
11890      return new CssRule(selector, rule.content);
11891    });
11892  }
11893  _scopeSelector(selector, scopeSelector, hostSelector) {
11894    return selector.split(',').map(part => part.trim().split(_shadowDeepSelectors)).map(deepParts => {
11895      const [shallowPart, ...otherParts] = deepParts;
11896      const applyScope = shallowPart => {
11897        if (this._selectorNeedsScoping(shallowPart, scopeSelector)) {
11898          return this._applySelectorScope(shallowPart, scopeSelector, hostSelector);
11899        } else {
11900          return shallowPart;
11901        }
11902      };
11903      return [applyScope(shallowPart), ...otherParts].join(' ');
11904    }).join(', ');
11905  }
11906  _selectorNeedsScoping(selector, scopeSelector) {
11907    const re = this._makeScopeMatcher(scopeSelector);
11908    return !re.test(selector);
11909  }
11910  _makeScopeMatcher(scopeSelector) {
11911    const lre = /\[/g;
11912    const rre = /\]/g;
11913    scopeSelector = scopeSelector.replace(lre, '\\[').replace(rre, '\\]');
11914    return new RegExp('^(' + scopeSelector + ')' + _selectorReSuffix, 'm');
11915  }
11916  // scope via name and [is=name]
11917  _applySimpleSelectorScope(selector, scopeSelector, hostSelector) {
11918    // In Android browser, the lastIndex is not reset when the regex is used in String.replace()
11919    _polyfillHostRe.lastIndex = 0;
11920    if (_polyfillHostRe.test(selector)) {
11921      const replaceBy = `[${hostSelector}]`;
11922      return selector.replace(_polyfillHostNoCombinatorRe, (hnc, selector) => {
11923        return selector.replace(/([^:]*)(:*)(.*)/, (_, before, colon, after) => {
11924          return before + replaceBy + colon + after;
11925        });
11926      }).replace(_polyfillHostRe, replaceBy + ' ');
11927    }
11928    return scopeSelector + ' ' + selector;
11929  }
11930  // return a selector with [name] suffix on each simple selector
11931  // e.g. .foo.bar > .zot becomes .foo[name].bar[name] > .zot[name]  /** @internal */
11932  _applySelectorScope(selector, scopeSelector, hostSelector) {
11933    const isRe = /\[is=([^\]]*)\]/g;
11934    scopeSelector = scopeSelector.replace(isRe, (_, ...parts) => parts[0]);
11935    const attrName = '[' + scopeSelector + ']';
11936    const _scopeSelectorPart = p => {
11937      let scopedP = p.trim();
11938      if (!scopedP) {
11939        return '';
11940      }
11941      if (p.indexOf(_polyfillHostNoCombinator) > -1) {
11942        scopedP = this._applySimpleSelectorScope(p, scopeSelector, hostSelector);
11943      } else {
11944        // remove :host since it should be unnecessary
11945        const t = p.replace(_polyfillHostRe, '');
11946        if (t.length > 0) {
11947          const matches = t.match(/([^:]*)(:*)(.*)/);
11948          if (matches) {
11949            scopedP = matches[1] + attrName + matches[2] + matches[3];
11950          }
11951        }
11952      }
11953      return scopedP;
11954    };
11955    const safeContent = new SafeSelector(selector);
11956    selector = safeContent.content();
11957    let scopedSelector = '';
11958    let startIndex = 0;
11959    let res;
11960    const sep = /( |>|\+|~(?!=))\s*/g;
11961    // If a selector appears before :host it should not be shimmed as it
11962    // matches on ancestor elements and not on elements in the host's shadow
11963    // `:host-context(div)` is transformed to
11964    // `-shadowcsshost-no-combinatordiv, div -shadowcsshost-no-combinator`
11965    // the `div` is not part of the component in the 2nd selectors and should not be scoped.
11966    // Historically `component-tag:host` was matching the component so we also want to preserve
11967    // this behavior to avoid breaking legacy apps (it should not match).
11968    // The behavior should be:
11969    // - `tag:host` -> `tag[h]` (this is to avoid breaking legacy apps, should not match anything)
11970    // - `tag :host` -> `tag [h]` (`tag` is not scoped because it's considered part of a
11971    //   `:host-context(tag)`)
11972    const hasHost = selector.indexOf(_polyfillHostNoCombinator) > -1;
11973    // Only scope parts after the first `-shadowcsshost-no-combinator` when it is present
11974    let shouldScope = !hasHost;
11975    while ((res = sep.exec(selector)) !== null) {
11976      const separator = res[1];
11977      const part = selector.slice(startIndex, res.index).trim();
11978      // A space following an escaped hex value and followed by another hex character
11979      // (ie: ".\fc ber" for ".über") is not a separator between 2 selectors
11980      // also keep in mind that backslashes are replaced by a placeholder by SafeSelector
11981      // These escaped selectors happen for example when esbuild runs with optimization.minify.
11982      if (part.match(/__esc-ph-(\d+)__/) && selector[res.index + 1]?.match(/[a-fA-F\d]/)) {
11983        continue;
11984      }
11985      shouldScope = shouldScope || part.indexOf(_polyfillHostNoCombinator) > -1;
11986      const scopedPart = shouldScope ? _scopeSelectorPart(part) : part;
11987      scopedSelector += `${scopedPart} ${separator} `;
11988      startIndex = sep.lastIndex;
11989    }
11990    const part = selector.substring(startIndex);
11991    shouldScope = shouldScope || part.indexOf(_polyfillHostNoCombinator) > -1;
11992    scopedSelector += shouldScope ? _scopeSelectorPart(part) : part;
11993    // replace the placeholders with their original values
11994    return safeContent.restore(scopedSelector);
11995  }
11996  _insertPolyfillHostInCssText(selector) {
11997    return selector.replace(_colonHostContextRe, _polyfillHostContext).replace(_colonHostRe, _polyfillHost);
11998  }
11999}
12000class SafeSelector {
12001  constructor(selector) {
12002    this.placeholders = [];
12003    this.index = 0;
12004    // Replaces attribute selectors with placeholders.
12005    // The WS in [attr="va lue"] would otherwise be interpreted as a selector separator.
12006    selector = this._escapeRegexMatches(selector, /(\[[^\]]*\])/g);
12007    // CSS allows for certain special characters to be used in selectors if they're escaped.
12008    // E.g. `.foo:blue` won't match a class called `foo:blue`, because the colon denotes a
12009    // pseudo-class, but writing `.foo\:blue` will match, because the colon was escaped.
12010    // Replace all escape sequences (`\` followed by a character) with a placeholder so
12011    // that our handling of pseudo-selectors doesn't mess with them.
12012    // Escaped characters have a specific placeholder so they can be detected separately.
12013    selector = selector.replace(/(\\.)/g, (_, keep) => {
12014      const replaceBy = `__esc-ph-${this.index}__`;
12015      this.placeholders.push(keep);
12016      this.index++;
12017      return replaceBy;
12018    });
12019    // Replaces the expression in `:nth-child(2n + 1)` with a placeholder.
12020    // WS and "+" would otherwise be interpreted as selector separators.
12021    this._content = selector.replace(/(:nth-[-\w]+)(\([^)]+\))/g, (_, pseudo, exp) => {
12022      const replaceBy = `__ph-${this.index}__`;
12023      this.placeholders.push(exp);
12024      this.index++;
12025      return pseudo + replaceBy;
12026    });
12027  }
12028  restore(content) {
12029    return content.replace(/__(?:ph|esc-ph)-(\d+)__/g, (_ph, index) => this.placeholders[+index]);
12030  }
12031  content() {
12032    return this._content;
12033  }
12034  /**
12035   * Replaces all of the substrings that match a regex within a
12036   * special string (e.g. `__ph-0__`, `__ph-1__`, etc).
12037   */
12038  _escapeRegexMatches(content, pattern) {
12039    return content.replace(pattern, (_, keep) => {
12040      const replaceBy = `__ph-${this.index}__`;
12041      this.placeholders.push(keep);
12042      this.index++;
12043      return replaceBy;
12044    });
12045  }
12046}
12047const _cssContentNextSelectorRe = /polyfill-next-selector[^}]*content:[\s]*?(['"])(.*?)\1[;\s]*}([^{]*?){/gim;
12048const _cssContentRuleRe = /(polyfill-rule)[^}]*(content:[\s]*(['"])(.*?)\3)[;\s]*[^}]*}/gim;
12049const _cssContentUnscopedRuleRe = /(polyfill-unscoped-rule)[^}]*(content:[\s]*(['"])(.*?)\3)[;\s]*[^}]*}/gim;
12050const _polyfillHost = '-shadowcsshost';
12051// note: :host-context pre-processed to -shadowcsshostcontext.
12052const _polyfillHostContext = '-shadowcsscontext';
12053const _parenSuffix = '(?:\\((' + '(?:\\([^)(]*\\)|[^)(]*)+?' + ')\\))?([^,{]*)';
12054const _cssColonHostRe = new RegExp(_polyfillHost + _parenSuffix, 'gim');
12055const _cssColonHostContextReGlobal = new RegExp(_polyfillHostContext + _parenSuffix, 'gim');
12056const _cssColonHostContextRe = new RegExp(_polyfillHostContext + _parenSuffix, 'im');
12057const _polyfillHostNoCombinator = _polyfillHost + '-no-combinator';
12058const _polyfillHostNoCombinatorRe = /-shadowcsshost-no-combinator([^\s]*)/;
12059const _shadowDOMSelectorsRe = [/::shadow/g, /::content/g,
12060// Deprecated selectors
12061/\/shadow-deep\//g, /\/shadow\//g];
12062// The deep combinator is deprecated in the CSS spec
12063// Support for `>>>`, `deep`, `::ng-deep` is then also deprecated and will be removed in the future.
12064// see https://github.com/angular/angular/pull/17677
12065const _shadowDeepSelectors = /(?:>>>)|(?:\/deep\/)|(?:::ng-deep)/g;
12066const _selectorReSuffix = '([>\\s~+[.,{:][\\s\\S]*)?$';
12067const _polyfillHostRe = /-shadowcsshost/gim;
12068const _colonHostRe = /:host/gim;
12069const _colonHostContextRe = /:host-context/gim;
12070const _newLinesRe = /\r?\n/g;
12071const _commentRe = /\/\*[\s\S]*?\*\//g;
12072const _commentWithHashRe = /\/\*\s*#\s*source(Mapping)?URL=/g;
12073const COMMENT_PLACEHOLDER = '%COMMENT%';
12074const _commentWithHashPlaceHolderRe = new RegExp(COMMENT_PLACEHOLDER, 'g');
12075const BLOCK_PLACEHOLDER = '%BLOCK%';
12076const _ruleRe = new RegExp(`(\\s*(?:${COMMENT_PLACEHOLDER}\\s*)*)([^;\\{\\}]+?)(\\s*)((?:{%BLOCK%}?\\s*;?)|(?:\\s*;))`, 'g');
12077const CONTENT_PAIRS = new Map([['{', '}']]);
12078const COMMA_IN_PLACEHOLDER = '%COMMA_IN_PLACEHOLDER%';
12079const SEMI_IN_PLACEHOLDER = '%SEMI_IN_PLACEHOLDER%';
12080const COLON_IN_PLACEHOLDER = '%COLON_IN_PLACEHOLDER%';
12081const _cssCommaInPlaceholderReGlobal = new RegExp(COMMA_IN_PLACEHOLDER, 'g');
12082const _cssSemiInPlaceholderReGlobal = new RegExp(SEMI_IN_PLACEHOLDER, 'g');
12083const _cssColonInPlaceholderReGlobal = new RegExp(COLON_IN_PLACEHOLDER, 'g');
12084class CssRule {
12085  constructor(selector, content) {
12086    this.selector = selector;
12087    this.content = content;
12088  }
12089}
12090function processRules(input, ruleCallback) {
12091  const escaped = escapeInStrings(input);
12092  const inputWithEscapedBlocks = escapeBlocks(escaped, CONTENT_PAIRS, BLOCK_PLACEHOLDER);
12093  let nextBlockIndex = 0;
12094  const escapedResult = inputWithEscapedBlocks.escapedString.replace(_ruleRe, (...m) => {
12095    const selector = m[2];
12096    let content = '';
12097    let suffix = m[4];
12098    let contentPrefix = '';
12099    if (suffix && suffix.startsWith('{' + BLOCK_PLACEHOLDER)) {
12100      content = inputWithEscapedBlocks.blocks[nextBlockIndex++];
12101      suffix = suffix.substring(BLOCK_PLACEHOLDER.length + 1);
12102      contentPrefix = '{';
12103    }
12104    const rule = ruleCallback(new CssRule(selector, content));
12105    return `${m[1]}${rule.selector}${m[3]}${contentPrefix}${rule.content}${suffix}`;
12106  });
12107  return unescapeInStrings(escapedResult);
12108}
12109class StringWithEscapedBlocks {
12110  constructor(escapedString, blocks) {
12111    this.escapedString = escapedString;
12112    this.blocks = blocks;
12113  }
12114}
12115function escapeBlocks(input, charPairs, placeholder) {
12116  const resultParts = [];
12117  const escapedBlocks = [];
12118  let openCharCount = 0;
12119  let nonBlockStartIndex = 0;
12120  let blockStartIndex = -1;
12121  let openChar;
12122  let closeChar;
12123  for (let i = 0; i < input.length; i++) {
12124    const char = input[i];
12125    if (char === '\\') {
12126      i++;
12127    } else if (char === closeChar) {
12128      openCharCount--;
12129      if (openCharCount === 0) {
12130        escapedBlocks.push(input.substring(blockStartIndex, i));
12131        resultParts.push(placeholder);
12132        nonBlockStartIndex = i;
12133        blockStartIndex = -1;
12134        openChar = closeChar = undefined;
12135      }
12136    } else if (char === openChar) {
12137      openCharCount++;
12138    } else if (openCharCount === 0 && charPairs.has(char)) {
12139      openChar = char;
12140      closeChar = charPairs.get(char);
12141      openCharCount = 1;
12142      blockStartIndex = i + 1;
12143      resultParts.push(input.substring(nonBlockStartIndex, blockStartIndex));
12144    }
12145  }
12146  if (blockStartIndex !== -1) {
12147    escapedBlocks.push(input.substring(blockStartIndex));
12148    resultParts.push(placeholder);
12149  } else {
12150    resultParts.push(input.substring(nonBlockStartIndex));
12151  }
12152  return new StringWithEscapedBlocks(resultParts.join(''), escapedBlocks);
12153}
12154/**
12155 * Object containing as keys characters that should be substituted by placeholders
12156 * when found in strings during the css text parsing, and as values the respective
12157 * placeholders
12158 */
12159const ESCAPE_IN_STRING_MAP = {
12160  ';': SEMI_IN_PLACEHOLDER,
12161  ',': COMMA_IN_PLACEHOLDER,
12162  ':': COLON_IN_PLACEHOLDER
12163};
12164/**
12165 * Parse the provided css text and inside strings (meaning, inside pairs of unescaped single or
12166 * double quotes) replace specific characters with their respective placeholders as indicated
12167 * by the `ESCAPE_IN_STRING_MAP` map.
12168 *
12169 * For example convert the text
12170 *  `animation: "my-anim:at\"ion" 1s;`
12171 * to
12172 *  `animation: "my-anim%COLON_IN_PLACEHOLDER%at\"ion" 1s;`
12173 *
12174 * This is necessary in order to remove the meaning of some characters when found inside strings
12175 * (for example `;` indicates the end of a css declaration, `,` the sequence of values and `:` the
12176 * division between property and value during a declaration, none of these meanings apply when such
12177 * characters are within strings and so in order to prevent parsing issues they need to be replaced
12178 * with placeholder text for the duration of the css manipulation process).
12179 *
12180 * @param input the original css text.
12181 *
12182 * @returns the css text with specific characters in strings replaced by placeholders.
12183 **/
12184function escapeInStrings(input) {
12185  let result = input;
12186  let currentQuoteChar = null;
12187  for (let i = 0; i < result.length; i++) {
12188    const char = result[i];
12189    if (char === '\\') {
12190      i++;
12191    } else {
12192      if (currentQuoteChar !== null) {
12193        // index i is inside a quoted sub-string
12194        if (char === currentQuoteChar) {
12195          currentQuoteChar = null;
12196        } else {
12197          const placeholder = ESCAPE_IN_STRING_MAP[char];
12198          if (placeholder) {
12199            result = `${result.substr(0, i)}${placeholder}${result.substr(i + 1)}`;
12200            i += placeholder.length - 1;
12201          }
12202        }
12203      } else if (char === '\'' || char === '"') {
12204        currentQuoteChar = char;
12205      }
12206    }
12207  }
12208  return result;
12209}
12210/**
12211 * Replace in a string all occurrences of keys in the `ESCAPE_IN_STRING_MAP` map with their
12212 * original representation, this is simply used to revert the changes applied by the
12213 * escapeInStrings function.
12214 *
12215 * For example it reverts the text:
12216 *  `animation: "my-anim%COLON_IN_PLACEHOLDER%at\"ion" 1s;`
12217 * to it's original form of:
12218 *  `animation: "my-anim:at\"ion" 1s;`
12219 *
12220 * Note: For the sake of simplicity this function does not check that the placeholders are
12221 * actually inside strings as it would anyway be extremely unlikely to find them outside of strings.
12222 *
12223 * @param input the css text containing the placeholders.
12224 *
12225 * @returns the css text without the placeholders.
12226 */
12227function unescapeInStrings(input) {
12228  let result = input.replace(_cssCommaInPlaceholderReGlobal, ',');
12229  result = result.replace(_cssSemiInPlaceholderReGlobal, ';');
12230  result = result.replace(_cssColonInPlaceholderReGlobal, ':');
12231  return result;
12232}
12233/**
12234 * Unescape all quotes present in a string, but only if the string was actually already
12235 * quoted.
12236 *
12237 * This generates a "canonical" representation of strings which can be used to match strings
12238 * which would otherwise only differ because of differently escaped quotes.
12239 *
12240 * For example it converts the string (assumed to be quoted):
12241 *  `this \\"is\\" a \\'\\\\'test`
12242 * to:
12243 *  `this "is" a '\\\\'test`
12244 * (note that the latter backslashes are not removed as they are not actually escaping the single
12245 * quote)
12246 *
12247 *
12248 * @param input the string possibly containing escaped quotes.
12249 * @param isQuoted boolean indicating whether the string was quoted inside a bigger string (if not
12250 * then it means that it doesn't represent an inner string and thus no unescaping is required)
12251 *
12252 * @returns the string in the "canonical" representation without escaped quotes.
12253 */
12254function unescapeQuotes(str, isQuoted) {
12255  return !isQuoted ? str : str.replace(/((?:^|[^\\])(?:\\\\)*)\\(?=['"])/g, '$1');
12256}
12257/**
12258 * Combine the `contextSelectors` with the `hostMarker` and the `otherSelectors`
12259 * to create a selector that matches the same as `:host-context()`.
12260 *
12261 * Given a single context selector `A` we need to output selectors that match on the host and as an
12262 * ancestor of the host:
12263 *
12264 * ```
12265 * A <hostMarker>, A<hostMarker> {}
12266 * ```
12267 *
12268 * When there is more than one context selector we also have to create combinations of those
12269 * selectors with each other. For example if there are `A` and `B` selectors the output is:
12270 *
12271 * ```
12272 * AB<hostMarker>, AB <hostMarker>, A B<hostMarker>,
12273 * B A<hostMarker>, A B <hostMarker>, B A <hostMarker> {}
12274 * ```
12275 *
12276 * And so on...
12277 *
12278 * @param contextSelectors an array of context selectors that will be combined.
12279 * @param otherSelectors the rest of the selectors that are not context selectors.
12280 */
12281function combineHostContextSelectors(contextSelectors, otherSelectors) {
12282  const hostMarker = _polyfillHostNoCombinator;
12283  _polyfillHostRe.lastIndex = 0; // reset the regex to ensure we get an accurate test
12284  const otherSelectorsHasHost = _polyfillHostRe.test(otherSelectors);
12285  // If there are no context selectors then just output a host marker
12286  if (contextSelectors.length === 0) {
12287    return hostMarker + otherSelectors;
12288  }
12289  const combined = [contextSelectors.pop() || ''];
12290  while (contextSelectors.length > 0) {
12291    const length = combined.length;
12292    const contextSelector = contextSelectors.pop();
12293    for (let i = 0; i < length; i++) {
12294      const previousSelectors = combined[i];
12295      // Add the new selector as a descendant of the previous selectors
12296      combined[length * 2 + i] = previousSelectors + ' ' + contextSelector;
12297      // Add the new selector as an ancestor of the previous selectors
12298      combined[length + i] = contextSelector + ' ' + previousSelectors;
12299      // Add the new selector to act on the same element as the previous selectors
12300      combined[i] = contextSelector + previousSelectors;
12301    }
12302  }
12303  // Finally connect the selector to the `hostMarker`s: either acting directly on the host
12304  // (A<hostMarker>) or as an ancestor (A <hostMarker>).
12305  return combined.map(s => otherSelectorsHasHost ? `${s}${otherSelectors}` : `${s}${hostMarker}${otherSelectors}, ${s} ${hostMarker}${otherSelectors}`).join(',');
12306}
12307/**
12308 * Mutate the given `groups` array so that there are `multiples` clones of the original array
12309 * stored.
12310 *
12311 * For example `repeatGroups([a, b], 3)` will result in `[a, b, a, b, a, b]` - but importantly the
12312 * newly added groups will be clones of the original.
12313 *
12314 * @param groups An array of groups of strings that will be repeated. This array is mutated
12315 *     in-place.
12316 * @param multiples The number of times the current groups should appear.
12317 */
12318function repeatGroups(groups, multiples) {
12319  const length = groups.length;
12320  for (let i = 1; i < multiples; i++) {
12321    for (let j = 0; j < length; j++) {
12322      groups[j + i * length] = groups[j].slice(0);
12323    }
12324  }
12325}
12326
12327/**
12328 * Distinguishes different kinds of IR operations.
12329 *
12330 * Includes both creation and update operations.
12331 */
12332var OpKind;
12333(function (OpKind) {
12334  /**
12335   * A special operation type which is used to represent the beginning and end nodes of a linked
12336   * list of operations.
12337   */
12338  OpKind[OpKind["ListEnd"] = 0] = "ListEnd";
12339  /**
12340   * An operation which wraps an output AST statement.
12341   */
12342  OpKind[OpKind["Statement"] = 1] = "Statement";
12343  /**
12344   * An operation which declares and initializes a `SemanticVariable`.
12345   */
12346  OpKind[OpKind["Variable"] = 2] = "Variable";
12347  /**
12348   * An operation to begin rendering of an element.
12349   */
12350  OpKind[OpKind["ElementStart"] = 3] = "ElementStart";
12351  /**
12352   * An operation to render an element with no children.
12353   */
12354  OpKind[OpKind["Element"] = 4] = "Element";
12355  /**
12356   * An operation which declares an embedded view.
12357   */
12358  OpKind[OpKind["Template"] = 5] = "Template";
12359  /**
12360   * An operation to end rendering of an element previously started with `ElementStart`.
12361   */
12362  OpKind[OpKind["ElementEnd"] = 6] = "ElementEnd";
12363  /**
12364   * An operation to begin an `ng-container`.
12365   */
12366  OpKind[OpKind["ContainerStart"] = 7] = "ContainerStart";
12367  /**
12368   * An operation for an `ng-container` with no children.
12369   */
12370  OpKind[OpKind["Container"] = 8] = "Container";
12371  /**
12372   * An operation to end an `ng-container`.
12373   */
12374  OpKind[OpKind["ContainerEnd"] = 9] = "ContainerEnd";
12375  /**
12376   * An operation disable binding for subsequent elements, which are descendants of a non-bindable
12377   * node.
12378   */
12379  OpKind[OpKind["DisableBindings"] = 10] = "DisableBindings";
12380  /**
12381   * An op to conditionally render a template.
12382   */
12383  OpKind[OpKind["Conditional"] = 11] = "Conditional";
12384  /**
12385   * An operation to re-enable binding, after it was previously disabled.
12386   */
12387  OpKind[OpKind["EnableBindings"] = 12] = "EnableBindings";
12388  /**
12389   * An operation to render a text node.
12390   */
12391  OpKind[OpKind["Text"] = 13] = "Text";
12392  /**
12393   * An operation declaring an event listener for an element.
12394   */
12395  OpKind[OpKind["Listener"] = 14] = "Listener";
12396  /**
12397   * An operation to interpolate text into a text node.
12398   */
12399  OpKind[OpKind["InterpolateText"] = 15] = "InterpolateText";
12400  /**
12401   * An intermediate binding op, that has not yet been processed into an individual property,
12402   * attribute, style, etc.
12403   */
12404  OpKind[OpKind["Binding"] = 16] = "Binding";
12405  /**
12406   * An operation to bind an expression to a property of an element.
12407   */
12408  OpKind[OpKind["Property"] = 17] = "Property";
12409  /**
12410   * An operation to bind an expression to a style property of an element.
12411   */
12412  OpKind[OpKind["StyleProp"] = 18] = "StyleProp";
12413  /**
12414   * An operation to bind an expression to a class property of an element.
12415   */
12416  OpKind[OpKind["ClassProp"] = 19] = "ClassProp";
12417  /**
12418   * An operation to bind an expression to the styles of an element.
12419   */
12420  OpKind[OpKind["StyleMap"] = 20] = "StyleMap";
12421  /**
12422   * An operation to bind an expression to the classes of an element.
12423   */
12424  OpKind[OpKind["ClassMap"] = 21] = "ClassMap";
12425  /**
12426   * An operation to advance the runtime's implicit slot context during the update phase of a view.
12427   */
12428  OpKind[OpKind["Advance"] = 22] = "Advance";
12429  /**
12430   * An operation to instantiate a pipe.
12431   */
12432  OpKind[OpKind["Pipe"] = 23] = "Pipe";
12433  /**
12434   * An operation to associate an attribute with an element.
12435   */
12436  OpKind[OpKind["Attribute"] = 24] = "Attribute";
12437  /**
12438   * An attribute that has been extracted for inclusion in the consts array.
12439   */
12440  OpKind[OpKind["ExtractedAttribute"] = 25] = "ExtractedAttribute";
12441  /**
12442   * An operation that configures a `@defer` block.
12443   */
12444  OpKind[OpKind["Defer"] = 26] = "Defer";
12445  /**
12446   * An operation that controls when a `@defer` loads.
12447   */
12448  OpKind[OpKind["DeferOn"] = 27] = "DeferOn";
12449  /**
12450   * An operation that controls when a `@defer` loads, using a custom expression as the condition.
12451   */
12452  OpKind[OpKind["DeferWhen"] = 28] = "DeferWhen";
12453  /**
12454   * An i18n message that has been extracted for inclusion in the consts array.
12455   */
12456  OpKind[OpKind["I18nMessage"] = 29] = "I18nMessage";
12457  /**
12458   * A host binding property.
12459   */
12460  OpKind[OpKind["HostProperty"] = 30] = "HostProperty";
12461  /**
12462   * A namespace change, which causes the subsequent elements to be processed as either HTML or SVG.
12463   */
12464  OpKind[OpKind["Namespace"] = 31] = "Namespace";
12465  /**
12466   * Configure a content projeciton definition for the view.
12467   */
12468  OpKind[OpKind["ProjectionDef"] = 32] = "ProjectionDef";
12469  /**
12470   * Create a content projection slot.
12471   */
12472  OpKind[OpKind["Projection"] = 33] = "Projection";
12473  /**
12474   * Create a repeater creation instruction op.
12475   */
12476  OpKind[OpKind["RepeaterCreate"] = 34] = "RepeaterCreate";
12477  /**
12478   * An update up for a repeater.
12479   */
12480  OpKind[OpKind["Repeater"] = 35] = "Repeater";
12481  /**
12482   * An operation to bind an expression to the property side of a two-way binding.
12483   */
12484  OpKind[OpKind["TwoWayProperty"] = 36] = "TwoWayProperty";
12485  /**
12486   * An operation declaring the event side of a two-way binding.
12487   */
12488  OpKind[OpKind["TwoWayListener"] = 37] = "TwoWayListener";
12489  /**
12490   * The start of an i18n block.
12491   */
12492  OpKind[OpKind["I18nStart"] = 38] = "I18nStart";
12493  /**
12494   * A self-closing i18n on a single element.
12495   */
12496  OpKind[OpKind["I18n"] = 39] = "I18n";
12497  /**
12498   * The end of an i18n block.
12499   */
12500  OpKind[OpKind["I18nEnd"] = 40] = "I18nEnd";
12501  /**
12502   * An expression in an i18n message.
12503   */
12504  OpKind[OpKind["I18nExpression"] = 41] = "I18nExpression";
12505  /**
12506   * An instruction that applies a set of i18n expressions.
12507   */
12508  OpKind[OpKind["I18nApply"] = 42] = "I18nApply";
12509  /**
12510   * An instruction to create an ICU expression.
12511   */
12512  OpKind[OpKind["IcuStart"] = 43] = "IcuStart";
12513  /**
12514   * An instruction to update an ICU expression.
12515   */
12516  OpKind[OpKind["IcuEnd"] = 44] = "IcuEnd";
12517  /**
12518   * An instruction representing a placeholder in an ICU expression.
12519   */
12520  OpKind[OpKind["IcuPlaceholder"] = 45] = "IcuPlaceholder";
12521  /**
12522   * An i18n context containing information needed to generate an i18n message.
12523   */
12524  OpKind[OpKind["I18nContext"] = 46] = "I18nContext";
12525  /**
12526   * A creation op that corresponds to i18n attributes on an element.
12527   */
12528  OpKind[OpKind["I18nAttributes"] = 47] = "I18nAttributes";
12529})(OpKind || (OpKind = {}));
12530/**
12531 * Distinguishes different kinds of IR expressions.
12532 */
12533var ExpressionKind;
12534(function (ExpressionKind) {
12535  /**
12536   * Read of a variable in a lexical scope.
12537   */
12538  ExpressionKind[ExpressionKind["LexicalRead"] = 0] = "LexicalRead";
12539  /**
12540   * A reference to the current view context.
12541   */
12542  ExpressionKind[ExpressionKind["Context"] = 1] = "Context";
12543  /**
12544   * A reference to the view context, for use inside a track function.
12545   */
12546  ExpressionKind[ExpressionKind["TrackContext"] = 2] = "TrackContext";
12547  /**
12548   * Read of a variable declared in a `VariableOp`.
12549   */
12550  ExpressionKind[ExpressionKind["ReadVariable"] = 3] = "ReadVariable";
12551  /**
12552   * Runtime operation to navigate to the next view context in the view hierarchy.
12553   */
12554  ExpressionKind[ExpressionKind["NextContext"] = 4] = "NextContext";
12555  /**
12556   * Runtime operation to retrieve the value of a local reference.
12557   */
12558  ExpressionKind[ExpressionKind["Reference"] = 5] = "Reference";
12559  /**
12560   * Runtime operation to snapshot the current view context.
12561   */
12562  ExpressionKind[ExpressionKind["GetCurrentView"] = 6] = "GetCurrentView";
12563  /**
12564   * Runtime operation to restore a snapshotted view.
12565   */
12566  ExpressionKind[ExpressionKind["RestoreView"] = 7] = "RestoreView";
12567  /**
12568   * Runtime operation to reset the current view context after `RestoreView`.
12569   */
12570  ExpressionKind[ExpressionKind["ResetView"] = 8] = "ResetView";
12571  /**
12572   * Defines and calls a function with change-detected arguments.
12573   */
12574  ExpressionKind[ExpressionKind["PureFunctionExpr"] = 9] = "PureFunctionExpr";
12575  /**
12576   * Indicates a positional parameter to a pure function definition.
12577   */
12578  ExpressionKind[ExpressionKind["PureFunctionParameterExpr"] = 10] = "PureFunctionParameterExpr";
12579  /**
12580   * Binding to a pipe transformation.
12581   */
12582  ExpressionKind[ExpressionKind["PipeBinding"] = 11] = "PipeBinding";
12583  /**
12584   * Binding to a pipe transformation with a variable number of arguments.
12585   */
12586  ExpressionKind[ExpressionKind["PipeBindingVariadic"] = 12] = "PipeBindingVariadic";
12587  /*
12588   * A safe property read requiring expansion into a null check.
12589   */
12590  ExpressionKind[ExpressionKind["SafePropertyRead"] = 13] = "SafePropertyRead";
12591  /**
12592   * A safe keyed read requiring expansion into a null check.
12593   */
12594  ExpressionKind[ExpressionKind["SafeKeyedRead"] = 14] = "SafeKeyedRead";
12595  /**
12596   * A safe function call requiring expansion into a null check.
12597   */
12598  ExpressionKind[ExpressionKind["SafeInvokeFunction"] = 15] = "SafeInvokeFunction";
12599  /**
12600   * An intermediate expression that will be expanded from a safe read into an explicit ternary.
12601   */
12602  ExpressionKind[ExpressionKind["SafeTernaryExpr"] = 16] = "SafeTernaryExpr";
12603  /**
12604   * An empty expression that will be stipped before generating the final output.
12605   */
12606  ExpressionKind[ExpressionKind["EmptyExpr"] = 17] = "EmptyExpr";
12607  /*
12608   * An assignment to a temporary variable.
12609   */
12610  ExpressionKind[ExpressionKind["AssignTemporaryExpr"] = 18] = "AssignTemporaryExpr";
12611  /**
12612   * A reference to a temporary variable.
12613   */
12614  ExpressionKind[ExpressionKind["ReadTemporaryExpr"] = 19] = "ReadTemporaryExpr";
12615  /**
12616   * An expression that will cause a literal slot index to be emitted.
12617   */
12618  ExpressionKind[ExpressionKind["SlotLiteralExpr"] = 20] = "SlotLiteralExpr";
12619  /**
12620   * A test expression for a conditional op.
12621   */
12622  ExpressionKind[ExpressionKind["ConditionalCase"] = 21] = "ConditionalCase";
12623  /**
12624   * An expression that will be automatically extracted to the component const array.
12625   */
12626  ExpressionKind[ExpressionKind["ConstCollected"] = 22] = "ConstCollected";
12627  /**
12628   * Operation that sets the value of a two-way binding.
12629   */
12630  ExpressionKind[ExpressionKind["TwoWayBindingSet"] = 23] = "TwoWayBindingSet";
12631})(ExpressionKind || (ExpressionKind = {}));
12632var VariableFlags;
12633(function (VariableFlags) {
12634  VariableFlags[VariableFlags["None"] = 0] = "None";
12635  /**
12636   * Always inline this variable, regardless of the number of times it's used.
12637   * An `AlwaysInline` variable may not depend on context, because doing so may cause side effects
12638   * that are illegal when multi-inlined. (The optimizer will enforce this constraint.)
12639   */
12640  VariableFlags[VariableFlags["AlwaysInline"] = 1] = "AlwaysInline";
12641})(VariableFlags || (VariableFlags = {}));
12642/**
12643 * Distinguishes between different kinds of `SemanticVariable`s.
12644 */
12645var SemanticVariableKind;
12646(function (SemanticVariableKind) {
12647  /**
12648   * Represents the context of a particular view.
12649   */
12650  SemanticVariableKind[SemanticVariableKind["Context"] = 0] = "Context";
12651  /**
12652   * Represents an identifier declared in the lexical scope of a view.
12653   */
12654  SemanticVariableKind[SemanticVariableKind["Identifier"] = 1] = "Identifier";
12655  /**
12656   * Represents a saved state that can be used to restore a view in a listener handler function.
12657   */
12658  SemanticVariableKind[SemanticVariableKind["SavedView"] = 2] = "SavedView";
12659  /**
12660   * An alias generated by a special embedded view type (e.g. a `@for` block).
12661   */
12662  SemanticVariableKind[SemanticVariableKind["Alias"] = 3] = "Alias";
12663})(SemanticVariableKind || (SemanticVariableKind = {}));
12664/**
12665 * Whether to compile in compatibilty mode. In compatibility mode, the template pipeline will
12666 * attempt to match the output of `TemplateDefinitionBuilder` as exactly as possible, at the cost
12667 * of producing quirky or larger code in some cases.
12668 */
12669var CompatibilityMode;
12670(function (CompatibilityMode) {
12671  CompatibilityMode[CompatibilityMode["Normal"] = 0] = "Normal";
12672  CompatibilityMode[CompatibilityMode["TemplateDefinitionBuilder"] = 1] = "TemplateDefinitionBuilder";
12673})(CompatibilityMode || (CompatibilityMode = {}));
12674/**
12675 * Enumeration of the types of attributes which can be applied to an element.
12676 */
12677var BindingKind;
12678(function (BindingKind) {
12679  /**
12680   * Static attributes.
12681   */
12682  BindingKind[BindingKind["Attribute"] = 0] = "Attribute";
12683  /**
12684   * Class bindings.
12685   */
12686  BindingKind[BindingKind["ClassName"] = 1] = "ClassName";
12687  /**
12688   * Style bindings.
12689   */
12690  BindingKind[BindingKind["StyleProperty"] = 2] = "StyleProperty";
12691  /**
12692   * Dynamic property bindings.
12693   */
12694  BindingKind[BindingKind["Property"] = 3] = "Property";
12695  /**
12696   * Property or attribute bindings on a template.
12697   */
12698  BindingKind[BindingKind["Template"] = 4] = "Template";
12699  /**
12700   * Internationalized attributes.
12701   */
12702  BindingKind[BindingKind["I18n"] = 5] = "I18n";
12703  /**
12704   * Animation property bindings.
12705   */
12706  BindingKind[BindingKind["Animation"] = 6] = "Animation";
12707  /**
12708   * Property side of a two-way binding.
12709   */
12710  BindingKind[BindingKind["TwoWayProperty"] = 7] = "TwoWayProperty";
12711})(BindingKind || (BindingKind = {}));
12712/**
12713 * Enumeration of possible times i18n params can be resolved.
12714 */
12715var I18nParamResolutionTime;
12716(function (I18nParamResolutionTime) {
12717  /**
12718   * Param is resolved at message creation time. Most params should be resolved at message creation
12719   * time. However, ICU params need to be handled in post-processing.
12720   */
12721  I18nParamResolutionTime[I18nParamResolutionTime["Creation"] = 0] = "Creation";
12722  /**
12723   * Param is resolved during post-processing. This should be used for params whose value comes from
12724   * an ICU.
12725   */
12726  I18nParamResolutionTime[I18nParamResolutionTime["Postproccessing"] = 1] = "Postproccessing";
12727})(I18nParamResolutionTime || (I18nParamResolutionTime = {}));
12728/**
12729 * The contexts in which an i18n expression can be used.
12730 */
12731var I18nExpressionFor;
12732(function (I18nExpressionFor) {
12733  /**
12734   * This expression is used as a value (i.e. inside an i18n block).
12735   */
12736  I18nExpressionFor[I18nExpressionFor["I18nText"] = 0] = "I18nText";
12737  /**
12738   * This expression is used in a binding.
12739   */
12740  I18nExpressionFor[I18nExpressionFor["I18nAttribute"] = 1] = "I18nAttribute";
12741})(I18nExpressionFor || (I18nExpressionFor = {}));
12742/**
12743 * Flags that describe what an i18n param value. These determine how the value is serialized into
12744 * the final map.
12745 */
12746var I18nParamValueFlags;
12747(function (I18nParamValueFlags) {
12748  I18nParamValueFlags[I18nParamValueFlags["None"] = 0] = "None";
12749  /**
12750   *  This value represents an element tag.
12751   */
12752  I18nParamValueFlags[I18nParamValueFlags["ElementTag"] = 1] = "ElementTag";
12753  /**
12754   * This value represents a template tag.
12755   */
12756  I18nParamValueFlags[I18nParamValueFlags["TemplateTag"] = 2] = "TemplateTag";
12757  /**
12758   * This value represents the opening of a tag.
12759   */
12760  I18nParamValueFlags[I18nParamValueFlags["OpenTag"] = 4] = "OpenTag";
12761  /**
12762   * This value represents the closing of a tag.
12763   */
12764  I18nParamValueFlags[I18nParamValueFlags["CloseTag"] = 8] = "CloseTag";
12765  /**
12766   * This value represents an i18n expression index.
12767   */
12768  I18nParamValueFlags[I18nParamValueFlags["ExpressionIndex"] = 16] = "ExpressionIndex";
12769})(I18nParamValueFlags || (I18nParamValueFlags = {}));
12770/**
12771 * Whether the active namespace is HTML, MathML, or SVG mode.
12772 */
12773var Namespace;
12774(function (Namespace) {
12775  Namespace[Namespace["HTML"] = 0] = "HTML";
12776  Namespace[Namespace["SVG"] = 1] = "SVG";
12777  Namespace[Namespace["Math"] = 2] = "Math";
12778})(Namespace || (Namespace = {}));
12779/**
12780 * The type of a `@defer` trigger, for use in the ir.
12781 */
12782var DeferTriggerKind;
12783(function (DeferTriggerKind) {
12784  DeferTriggerKind[DeferTriggerKind["Idle"] = 0] = "Idle";
12785  DeferTriggerKind[DeferTriggerKind["Immediate"] = 1] = "Immediate";
12786  DeferTriggerKind[DeferTriggerKind["Timer"] = 2] = "Timer";
12787  DeferTriggerKind[DeferTriggerKind["Hover"] = 3] = "Hover";
12788  DeferTriggerKind[DeferTriggerKind["Interaction"] = 4] = "Interaction";
12789  DeferTriggerKind[DeferTriggerKind["Viewport"] = 5] = "Viewport";
12790})(DeferTriggerKind || (DeferTriggerKind = {}));
12791/**
12792 * Kinds of i18n contexts. They can be created because of root i18n blocks, or ICUs.
12793 */
12794var I18nContextKind;
12795(function (I18nContextKind) {
12796  I18nContextKind[I18nContextKind["RootI18n"] = 0] = "RootI18n";
12797  I18nContextKind[I18nContextKind["Icu"] = 1] = "Icu";
12798  I18nContextKind[I18nContextKind["Attr"] = 2] = "Attr";
12799})(I18nContextKind || (I18nContextKind = {}));
12800var TemplateKind;
12801(function (TemplateKind) {
12802  TemplateKind[TemplateKind["NgTemplate"] = 0] = "NgTemplate";
12803  TemplateKind[TemplateKind["Structural"] = 1] = "Structural";
12804  TemplateKind[TemplateKind["Block"] = 2] = "Block";
12805})(TemplateKind || (TemplateKind = {}));
12806
12807/**
12808 * Marker symbol for `ConsumesSlotOpTrait`.
12809 */
12810const ConsumesSlot = Symbol('ConsumesSlot');
12811/**
12812 * Marker symbol for `DependsOnSlotContextOpTrait`.
12813 */
12814const DependsOnSlotContext = Symbol('DependsOnSlotContext');
12815/**
12816 * Marker symbol for `ConsumesVars` trait.
12817 */
12818const ConsumesVarsTrait = Symbol('ConsumesVars');
12819/**
12820 * Marker symbol for `UsesVarOffset` trait.
12821 */
12822const UsesVarOffset = Symbol('UsesVarOffset');
12823/**
12824 * Default values for most `ConsumesSlotOpTrait` fields (used with the spread operator to initialize
12825 * implementors of the trait).
12826 */
12827const TRAIT_CONSUMES_SLOT = {
12828  [ConsumesSlot]: true,
12829  numSlotsUsed: 1
12830};
12831/**
12832 * Default values for most `DependsOnSlotContextOpTrait` fields (used with the spread operator to
12833 * initialize implementors of the trait).
12834 */
12835const TRAIT_DEPENDS_ON_SLOT_CONTEXT = {
12836  [DependsOnSlotContext]: true
12837};
12838/**
12839 * Default values for `UsesVars` fields (used with the spread operator to initialize
12840 * implementors of the trait).
12841 */
12842const TRAIT_CONSUMES_VARS = {
12843  [ConsumesVarsTrait]: true
12844};
12845/**
12846 * Test whether an operation implements `ConsumesSlotOpTrait`.
12847 */
12848function hasConsumesSlotTrait(op) {
12849  return op[ConsumesSlot] === true;
12850}
12851/**
12852 * Test whether an operation implements `DependsOnSlotContextOpTrait`.
12853 */
12854function hasDependsOnSlotContextTrait(op) {
12855  return op[DependsOnSlotContext] === true;
12856}
12857function hasConsumesVarsTrait(value) {
12858  return value[ConsumesVarsTrait] === true;
12859}
12860/**
12861 * Test whether an expression implements `UsesVarOffsetTrait`.
12862 */
12863function hasUsesVarOffsetTrait(expr) {
12864  return expr[UsesVarOffset] === true;
12865}
12866
12867/**
12868 * Create a `StatementOp`.
12869 */
12870function createStatementOp(statement) {
12871  return {
12872    kind: OpKind.Statement,
12873    statement,
12874    ...NEW_OP
12875  };
12876}
12877/**
12878 * Create a `VariableOp`.
12879 */
12880function createVariableOp(xref, variable, initializer, flags) {
12881  return {
12882    kind: OpKind.Variable,
12883    xref,
12884    variable,
12885    initializer,
12886    flags,
12887    ...NEW_OP
12888  };
12889}
12890/**
12891 * Static structure shared by all operations.
12892 *
12893 * Used as a convenience via the spread operator (`...NEW_OP`) when creating new operations, and
12894 * ensures the fields are always in the same order.
12895 */
12896const NEW_OP = {
12897  debugListId: null,
12898  prev: null,
12899  next: null
12900};
12901
12902/**
12903 * Create an `InterpolationTextOp`.
12904 */
12905function createInterpolateTextOp(xref, interpolation, sourceSpan) {
12906  return {
12907    kind: OpKind.InterpolateText,
12908    target: xref,
12909    interpolation,
12910    sourceSpan,
12911    ...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
12912    ...TRAIT_CONSUMES_VARS,
12913    ...NEW_OP
12914  };
12915}
12916class Interpolation {
12917  constructor(strings, expressions, i18nPlaceholders) {
12918    this.strings = strings;
12919    this.expressions = expressions;
12920    this.i18nPlaceholders = i18nPlaceholders;
12921    if (i18nPlaceholders.length !== 0 && i18nPlaceholders.length !== expressions.length) {
12922      throw new Error(`Expected ${expressions.length} placeholders to match interpolation expression count, but got ${i18nPlaceholders.length}`);
12923    }
12924  }
12925}
12926/**
12927 * Create a `BindingOp`, not yet transformed into a particular type of binding.
12928 */
12929function createBindingOp(target, kind, name, expression, unit, securityContext, isTextAttribute, isStru
12929cturalTemplateAttribute, templateKind, i18nMessage, sourceSpan) {
12930  return {
12931    kind: OpKind.Binding,
12932    bindingKind: kind,
12933    target,
12934    name,
12935    expression,
12936    unit,
12937    securityContext,
12938    isTextAttribute,
12939    isStructuralTemplateAttribute,
12940    templateKind,
12941    i18nContext: null,
12942    i18nMessage,
12943    sourceSpan,
12944    ...NEW_OP
12945  };
12946}
12947/**
12948 * Create a `PropertyOp`.
12949 */
12950function createPropertyOp(target, name, expression, isAnimationTrigger, securityContext, isStructuralTemplateAttribute, templateKind, i18nContext, i18nMessage, sourceSpan) {
12951  return {
12952    kind: OpKind.Property,
12953    target,
12954    name,
12955    expression,
12956    isAnimationTrigger,
12957    securityContext,
12958    sanitizer: null,
12959    isStructuralTemplateAttribute,
12960    templateKind,
12961    i18nContext,
12962    i18nMessage,
12963    sourceSpan,
12964    ...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
12965    ...TRAIT_CONSUMES_VARS,
12966    ...NEW_OP
12967  };
12968}
12969/**
12970 * Create a `TwoWayPropertyOp`.
12971 */
12972function createTwoWayPropertyOp(target, name, expression, securityContext, isStructuralTemplateAttribute, templateKind, i18nContext, i18nMessage, sourceSpan) {
12973  return {
12974    kind: OpKind.TwoWayProperty,
12975    target,
12976    name,
12977    expression,
12978    securityContext,
12979    sanitizer: null,
12980    isStructuralTemplateAttribute,
12981    templateKind,
12982    i18nContext,
12983    i18nMessage,
12984    sourceSpan,
12985    ...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
12986    ...TRAIT_CONSUMES_VARS,
12987    ...NEW_OP
12988  };
12989}
12990/** Create a `StylePropOp`. */
12991function createStylePropOp(xref, name, expression, unit, sourceSpan) {
12992  return {
12993    kind: OpKind.StyleProp,
12994    target: xref,
12995    name,
12996    expression,
12997    unit,
12998    sourceSpan,
12999    ...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
13000    ...TRAIT_CONSUMES_VARS,
13001    ...NEW_OP
13002  };
13003}
13004/**
13005 * Create a `ClassPropOp`.
13006 */
13007function createClassPropOp(xref, name, expression, sourceSpan) {
13008  return {
13009    kind: OpKind.ClassProp,
13010    target: xref,
13011    name,
13012    expression,
13013    sourceSpan,
13014    ...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
13015    ...TRAIT_CONSUMES_VARS,
13016    ...NEW_OP
13017  };
13018}
13019/** Create a `StyleMapOp`. */
13020function createStyleMapOp(xref, expression, sourceSpan) {
13021  return {
13022    kind: OpKind.StyleMap,
13023    target: xref,
13024    expression,
13025    sourceSpan,
13026    ...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
13027    ...TRAIT_CONSUMES_VARS,
13028    ...NEW_OP
13029  };
13030}
13031/**
13032 * Create a `ClassMapOp`.
13033 */
13034function createClassMapOp(xref, expression, sourceSpan) {
13035  return {
13036    kind: OpKind.ClassMap,
13037    target: xref,
13038    expression,
13039    sourceSpan,
13040    ...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
13041    ...TRAIT_CONSUMES_VARS,
13042    ...NEW_OP
13043  };
13044}
13045/**
13046 * Create an `AttributeOp`.
13047 */
13048function createAttributeOp(target, namespace, name, expression, securityContext, isTextAttribute, isStructuralTemplateAttribute, templateKind, i18nMessage, sourceSpan) {
13049  return {
13050    kind: OpKind.Attribute,
13051    target,
13052    namespace,
13053    name,
13054    expression,
13055    securityContext,
13056    sanitizer: null,
13057    isTextAttribute,
13058    isStructuralTemplateAttribute,
13059    templateKind,
13060    i18nContext: null,
13061    i18nMessage,
13062    sourceSpan,
13063    ...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
13064    ...TRAIT_CONSUMES_VARS,
13065    ...NEW_OP
13066  };
13067}
13068/**
13069 * Create an `AdvanceOp`.
13070 */
13071function createAdvanceOp(delta, sourceSpan) {
13072  return {
13073    kind: OpKind.Advance,
13074    delta,
13075    sourceSpan,
13076    ...NEW_OP
13077  };
13078}
13079/**
13080 * Create a conditional op, which will display an embedded view according to a condtion.
13081 */
13082function createConditionalOp(target, targetSlot, test, conditions, sourceSpan) {
13083  return {
13084    kind: OpKind.Conditional,
13085    target,
13086    targetSlot,
13087    test,
13088    conditions,
13089    processed: null,
13090    sourceSpan,
13091    contextValue: null,
13092    ...NEW_OP,
13093    ...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
13094    ...TRAIT_CONSUMES_VARS
13095  };
13096}
13097function createRepeaterOp(repeaterCreate, targetSlot, collection, sourceSpan) {
13098  return {
13099    kind: OpKind.Repeater,
13100    target: repeaterCreate,
13101    targetSlot,
13102    collection,
13103    sourceSpan,
13104    ...NEW_OP,
13105    ...TRAIT_DEPENDS_ON_SLOT_CONTEXT
13106  };
13107}
13108function createDeferWhenOp(target, expr, prefetch, sourceSpan) {
13109  return {
13110    kind: OpKind.DeferWhen,
13111    target,
13112    expr,
13113    prefetch,
13114    sourceSpan,
13115    ...NEW_OP,
13116    ...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
13117    ...TRAIT_CONSUMES_VARS
13118  };
13119}
13120/**
13121 * Create an i18n expression op.
13122 */
13123function createI18nExpressionOp(context, target, i18nOwner, handle, expression, icuPlaceholder, i18nPlaceholder, resolutionTime, usage, name, sourceSpan) {
13124  return {
13125    kind: OpKind.I18nExpression,
13126    context,
13127    target,
13128    i18nOwner,
13129    handle,
13130    expression,
13131    icuPlaceholder,
13132    i18nPlaceholder,
13133    resolutionTime,
13134    usage,
13135    name,
13136    sourceSpan,
13137    ...NEW_OP,
13138    ...TRAIT_CONSUMES_VARS,
13139    ...TRAIT_DEPENDS_ON_SLOT_CONTEXT
13140  };
13141}
13142/**
13143 * Creates an op to apply i18n expression ops.
13144 */
13145function createI18nApplyOp(owner, handle, sourceSpan) {
13146  return {
13147    kind: OpKind.I18nApply,
13148    owner,
13149    handle,
13150    sourceSpan,
13151    ...NEW_OP
13152  };
13153}
13154var _a, _b, _c, _d, _e, _f;
13155/**
13156 * Check whether a given `o.Expression` is a logical IR expression type.
13157 */
13158function isIrExpression(expr) {
13159  return expr instanceof ExpressionBase;
13160}
13161/**
13162 * Base type used for all logical IR expressions.
13163 */
13164class ExpressionBase extends Expression {
13165  constructor(sourceSpan = null) {
13166    super(null, sourceSpan);
13167  }
13168}
13169/**
13170 * Logical expression representing a lexical read of a variable name.
13171 */
13172class LexicalReadExpr extends ExpressionBase {
13173  constructor(name) {
13174    super();
13175    this.name = name;
13176    this.kind = ExpressionKind.LexicalRead;
13177  }
13178  visitExpression(visitor, context) {}
13179  isEquivalent(other) {
13180    // We assume that the lexical reads are in the same context, which must be true for parent
13181    // expressions to be equivalent.
13182    // TODO: is this generally safe?
13183    return this.name === other.name;
13184  }
13185  isConstant() {
13186    return false;
13187  }
13188  transformInternalExpressions() {}
13189  clone() {
13190    return new LexicalReadExpr(this.name);
13191  }
13192}
13193/**
13194 * Runtime operation to retrieve the value of a local reference.
13195 */
13196class ReferenceExpr extends ExpressionBase {
13197  constructor(target, targetSlot, offset) {
13198    super();
13199    this.target = target;
13200    this.targetSlot = targetSlot;
13201    this.offset = offset;
13202    this.kind = ExpressionKind.Reference;
13203  }
13204  visitExpression() {}
13205  isEquivalent(e) {
13206    return e instanceof ReferenceExpr && e.target === this.target;
13207  }
13208  isConstant() {
13209    return false;
13210  }
13211  transformInternalExpressions() {}
13212  clone() {
13213    return new ReferenceExpr(this.target, this.targetSlot, this.offset);
13214  }
13215}
13216/**
13217 * A reference to the current view context (usually the `ctx` variable in a template function).
13218 */
13219class ContextExpr extends ExpressionBase {
13220  constructor(view) {
13221    super();
13222    this.view = view;
13223    this.kind = ExpressionKind.Context;
13224  }
13225  visitExpression() {}
13226  isEquivalent(e) {
13227    return e instanceof ContextExpr && e.view === this.view;
13228  }
13229  isConstant() {
13230    return false;
13231  }
13232  transformInternalExpressions() {}
13233  clone() {
13234    return new ContextExpr(this.view);
13235  }
13236}
13237/**
13238 * A reference to the current view context inside a track function.
13239 */
13240class TrackContextExpr extends ExpressionBase {
13241  constructor(view) {
13242    super();
13243    this.view = view;
13244    this.kind = ExpressionKind.TrackContext;
13245  }
13246  visitExpression() {}
13247  isEquivalent(e) {
13248    return e instanceof TrackContextExpr && e.view === this.view;
13249  }
13250  isConstant() {
13251    return false;
13252  }
13253  transformInternalExpressions() {}
13254  clone() {
13255    return new TrackContextExpr(this.view);
13256  }
13257}
13258/**
13259 * Runtime operation to navigate to the next view context in the view hierarchy.
13260 */
13261class NextContextExpr extends ExpressionBase {
13262  constructor() {
13263    super();
13264    this.kind = ExpressionKind.NextContext;
13265    this.steps = 1;
13266  }
13267  visitExpression() {}
13268  isEquivalent(e) {
13269    return e instanceof NextContextExpr && e.steps === this.steps;
13270  }
13271  isConstant() {
13272    return false;
13273  }
13274  transformInternalExpressions() {}
13275  clone() {
13276    const expr = new NextContextExpr();
13277    expr.steps = this.steps;
13278    return expr;
13279  }
13280}
13281/**
13282 * Runtime operation to snapshot the current view context.
13283 *
13284 * The result of this operation can be stored in a variable and later used with the `RestoreView`
13285 * operation.
13286 */
13287class GetCurrentViewExpr extends ExpressionBase {
13288  constructor() {
13289    super();
13290    this.kind = ExpressionKind.GetCurrentView;
13291  }
13292  visitExpression() {}
13293  isEquivalent(e) {
13294    return e instanceof GetCurrentViewExpr;
13295  }
13296  isConstant() {
13297    return false;
13298  }
13299  transformInternalExpressions() {}
13300  clone() {
13301    return new GetCurrentViewExpr();
13302  }
13303}
13304/**
13305 * Runtime operation to restore a snapshotted view.
13306 */
13307class RestoreViewExpr extends ExpressionBase {
13308  constructor(view) {
13309    super();
13310    this.view = view;
13311    this.kind = ExpressionKind.RestoreView;
13312  }
13313  visitExpression(visitor, context) {
13314    if (typeof this.view !== 'number') {
13315      this.view.visitExpression(visitor, context);
13316    }
13317  }
13318  isEquivalent(e) {
13319    if (!(e instanceof RestoreViewExpr) || typeof e.view !== typeof this.view) {
13320      return false;
13321    }
13322    if (typeof this.view === 'number') {
13323      return this.view === e.view;
13324    } else {
13325      return this.view.isEquivalent(e.view);
13326    }
13327  }
13328  isConstant() {
13329    return false;
13330  }
13331  transformInternalExpressions(transform, flags) {
13332    if (typeof this.view !== 'number') {
13333      this.view = transformExpressionsInExpression(this.view, transform, flags);
13334    }
13335  }
13336  clone() {
13337    return new RestoreViewExpr(this.view instanceof Expression ? this.view.clone() : this.view);
13338  }
13339}
13340/**
13341 * Runtime operation to reset the current view context after `RestoreView`.
13342 */
13343class ResetViewExpr extends ExpressionBase {
13344  constructor(expr) {
13345    super();
13346    this.expr = expr;
13347    this.kind = ExpressionKind.ResetView;
13348  }
13349  visitExpression(visitor, context) {
13350    this.expr.visitExpression(visitor, context);
13351  }
13352  isEquivalent(e) {
13353    return e instanceof ResetViewExpr && this.expr.isEquivalent(e.expr);
13354  }
13355  isConstant() {
13356    return false;
13357  }
13358  transformInternalExpressions(transform, flags) {
13359    this.expr = transformExpressionsInExpression(this.expr, transform, flags);
13360  }
13361  clone() {
13362    return new ResetViewExpr(this.expr.clone());
13363  }
13364}
13365class TwoWayBindingSetExpr extends ExpressionBase {
13366  constructor(target, value) {
13367    super();
13368    this.target = target;
13369    this.value = value;
13370    this.kind = ExpressionKind.TwoWayBindingSet;
13371  }
13372  visitExpression(visitor, context) {
13373    this.target.visitExpression(visitor, context);
13374    this.value.visitExpression(visitor, context);
13375  }
13376  isEquivalent(other) {
13377    return this.target.isEquivalent(other.target) && this.value.isEquivalent(other.value);
13378  }
13379  isConstant() {
13380    return false;
13381  }
13382  transformInternalExpressions(transform, flags) {
13383    this.target = transformExpressionsInExpression(this.target, transform, flags);
13384    this.value = transformExpressionsInExpression(this.value, transform, flags);
13385  }
13386  clone() {
13387    return new TwoWayBindingSetExpr(this.target, this.value);
13388  }
13389}
13390/**
13391 * Read of a variable declared as an `ir.VariableOp` and referenced through its `ir.XrefId`.
13392 */
13393class ReadVariableExpr extends ExpressionBase {
13394  constructor(xref) {
13395    super();
13396    this.xref = xref;
13397    this.kind = ExpressionKind.ReadVariable;
13398    this.name = null;
13399  }
13400  visitExpression() {}
13401  isEquivalent(other) {
13402    return other instanceof ReadVariableExpr && other.xref === this.xref;
13403  }
13404  isConstant() {
13405    return false;
13406  }
13407  transformInternalExpressions() {}
13408  clone() {
13409    const expr = new ReadVariableExpr(this.xref);
13410    expr.name = this.name;
13411    return expr;
13412  }
13413}
13414class PureFunctionExpr extends ExpressionBase {
13415  static #_ = (_a = ConsumesVarsTrait, _b = UsesVarOffset);
13416  constructor(expression, args) {
13417    super();
13418    this.kind = ExpressionKind.PureFunctionExpr;
13419    this[_a] = true;
13420    this[_b] = true;
13421    this.varOffset = null;
13422    /**
13423     * Once extracted to the `ConstantPool`, a reference to the function which defines the computation
13424     * of `body`.
13425     */
13426    this.fn = null;
13427    this.body = expression;
13428    this.args = args;
13429  }
13430  visitExpression(visitor, context) {
13431    this.body?.visitExpression(visitor, context);
13432    for (const arg of this.args) {
13433      arg.visitExpression(visitor, context);
13434    }
13435  }
13436  isEquivalent(other) {
13437    if (!(other instanceof PureFunctionExpr) || other.args.length !== this.args.length) {
13438      return false;
13439    }
13440    return other.body !== null && this.body !== null && other.body.isEquivalent(this.body) && other.args.every((arg, idx) => arg.isEquivalent(this.args[idx]));
13441  }
13442  isConstant() {
13443    return false;
13444  }
13445  transformInternalExpressions(transform, flags) {
13446    if (this.body !== null) {
13447      // TODO: figure out if this is the right flag to pass here.
13448      this.body = transformExpressionsInExpression(this.body, transform, flags | VisitorContextFlag.InChildOperation);
13449    } else if (this.fn !== null) {
13450      this.fn = transformExpressionsInExpression(this.fn, transform, flags);
13451    }
13452    for (let i = 0; i < this.args.length; i++) {
13453      this.args[i] = transformExpressionsInExpression(this.args[i], transform, flags);
13454    }
13455  }
13456  clone() {
13457    const expr = new PureFunctionExpr(this.body?.clone() ?? null, this.args.map(arg => arg.clone()));
13458    expr.fn = this.fn?.clone() ?? null;
13459    expr.varOffset = this.varOffset;
13460    return expr;
13461  }
13462}
13463class PureFunctionParameterExpr extends ExpressionBase {
13464  constructor(index) {
13465    super();
13466    this.index = index;
13467    this.kind = ExpressionKind.PureFunctionParameterExpr;
13468  }
13469  visitExpression() {}
13470  isEquivalent(other) {
13471    return other instanceof PureFunctionParameterExpr && other.index === this.index;
13472  }
13473  isConstant() {
13474    return true;
13475  }
13476  transformInternalExpressions() {}
13477  clone() {
13478    return new PureFunctionParameterExpr(this.index);
13479  }
13480}
13481class PipeBindingExpr extends ExpressionBase {
13482  static #_ = (_c = ConsumesVarsTrait, _d = UsesVarOffset);
13483  constructor(target, targetSlot, name, args) {
13484    super();
13485    this.target = target;
13486    this.targetSlot = targetSlot;
13487    this.name = name;
13488    this.args = args;
13489    this.kind = ExpressionKind.PipeBinding;
13490    this[_c] = true;
13491    this[_d] = true;
13492    this.varOffset = null;
13493  }
13494  visitExpression(visitor, context) {
13495    for (const arg of this.args) {
13496      arg.visitExpression(visitor, context);
13497    }
13498  }
13499  isEquivalent() {
13500    return false;
13501  }
13502  isConstant() {
13503    return false;
13504  }
13505  transformInternalExpressions(transform, flags) {
13506    for (let idx = 0; idx < this.args.length; idx++) {
13507      this.args[idx] = transformExpressionsInExpression(this.args[idx], transform, flags);
13508    }
13509  }
13510  clone() {
13511    const r = new PipeBindingExpr(this.target, this.targetSlot, this.name, this.args.map(a => a.clone()));
13512    r.varOffset = this.varOffset;
13513    return r;
13514  }
13515}
13516class PipeBindingVariadicExpr extends ExpressionBase {
13517  static #_ = (_e = ConsumesVarsTrait, _f = UsesVarOffset);
13518  constructor(target, targetSlot, name, args, numArgs) {
13519    super();
13520    this.target = target;
13521    this.targetSlot = targetSlot;
13522    this.name = name;
13523    this.args = args;
13524    this.numArgs = numArgs;
13525    this.kind = ExpressionKind.PipeBindingVariadic;
13526    this[_e] = true;
13527    this[_f] = true;
13528    this.varOffset = null;
13529  }
13530  visitExpression(visitor, context) {
13531    this.args.visitExpression(visitor, context);
13532  }
13533  isEquivalent() {
13534    return false;
13535  }
13536  isConstant() {
13537    return false;
13538  }
13539  transformInternalExpressions(transform, flags) {
13540    this.args = transformExpressionsInExpression(this.args, transform, flags);
13541  }
13542  clone() {
13543    const r = new PipeBindingVariadicExpr(this.target, this.targetSlot, this.name, this.args.clone(), this.numArgs);
13544    r.varOffset = this.varOffset;
13545    return r;
13546  }
13547}
13548class SafePropertyReadExpr extends ExpressionBase {
13549  constructor(receiver, name) {
13550    super();
13551    this.receiver = receiver;
13552    this.name = name;
13553    this.kind = ExpressionKind.SafePropertyRead;
13554  }
13555  // An alias for name, which allows other logic to handle property reads and keyed reads together.
13556  get index() {
13557    return this.name;
13558  }
13559  visitExpression(visitor, context) {
13560    this.receiver.visitExpression(visitor, context);
13561  }
13562  isEquivalent() {
13563    return false;
13564  }
13565  isConstant() {
13566    return false;
13567  }
13568  transformInternalExpressions(transform, flags) {
13569    this.receiver = transformExpressionsInExpression(this.receiver, transform, flags);
13570  }
13571  clone() {
13572    return new SafePropertyReadExpr(this.receiver.clone(), this.name);
13573  }
13574}
13575class SafeKeyedReadExpr extends ExpressionBase {
13576  constructor(receiver, index, sourceSpan) {
13577    super(sourceSpan);
13578    this.receiver = receiver;
13579    this.index = index;
13580    this.kind = ExpressionKind.SafeKeyedRead;
13581  }
13582  visitExpression(visitor, context) {
13583    this.receiver.visitExpression(visitor, context);
13584    this.index.visitExpression(visitor, context);
13585  }
13586  isEquivalent() {
13587    return false;
13588  }
13589  isConstant() {
13590    return false;
13591  }
13592  transformInternalExpressions(transform, flags) {
13593    this.receiver = transformExpressionsInExpression(this.receiver, transform, flags);
13594    this.index = transformExpressionsInExpression(this.index, transform, flags);
13595  }
13596  clone() {
13597    return new SafeKeyedReadExpr(this.receiver.clone(), this.index.clone(), this.sourceSpan);
13598  }
13599}
13600class SafeInvokeFunctionExpr extends ExpressionBase {
13601  constructor(receiver, args) {
13602    super();
13603    this.receiver = receiver;
13604    this.args = args;
13605    this.kind = ExpressionKind.SafeInvokeFunction;
13606  }
13607  visitExpression(visitor, context) {
13608    this.receiver.visitExpression(visitor, context);
13609    for (const a of this.args) {
13610      a.visitExpression(visitor, context);
13611    }
13612  }
13613  isEquivalent() {
13614    return false;
13615  }
13616  isConstant() {
13617    return false;
13618  }
13619  transformInternalExpressions(transform, flags) {
13620    this.receiver = transformExpressionsInExpression(this.receiver, transform, flags);
13621    for (let i = 0; i < this.args.length; i++) {
13622      this.args[i] = transformExpressionsInExpression(this.args[i], transform, flags);
13623    }
13624  }
13625  clone() {
13626    return new SafeInvokeFunctionExpr(this.receiver.clone(), this.args.map(a => a.clone()));
13627  }
13628}
13629class SafeTernaryExpr extends ExpressionBase {
13630  constructor(guard, expr) {
13631    super();
13632    this.guard = guard;
13633    this.expr = expr;
13634    this.kind = ExpressionKind.SafeTernaryExpr;
13635  }
13636  visitExpression(visitor, context) {
13637    this.guard.visitExpression(visitor, context);
13638    this.expr.visitExpression(visitor, context);
13639  }
13640  isEquivalent() {
13641    return false;
13642  }
13643  isConstant() {
13644    return false;
13645  }
13646  transformInternalExpressions(transform, flags) {
13647    this.guard = transformExpressionsInExpression(this.guard, transform, flags);
13648    this.expr = transformExpressionsInExpression(this.expr, transform, flags);
13649  }
13650  clone() {
13651    return new SafeTernaryExpr(this.guard.clone(), this.expr.clone());
13652  }
13653}
13654class EmptyExpr extends ExpressionBase {
13655  constructor() {
13656    super(...arguments);
13657    this.kind = ExpressionKind.EmptyExpr;
13658  }
13659  visitExpression(visitor, context) {}
13660  isEquivalent(e) {
13661    return e instanceof EmptyExpr;
13662  }
13663  isConstant() {
13664    return true;
13665  }
13666  clone() {
13667    return new EmptyExpr();
13668  }
13669  transformInternalExpressions() {}
13670}
13671class AssignTemporaryExpr extends ExpressionBase {
13672  constructor(expr, xref) {
13673    super();
13674    this.expr = expr;
13675    this.xref = xref;
13676    this.kind = ExpressionKind.AssignTemporaryExpr;
13677    this.name = null;
13678  }
13679  visitExpression(visitor, context) {
13680    this.expr.visitExpression(visitor, context);
13681  }
13682  isEquivalent() {
13683    return false;
13684  }
13685  isConstant() {
13686    return false;
13687  }
13688  transformInternalExpressions(transform, flags) {
13689    this.expr = transformExpressionsInExpression(this.expr, transform, flags);
13690  }
13691  clone() {
13692    const a = new AssignTemporaryExpr(this.expr.clone(), this.xref);
13693    a.name = this.name;
13694    return a;
13695  }
13696}
13697class ReadTemporaryExpr extends ExpressionBase {
13698  constructor(xref) {
13699    super();
13700    this.xref = xref;
13701    this.kind = ExpressionKind.ReadTemporaryExpr;
13702    this.name = null;
13703  }
13704  visitExpression(visitor, context) {}
13705  isEquivalent() {
13706    return this.xref === this.xref;
13707  }
13708  isConstant() {
13709    return false;
13710  }
13711  transformInternalExpressions(transform, flags) {}
13712  clone() {
13713    const r = new ReadTemporaryExpr(this.xref);
13714    r.name = this.name;
13715    return r;
13716  }
13717}
13718class SlotLiteralExpr extends ExpressionBase {
13719  constructor(slot) {
13720    super();
13721    this.slot = slot;
13722    this.kind = ExpressionKind.SlotLiteralExpr;
13723  }
13724  visitExpression(visitor, context) {}
13725  isEquivalent(e) {
13726    return e instanceof SlotLiteralExpr && e.slot === this.slot;
13727  }
13728  isConstant() {
13729    return true;
13730  }
13731  clone() {
13732    return new SlotLiteralExpr(this.slot);
13733  }
13734  transformInternalExpressions() {}
13735}
13736class ConditionalCaseExpr extends ExpressionBase {
13737  /**
13738   * Create an expression for one branch of a conditional.
13739   * @param expr The expression to be tested for this case. Might be null, as in an `else` case.
13740   * @param target The Xref of the view to be displayed if this condition is true.
13741   */
13742  constructor(expr, target, targetSlot, alias = null) {
13743    super();
13744    this.expr = expr;
13745    this.target = target;
13746    this.targetSlot = targetSlot;
13747    this.alias = alias;
13748    this.kind = ExpressionKind.ConditionalCase;
13749  }
13750  visitExpression(visitor, context) {
13751    if (this.expr !== null) {
13752      this.expr.visitExpression(visitor, context);
13753    }
13754  }
13755  isEquivalent(e) {
13756    return e instanceof ConditionalCaseExpr && e.expr === this.expr;
13757  }
13758  isConstant() {
13759    return true;
13760  }
13761  clone() {
13762    return new ConditionalCaseExpr(this.expr, this.target, this.targetSlot);
13763  }
13764  transformInternalExpressions(transform, flags) {
13765    if (this.expr !== null) {
13766      this.expr = transformExpressionsInExpression(this.expr, transform, flags);
13767    }
13768  }
13769}
13770class ConstCollectedExpr extends ExpressionBase {
13771  constructor(expr) {
13772    super();
13773    this.expr = expr;
13774    this.kind = ExpressionKind.ConstCollected;
13775  }
13776  transformInternalExpressions(transform, flags) {
13777    this.expr = transform(this.expr, flags);
13778  }
13779  visitExpression(visitor, context) {
13780    this.expr.visitExpression(visitor, context);
13781  }
13782  isEquivalent(e) {
13783    if (!(e instanceof ConstCollectedExpr)) {
13784      return false;
13785    }
13786    return this.expr.isEquivalent(e.expr);
13787  }
13788  isConstant() {
13789    return this.expr.isConstant();
13790  }
13791  clone() {
13792    return new ConstCollectedExpr(this.expr);
13793  }
13794}
13795/**
13796 * Visits all `Expression`s in the AST of `op` with the `visitor` function.
13797 */
13798function visitExpressionsInOp(op, visitor) {
13799  transformExpressionsInOp(op, (expr, flags) => {
13800    visitor(expr, flags);
13801    return expr;
13802  }, VisitorContextFlag.None);
13803}
13804var VisitorContextFlag;
13805(function (VisitorContextFlag) {
13806  VisitorContextFlag[VisitorContextFlag["None"] = 0] = "None";
13807  VisitorContextFlag[VisitorContextFlag["InChildOperation"] = 1] = "InChildOperation";
13808})(VisitorContextFlag || (VisitorContextFlag = {}));
13809function transformExpressionsInInterpolation(interpolation, transform, flags) {
13810  for (let i = 0; i < interpolation.expressions.length; i++) {
13811    interpolation.expressions[i] = transformExpressionsInExpression(interpolation.expressions[i], transform, flags);
13812  }
13813}
13814/**
13815 * Transform all `Expression`s in the AST of `op` with the `transform` function.
13816 *
13817 * All such operations will be replaced with the result of applying `transform`, which may be an
13818 * identity transformation.
13819 */
13820function transformExpressionsInOp(op, transform, flags) {
13821  switch (op.kind) {
13822    case OpKind.StyleProp:
13823    case OpKind.StyleMap:
13824    case OpKind.ClassProp:
13825    case OpKind.ClassMap:
13826    case OpKind.Binding:
13827      if (op.expression instanceof Interpolation) {
13828        transformExpressionsInInterpolation(op.expression, transform, flags);
13829      } else {
13830        op.expression = transformExpressionsInExpression(op.expression, transform, flags);
13831      }
13832      break;
13833    case OpKind.Property:
13834    case OpKind.HostProperty:
13835    case OpKind.Attribute:
13836      if (op.expression instanceof Interpolation) {
13837        transformExpressionsInInterpolation(op.expression, transform, flags);
13838      } else {
13839        op.expression = transformExpressionsInExpression(op.expression, transform, flags);
13840      }
13841      op.sanitizer = op.sanitizer && transformExpressionsInExpression(op.sanitizer, transform, flags);
13842      break;
13843    case OpKind.TwoWayProperty:
13844      op.expression = transformExpressionsInExpression(op.expression, transform, flags);
13845      op.sanitizer = op.sanitizer && transformExpressionsInExpression(op.sanitizer, transform, flags);
13846      break;
13847    case OpKind.I18nExpression:
13848      op.expression = transformExpressionsInExpression(op.expression, transform, flags);
13849      break;
13850    case OpKind.InterpolateText:
13851      transformExpressionsInInterpolation(op.interpolation, transform, flags);
13852      break;
13853    case OpKind.Statement:
13854      transformExpressionsInStatement(op.statement, transform, flags);
13855      break;
13856    case OpKind.Variable:
13857      op.initializer = transformExpressionsInExpression(op.initializer, transform, flags);
13858      break;
13859    case OpKind.Conditional:
13860      for (const condition of op.conditions) {
13861        if (condition.expr === null) {
13862          // This is a default case.
13863          continue;
13864        }
13865        condition.expr = transformExpressionsInExpression(condition.expr, transform, flags);
13866      }
13867      if (op.processed !== null) {
13868        op.processed = transformExpressionsInExpression(op.processed, transform, flags);
13869      }
13870      if (op.contextValue !== null) {
13871        op.contextValue = transformExpressionsInExpression(op.contextValue, transform, flags);
13872      }
13873      break;
13874    case OpKind.Listener:
13875    case OpKind.TwoWayListener:
13876      for (const innerOp of op.handlerOps) {
13877        transformExpressionsInOp(innerOp, transform, flags | VisitorContextFlag.InChildOperation);
13878      }
13879      break;
13880    case OpKind.ExtractedAttribute:
13881      op.expression = op.expression && transformExpressionsInExpression(op.expression, transform, flags);
13882      op.trustedValueFn = op.trustedValueFn && transformExpressionsInExpression(op.trustedValueFn, transform, flags);
13883      break;
13884    case OpKind.RepeaterCreate:
13885      op.track = transformExpressionsInExpression(op.track, transform, flags);
13886      if (op.trackByFn !== null) {
13887        op.trackByFn = transformExpressionsInExpression(op.trackByFn, transform, flags);
13888      }
13889      break;
13890    case OpKind.Repeater:
13891      op.collection = transformExpressionsInExpression(op.collection, transform, flags);
13892      break;
13893    case OpKind.Defer:
13894      if (op.loadingConfig !== null) {
13895        op.loadingConfig = transformExpressionsInExpression(op.loadingConfig, transform, flags);
13896      }
13897      if (op.placeholderConfig !== null) {
13898        op.placeholderConfig = transformExpressionsInExpression(op.placeholderConfig, transform, flags);
13899      }
13900      if (op.resolverFn !== null) {
13901        op.resolverFn = transformExpressionsInExpression(op.resolverFn, transform, flags);
13902      }
13903      break;
13904    case OpKind.I18nMessage:
13905      for (const [placeholder, expr] of op.params) {
13906        op.params.set(placeholder, transformExpressionsInExpression(expr, transform, flags));
13907      }
13908      for (const [placeholder, expr] of op.postprocessingParams) {
13909        op.postprocessingParams.set(placeholder, transformExpressionsInExpression(expr, transform, flags));
13910      }
13911      break;
13912    case OpKind.DeferWhen:
13913      op.expr = transformExpressionsInExpression(op.expr, transform, flags);
13914      break;
13915    case OpKind.Advance:
13916    case OpKind.Container:
13917    case OpKind.ContainerEnd:
13918    case OpKind.ContainerStart:
13919    case OpKind.DeferOn:
13920    case OpKind.DisableBindings:
13921    case OpKind.Element:
13922    case OpKind.ElementEnd:
13923    case OpKind.ElementStart:
13924    case OpKind.EnableBindings:
13925    case OpKind.I18n:
13926    case OpKind.I18nApply:
13927    case OpKind.I18nContext:
13928    case OpKind.I18nEnd:
13929    case OpKind.I18nStart:
13930    case OpKind.IcuEnd:
13931    case OpKind.IcuStart:
13932    case OpKind.Namespace:
13933    case OpKind.Pipe:
13934    case OpKind.Projection:
13935    case OpKind.ProjectionDef:
13936    case OpKind.Template:
13937    case OpKind.Text:
13938    case OpKind.I18nAttributes:
13939    case OpKind.IcuPlaceholder:
13940      // These operations contain no expressions.
13941      break;
13942    default:
13943      throw new Error(`AssertionError: transformExpressionsInOp doesn't handle ${OpKind[op.kind]}`);
13944  }
13945}
13946/**
13947 * Transform all `Expression`s in the AST of `expr` with the `transform` function.
13948 *
13949 * All such operations will be replaced with the result of applying `transform`, which may be an
13950 * identity transformation.
13951 */
13952function transformExpressionsInExpression(expr, transform, flags) {
13953  if (expr instanceof ExpressionBase) {
13954    expr.transformInternalExpressions(transform, flags);
13955  } else if (expr instanceof BinaryOperatorExpr) {
13956    expr.lhs = transformExpressionsInExpression(expr.lhs, transform, flags);
13957    expr.rhs = transformExpressionsInExpression(expr.rhs, transform, flags);
13958  } else if (expr instanceof UnaryOperatorExpr) {
13959    expr.expr = transformExpressionsInExpression(expr.expr, transform, flags);
13960  } else if (expr instanceof ReadPropExpr) {
13961    expr.receiver = transformExpressionsInExpression(expr.receiver, transform, flags);
13962  } else if (expr instanceof ReadKeyExpr) {
13963    expr.receiver = transformExpressionsInExpression(expr.receiver, transform, flags);
13964    expr.index = transformExpressionsInExpression(expr.index, transform, flags);
13965  } else if (expr instanceof WritePropExpr) {
13966    expr.receiver = transformExpressionsInExpression(expr.receiver, transform, flags);
13967    expr.value = transformExpressionsInExpression(expr.value, transform, flags);
13968  } else if (expr instanceof WriteKeyExpr) {
13969    expr.receiver = transformExpressionsInExpression(expr.receiver, transform, flags);
13970    expr.index = transformExpressionsInExpression(expr.index, transform, flags);
13971    expr.value = transformExpressionsInExpression(expr.value, transform, flags);
13972  } else if (expr instanceof InvokeFunctionExpr) {
13973    expr.fn = transformExpressionsInExpression(expr.fn, transform, flags);
13974    for (let i = 0; i < expr.args.length; i++) {
13975      expr.args[i] = transformExpressionsInExpression(expr.args[i], transform, flags);
13976    }
13977  } else if (expr instanceof LiteralArrayExpr) {
13978    for (let i = 0; i < expr.entries.length; i++) {
13979      expr.entries[i] = transformExpressionsInExpression(expr.entries[i], transform, flags);
13980    }
13981  } else if (expr instanceof LiteralMapExpr) {
13982    for (let i = 0; i < expr.entries.length; i++) {
13983      expr.entries[i].value = transformExpressionsInExpression(expr.entries[i].value, transform, flags);
13984    }
13985  } else if (expr instanceof ConditionalExpr) {
13986    expr.condition = transformExpressionsInExpression(expr.condition, transform, flags);
13987    expr.trueCase = transformExpressionsInExpression(expr.trueCase, transform, flags);
13988    if (expr.falseCase !== null) {
13989      expr.falseCase = transformExpressionsInExpression(expr.falseCase, transform, flags);
13990    }
13991  } else if (expr instanceof TypeofExpr) {
13992    expr.expr = transformExpressionsInExpression(expr.expr, transform, flags);
13993  }
13993 else if (expr instanceof WriteVarExpr) {
13994    expr.value = transformExpressionsInExpression(expr.value, transform, flags);
13995  } else if (expr instanceof LocalizedString) {
13996    for (let i = 0; i < expr.expressions.length; i++) {
13997      expr.expressions[i] = transformExpressionsInExpression(expr.expressions[i], transform, flags);
13998    }
13999  } else if (expr instanceof NotExpr) {
14000    expr.condition = transformExpressionsInExpression(expr.condition, transform, flags);
14001  } else if (expr instanceof TaggedTemplateExpr) {
14002    expr.tag = transformExpressionsInExpression(expr.tag, transform, flags);
14003    expr.template.expressions = expr.template.expressions.map(e => transformExpressionsInExpression(e, transform, flags));
14004  } else if (expr instanceof ArrowFunctionExpr) {
14005    if (Array.isArray(expr.body)) {
14006      for (let i = 0; i < expr.body.length; i++) {
14007        transformExpressionsInStatement(expr.body[i], transform, flags);
14008      }
14009    } else {
14010      expr.body = transformExpressionsInExpression(expr.body, transform, flags);
14011    }
14012  } else if (expr instanceof WrappedNodeExpr) {
14013    // TODO: Do we need to transform any TS nodes nested inside of this expression?
14014  } else if (expr instanceof ReadVarExpr || expr instanceof ExternalExpr || expr instanceof LiteralExpr) {
14015    // No action for these types.
14016  } else {
14017    throw new Error(`Unhandled expression kind: ${expr.constructor.name}`);
14018  }
14019  return transform(expr, flags);
14020}
14021/**
14022 * Transform all `Expression`s in the AST of `stmt` with the `transform` function.
14023 *
14024 * All such operations will be replaced with the result of applying `transform`, which may be an
14025 * identity transformation.
14026 */
14027function transformExpressionsInStatement(stmt, transform, flags) {
14028  if (stmt instanceof ExpressionStatement) {
14029    stmt.expr = transformExpressionsInExpression(stmt.expr, transform, flags);
14030  } else if (stmt instanceof ReturnStatement) {
14031    stmt.value = transformExpressionsInExpression(stmt.value, transform, flags);
14032  } else if (stmt instanceof DeclareVarStmt) {
14033    if (stmt.value !== undefined) {
14034      stmt.value = transformExpressionsInExpression(stmt.value, transform, flags);
14035    }
14036  } else if (stmt instanceof IfStmt) {
14037    stmt.condition = transformExpressionsInExpression(stmt.condition, transform, flags);
14038    for (const caseStatement of stmt.trueCase) {
14039      transformExpressionsInStatement(caseStatement, transform, flags);
14040    }
14041    for (const caseStatement of stmt.falseCase) {
14042      transformExpressionsInStatement(caseStatement, transform, flags);
14043    }
14044  } else {
14045    throw new Error(`Unhandled statement kind: ${stmt.constructor.name}`);
14046  }
14047}
14048/**
14049 * Checks whether the given expression is a string literal.
14050 */
14051function isStringLiteral(expr) {
14052  return expr instanceof LiteralExpr && typeof expr.value === 'string';
14053}
14054
14055/**
14056 * A linked list of `Op` nodes of a given subtype.
14057 *
14058 * @param OpT specific subtype of `Op` nodes which this list contains.
14059 */
14060class OpList {
14061  static #_ = this.nextListId = 0;
14062  constructor() {
14063    /**
14064     * Debug ID of this `OpList` instance.
14065     */
14066    this.debugListId = OpList.nextListId++;
14067    // OpList uses static head/tail nodes of a special `ListEnd` type.
14068    // This avoids the need for special casing of the first and last list
14069    // elements in all list operations.
14070    this.head = {
14071      kind: OpKind.ListEnd,
14072      next: null,
14073      prev: null,
14074      debugListId: this.debugListId
14075    };
14076    this.tail = {
14077      kind: OpKind.ListEnd,
14078      next: null,
14079      prev: null,
14080      debugListId: this.debugListId
14081    };
14082    // Link `head` and `tail` together at the start (list is empty).
14083    this.head.next = this.tail;
14084    this.tail.prev = this.head;
14085  }
14086  /**
14087   * Push a new operation to the tail of the list.
14088   */
14089  push(op) {
14090    if (Array.isArray(op)) {
14091      for (const o of op) {
14092        this.push(o);
14093      }
14094      return;
14095    }
14096    OpList.assertIsNotEnd(op);
14097    OpList.assertIsUnowned(op);
14098    op.debugListId = this.debugListId;
14099    // The old "previous" node (which might be the head, if the list is empty).
14100    const oldLast = this.tail.prev;
14101    // Insert `op` following the old last node.
14102    op.prev = oldLast;
14103    oldLast.next = op;
14104    // Connect `op` with the list tail.
14105    op.next = this.tail;
14106    this.tail.prev = op;
14107  }
14108  /**
14109   * Prepend one or more nodes to the start of the list.
14110   */
14111  prepend(ops) {
14112    if (ops.length === 0) {
14113      return;
14114    }
14115    for (const op of ops) {
14116      OpList.assertIsNotEnd(op);
14117      OpList.assertIsUnowned(op);
14118      op.debugListId = this.debugListId;
14119    }
14120    const first = this.head.next;
14121    let prev = this.head;
14122    for (const op of ops) {
14123      prev.next = op;
14124      op.prev = prev;
14125      prev = op;
14126    }
14127    prev.next = first;
14128    first.prev = prev;
14129  }
14130  /**
14131   * `OpList` is iterable via the iteration protocol.
14132   *
14133   * It's safe to mutate the part of the list that has already been returned by the iterator, up to
14134   * and including the last operation returned. Mutations beyond that point _may_ be safe, but may
14135   * also corrupt the iteration position and should be avoided.
14136   */
14137  *[Symbol.iterator]() {
14138    let current = this.head.next;
14139    while (current !== this.tail) {
14140      // Guards against corruption of the iterator state by mutations to the tail of the list during
14141      // iteration.
14142      OpList.assertIsOwned(current, this.debugListId);
14143      const next = current.next;
14144      yield current;
14145      current = next;
14146    }
14147  }
14148  *reversed() {
14149    let current = this.tail.prev;
14150    while (current !== this.head) {
14151      OpList.assertIsOwned(current, this.debugListId);
14152      const prev = current.prev;
14153      yield current;
14154      current = prev;
14155    }
14156  }
14157  /**
14158   * Replace `oldOp` with `newOp` in the list.
14159   */
14160  static replace(oldOp, newOp) {
14161    OpList.assertIsNotEnd(oldOp);
14162    OpList.assertIsNotEnd(newOp);
14163    OpList.assertIsOwned(oldOp);
14164    OpList.assertIsUnowned(newOp);
14165    newOp.debugListId = oldOp.debugListId;
14166    if (oldOp.prev !== null) {
14167      oldOp.prev.next = newOp;
14168      newOp.prev = oldOp.prev;
14169    }
14170    if (oldOp.next !== null) {
14171      oldOp.next.prev = newOp;
14172      newOp.next = oldOp.next;
14173    }
14174    oldOp.debugListId = null;
14175    oldOp.prev = null;
14176    oldOp.next = null;
14177  }
14178  /**
14179   * Replace `oldOp` with some number of new operations in the list (which may include `oldOp`).
14180   */
14181  static replaceWithMany(oldOp, newOps) {
14182    if (newOps.length === 0) {
14183      // Replacing with an empty list -> pure removal.
14184      OpList.remove(oldOp);
14185      return;
14186    }
14187    OpList.assertIsNotEnd(oldOp);
14188    OpList.assertIsOwned(oldOp);
14189    const listId = oldOp.debugListId;
14190    oldOp.debugListId = null;
14191    for (const newOp of newOps) {
14192      OpList.assertIsNotEnd(newOp);
14193      // `newOp` might be `oldOp`, but at this point it's been marked as unowned.
14194      OpList.assertIsUnowned(newOp);
14195    }
14196    // It should be safe to reuse `oldOp` in the `newOps` list - maybe you want to sandwich an
14197    // operation between two new ops.
14198    const {
14199      prev: oldPrev,
14200      next: oldNext
14201    } = oldOp;
14202    oldOp.prev = null;
14203    oldOp.next = null;
14204    let prev = oldPrev;
14205    for (const newOp of newOps) {
14206      this.assertIsUnowned(newOp);
14207      newOp.debugListId = listId;
14208      prev.next = newOp;
14209      newOp.prev = prev;
14210      // This _should_ be the case, but set it just in case.
14211      newOp.next = null;
14212      prev = newOp;
14213    }
14214    // At the end of iteration, `prev` holds the last node in the list.
14215    const first = newOps[0];
14216    const last = prev;
14217    // Replace `oldOp` with the chain `first` -> `last`.
14218    if (oldPrev !== null) {
14219      oldPrev.next = first;
14220      first.prev = oldPrev;
14221    }
14222    if (oldNext !== null) {
14223      oldNext.prev = last;
14224      last.next = oldNext;
14225    }
14226  }
14227  /**
14228   * Remove the given node from the list which contains it.
14229   */
14230  static remove(op) {
14231    OpList.assertIsNotEnd(op);
14232    OpList.assertIsOwned(op);
14233    op.prev.next = op.next;
14234    op.next.prev = op.prev;
14235    // Break any link between the node and this list to safeguard against its usage in future
14236    // operations.
14237    op.debugListId = null;
14238    op.prev = null;
14239    op.next = null;
14240  }
14241  /**
14242   * Insert `op` before `target`.
14243   */
14244  static insertBefore(op, target) {
14245    if (Array.isArray(op)) {
14246      for (const o of op) {
14247        this.insertBefore(o, target);
14248      }
14249      return;
14250    }
14251    OpList.assertIsOwned(target);
14252    if (target.prev === null) {
14253      throw new Error(`AssertionError: illegal operation on list start`);
14254    }
14255    OpList.assertIsNotEnd(op);
14256    OpList.assertIsUnowned(op);
14257    op.debugListId = target.debugListId;
14258    // Just in case.
14259    op.prev = null;
14260    target.prev.next = op;
14261    op.prev = target.prev;
14262    op.next = target;
14263    target.prev = op;
14264  }
14265  /**
14266   * Insert `op` after `target`.
14267   */
14268  static insertAfter(op, target) {
14269    OpList.assertIsOwned(target);
14270    if (target.next === null) {
14271      throw new Error(`AssertionError: illegal operation on list end`);
14272    }
14273    OpList.assertIsNotEnd(op);
14274    OpList.assertIsUnowned(op);
14275    op.debugListId = target.debugListId;
14276    target.next.prev = op;
14277    op.next = target.next;
14278    op.prev = target;
14279    target.next = op;
14280  }
14281  /**
14282   * Asserts that `op` does not currently belong to a list.
14283   */
14284  static assertIsUnowned(op) {
14285    if (op.debugListId !== null) {
14286      throw new Error(`AssertionError: illegal operation on owned node: ${OpKind[op.kind]}`);
14287    }
14288  }
14289  /**
14290   * Asserts that `op` currently belongs to a list. If `byList` is passed, `op` is asserted to
14291   * specifically belong to that list.
14292   */
14293  static assertIsOwned(op, byList) {
14294    if (op.debugListId === null) {
14295      throw new Error(`AssertionError: illegal operation on unowned node: ${OpKind[op.kind]}`);
14296    } else if (byList !== undefined && op.debugListId !== byList) {
14297      throw new Error(`AssertionError: node belongs to the wrong list (expected ${byList}, actual ${op.debugListId})`);
14298    }
14299  }
14300  /**
14301   * Asserts that `op` is not a special `ListEnd` node.
14302   */
14303  static assertIsNotEnd(op) {
14304    if (op.kind === OpKind.ListEnd) {
14305      throw new Error(`AssertionError: illegal operation on list head or tail`);
14306    }
14307  }
14308}
14309class SlotHandle {
14310  constructor() {
14311    this.slot = null;
14312  }
14313}
14314
14315/**
14316 * The set of OpKinds that represent the creation of an element or container
14317 */
14318const elementContainerOpKinds = new Set([OpKind.Element, OpKind.ElementStart, OpKind.Container, OpKind.ContainerStart, OpKind.Template, OpKind.RepeaterCreate]);
14319/**
14320 * Checks whether the given operation represents the creation of an element or container.
14321 */
14322function isElementOrContainerOp(op) {
14323  return elementContainerOpKinds.has(op.kind);
14324}
14325/**
14326 * Create an `ElementStartOp`.
14327 */
14328function createElementStartOp(tag, xref, namespace, i18nPlaceholder, startSourceSpan, wholeSourceSpan) {
14329  return {
14330    kind: OpKind.ElementStart,
14331    xref,
14332    tag,
14333    handle: new SlotHandle(),
14334    attributes: null,
14335    localRefs: [],
14336    nonBindable: false,
14337    namespace,
14338    i18nPlaceholder,
14339    startSourceSpan,
14340    wholeSourceSpan,
14341    ...TRAIT_CONSUMES_SLOT,
14342    ...NEW_OP
14343  };
14344}
14345/**
14346 * Create a `TemplateOp`.
14347 */
14348function createTemplateOp(xref, templateKind, tag, functionNameSuffix, namespace, i18nPlaceholder, startSourceSpan, wholeSourceSpan) {
14349  return {
14350    kind: OpKind.Template,
14351    xref,
14352    templateKind,
14353    attributes: null,
14354    tag,
14355    handle: new SlotHandle(),
14356    functionNameSuffix,
14357    decls: null,
14358    vars: null,
14359    localRefs: [],
14360    nonBindable: false,
14361    namespace,
14362    i18nPlaceholder,
14363    startSourceSpan,
14364    wholeSourceSpan,
14365    ...TRAIT_CONSUMES_SLOT,
14366    ...NEW_OP
14367  };
14368}
14369function createRepeaterCreateOp(primaryView, emptyView, tag, track, varNames, emptyTag, i18nPlaceholder, emptyI18nPlaceholder, startSourceSpan, wholeSourceSpan) {
14370  return {
14371    kind: OpKind.RepeaterCreate,
14372    attributes: null,
14373    xref: primaryView,
14374    handle: new SlotHandle(),
14375    emptyView,
14376    track,
14377    trackByFn: null,
14378    tag,
14379    emptyTag,
14380    emptyAttributes: null,
14381    functionNameSuffix: 'For',
14382    namespace: Namespace.HTML,
14383    nonBindable: false,
14384    localRefs: [],
14385    decls: null,
14386    vars: null,
14387    varNames,
14388    usesComponentInstance: false,
14389    i18nPlaceholder,
14390    emptyI18nPlaceholder,
14391    startSourceSpan,
14392    wholeSourceSpan,
14393    ...TRAIT_CONSUMES_SLOT,
14394    ...NEW_OP,
14395    ...TRAIT_CONSUMES_VARS,
14396    numSlotsUsed: emptyView === null ? 2 : 3
14397  };
14398}
14399/**
14400 * Create an `ElementEndOp`.
14401 */
14402function createElementEndOp(xref, sourceSpan) {
14403  return {
14404    kind: OpKind.ElementEnd,
14405    xref,
14406    sourceSpan,
14407    ...NEW_OP
14408  };
14409}
14410function createDisableBindingsOp(xref) {
14411  return {
14412    kind: OpKind.DisableBindings,
14413    xref,
14414    ...NEW_OP
14415  };
14416}
14417function createEnableBindingsOp(xref) {
14418  return {
14419    kind: OpKind.EnableBindings,
14420    xref,
14421    ...NEW_OP
14422  };
14423}
14424/**
14425 * Create a `TextOp`.
14426 */
14427function createTextOp(xref, initialValue, icuPlaceholder, sourceSpan) {
14428  return {
14429    kind: OpKind.Text,
14430    xref,
14431    handle: new SlotHandle(),
14432    initialValue,
14433    icuPlaceholder,
14434    sourceSpan,
14435    ...TRAIT_CONSUMES_SLOT,
14436    ...NEW_OP
14437  };
14438}
14439/**
14440 * Create a `ListenerOp`. Host bindings reuse all the listener logic.
14441 */
14442function createListenerOp(target, targetSlot, name, tag, handlerOps, animationPhase, eventTarget, hostListener, sourceSpan) {
14443  const handlerList = new OpList();
14444  handlerList.push(handlerOps);
14445  return {
14446    kind: OpKind.Listener,
14447    target,
14448    targetSlot,
14449    tag,
14450    hostListener,
14451    name,
14452    handlerOps: handlerList,
14453    handlerFnName: null,
14454    consumesDollarEvent: false,
14455    isAnimationListener: animationPhase !== null,
14456    animationPhase,
14457    eventTarget,
14458    sourceSpan,
14459    ...NEW_OP
14460  };
14461}
14462/**
14463 * Create a `TwoWayListenerOp`.
14464 */
14465function createTwoWayListenerOp(target, targetSlot, name, tag, handlerOps, sourceSpan) {
14466  const handlerList = new OpList();
14467  handlerList.push(handlerOps);
14468  return {
14469    kind: OpKind.TwoWayListener,
14470    target,
14471    targetSlot,
14472    tag,
14473    name,
14474    handlerOps: handlerList,
14475    handlerFnName: null,
14476    sourceSpan,
14477    ...NEW_OP
14478  };
14479}
14480function createPipeOp(xref, slot, name) {
14481  return {
14482    kind: OpKind.Pipe,
14483    xref,
14484    handle: slot,
14485    name,
14486    ...NEW_OP,
14487    ...TRAIT_CONSUMES_SLOT
14488  };
14489}
14490function createNamespaceOp(namespace) {
14491  return {
14492    kind: OpKind.Namespace,
14493    active: namespace,
14494    ...NEW_OP
14495  };
14496}
14497function createProjectionDefOp(def) {
14498  return {
14499    kind: OpKind.ProjectionDef,
14500    def,
14501    ...NEW_OP
14502  };
14503}
14504function createProjectionOp(xref, selector, i18nPlaceholder, sourceSpan) {
14505  return {
14506    kind: OpKind.Projection,
14507    xref,
14508    handle: new SlotHandle(),
14509    selector,
14510    i18nPlaceholder,
14511    projectionSlotIndex: 0,
14512    attributes: null,
14513    localRefs: [],
14514    sourceSpan,
14515    ...NEW_OP,
14516    ...TRAIT_CONSUMES_SLOT
14517  };
14518}
14519/**
14520 * Create an `ExtractedAttributeOp`.
14521 */
14522function createExtractedAttributeOp(target, bindingKind, namespace, name, expression, i18nContext, i18nMessage, securityContext) {
14523  return {
14524    kind: OpKind.ExtractedAttribute,
14525    target,
14526    bindingKind,
14527    namespace,
14528    name,
14529    expression,
14530    i18nContext,
14531    i18nMessage,
14532    securityContext,
14533    trustedValueFn: null,
14534    ...NEW_OP
14535  };
14536}
14537function createDeferOp(xref, main, mainSlot, metadata, resolverFn, sourceSpan) {
14538  return {
14539    kind: OpKind.Defer,
14540    xref,
14541    handle: new SlotHandle(),
14542    mainView: main,
14543    mainSlot,
14544    loadingView: null,
14545    loadingSlot: null,
14546    loadingConfig: null,
14547    loadingMinimumTime: null,
14548    loadingAfterTime: null,
14549    placeholderView: null,
14550    placeholderSlot: null,
14551    placeholderConfig: null,
14552    placeholderMinimumTime: null,
14553    errorView: null,
14554    errorSlot: null,
14555    metadata,
14556    resolverFn,
14557    sourceSpan,
14558    ...NEW_OP,
14559    ...TRAIT_CONSUMES_SLOT,
14560    numSlotsUsed: 2
14561  };
14562}
14563function createDeferOnOp(defer, trigger, prefetch, sourceSpan) {
14564  return {
14565    kind: OpKind.DeferOn,
14566    defer,
14567    trigger,
14568    prefetch,
14569    sourceSpan,
14570    ...NEW_OP
14571  };
14572}
14573/**
14574 * Create an `ExtractedMessageOp`.
14575 */
14576function createI18nMessageOp(xref, i18nContext, i18nBlock, message, messagePlaceholder, params, postprocessingParams, needsPostprocessing) {
14577  return {
14578    kind: OpKind.I18nMessage,
14579    xref,
14580    i18nContext,
14581    i18nBlock,
14582    message,
14583    messagePlaceholder,
14584    params,
14585    postprocessingParams,
14586    needsPostprocessing,
14587    subMessages: [],
14588    ...NEW_OP
14589  };
14590}
14591/**
14592 * Create an `I18nStartOp`.
14593 */
14594function createI18nStartOp(xref, message, root, sourceSpan) {
14595  return {
14596    kind: OpKind.I18nStart,
14597    xref,
14598    handle: new SlotHandle(),
14599    root: root ?? xref,
14600    message,
14601    messageIndex: null,
14602    subTemplateIndex: null,
14603    context: null,
14604    sourceSpan,
14605    ...NEW_OP,
14606    ...TRAIT_CONSUMES_SLOT
14607  };
14608}
14609/**
14610 * Create an `I18nEndOp`.
14611 */
14612function createI18nEndOp(xref, sourceSpan) {
14613  return {
14614    kind: OpKind.I18nEnd,
14615    xref,
14616    sourceSpan,
14617    ...NEW_OP
14618  };
14619}
14620/**
14621 * Creates an ICU start op.
14622 */
14623function createIcuStartOp(xref, message, messagePlaceholder, sourceSpan) {
14624  return {
14625    kind: OpKind.IcuStart,
14626    xref,
14627    message,
14628    messagePlaceholder,
14629    context: null,
14630    sourceSpan,
14631    ...NEW_OP
14632  };
14633}
14634/**
14635 * Creates an ICU end op.
14636 */
14637function createIcuEndOp(xref) {
14638  return {
14639    kind: OpKind.IcuEnd,
14640    xref,
14641    ...NEW_OP
14642  };
14643}
14644/**
14645 * Creates an ICU placeholder op.
14646 */
14647function createIcuPlaceholderOp(xref, name, strings) {
14648  return {
14649    kind: OpKind.IcuPlaceholder,
14650    xref,
14651    name,
14652    strings,
14653    expressionPlaceholders: [],
14654    ...NEW_OP
14655  };
14656}
14657function createI18nContextOp(contextKind, xref, i18nBlock, message, sourceSpan) {
14658  if (i18nBlock === null && contextKind !== I18nContextKind.Attr) {
14659    throw new Error('AssertionError: i18nBlock must be provided for non-attribute contexts.');
14660  }
14661  return {
14662    kind: OpKind.I18nContext,
14663    contextKind,
14664    xref,
14665    i18nBlock,
14666    message,
14667    sourceSpan,
14668    params: new Map(),
14669    postprocessingParams: new Map(),
14670    ...NEW_OP
14671  };
14672}
14673function createI18nAttributesOp(xref, handle, target) {
14674  return {
14675    kind: OpKind.I18nAttributes,
14676    xref,
14677    handle,
14678    target,
14679    i18nAttributesConfig: null,
14680    ...NEW_OP,
14681    ...TRAIT_CONSUMES_SLOT
14682  };
14683}
14684function createHostPropertyOp(name, expression, isAnimationTrigger, i18nContext, securityContext, sourceSpan) {
14685  return {
14686    kind: OpKind.HostProperty,
14687    name,
14688    expression,
14689    isAnimationTrigger,
14690    i18nContext,
14691    securityContext,
14692    sanitizer: null,
14693    sourceSpan,
14694    ...TRAIT_CONSUMES_VARS,
14695    ...NEW_OP
14696  };
14697}
14698
14699/**
14700 * When referenced in the template's context parameters, this indicates a reference to the entire
14701 * context object, rather than a specific parameter.
14702 */
14703const CTX_REF = 'CTX_REF_MARKER';
14704var CompilationJobKind;
14705(function (CompilationJobKind) {
14706  CompilationJobKind[CompilationJobKind["Tmpl"] = 0] = "Tmpl";
14707  CompilationJobKind[CompilationJobKind["Host"] = 1] = "Host";
14708  CompilationJobKind[CompilationJobKind["Both"] = 2] = "Both";
14709})(CompilationJobKind || (CompilationJobKind = {}));
14710/**
14711 * An entire ongoing compilation, which will result in one or more template functions when complete.
14712 * Contains one or more corresponding compilation units.
14713 */
14714class CompilationJob {
14715  constructor(componentName, pool, compatibility) {
14716    this.componentName = componentName;
14717    this.pool = pool;
14718    this.compatibility = compatibility;
14719    this.kind = CompilationJobKind.Both;
14720    /**
14721     * Tracks the next `ir.XrefId` which can be assigned as template structures are ingested.
14722     */
14723    this.nextXrefId = 0;
14724  }
14725  /**
14726   * Generate a new unique `ir.XrefId` in this job.
14727   */
14728  allocateXrefId() {
14729    return this.nextXrefId++;
14730  }
14731}
14732/**
14733 * Compilation-in-progress of a whole component's template, including the main template and any
14734 * embedded views or host bindings.
14735 */
14736class ComponentCompilationJob extends CompilationJob {
14737  constructor(componentName, pool, compatibility, relativeContextFilePath, i18nUseExternalIds, deferBlocksMeta, allDeferrableDepsFn) {
14738    super(componentName, pool, compatibility);
14739    this.relativeContextFilePath = relativeContextFilePath;
14740    this.i18nUseExternalIds = i18nUseExternalIds;
14741    this.deferBlocksMeta = deferBlocksMeta;
14742    this.allDeferrableDepsFn = allDeferrableDepsFn;
14743    this.kind = CompilationJobKind.Tmpl;
14744    this.fnSuffix = 'Template';
14745    this.views = new Map();
14746    /**
14747     * Causes ngContentSelectors to be emitted, for content projection slots in the view. Possibly a
14748     * reference into the constant pool.
14749     */
14750    this.contentSelectors = null;
14751    /**
14752     * Constant expressions used by operations within this component's compilation.
14753     *
14754     * This will eventually become the `consts` array in the component definition.
14755     */
14756    this.consts = [];
14757    /**
14758     * Initialization statements needed to set up the consts.
14759     */
14760    this.constsInitializers = [];
14761    this.root = new ViewCompilationUnit(this, this.allocateXrefId(), null);
14762    this.views.set(this.root.xref, this.root);
14763  }
14764  /**
14765   * Add a `ViewCompilation` for a new embedded view to this compilation.
14766   */
14767  allocateView(parent) {
14768    const view = new ViewCompilationUnit(this, this.allocateXrefId(), parent);
14769    this.views.set(view.xref, view);
14770    return view;
14771  }
14772  get units() {
14773    return this.views.values();
14774  }
14775  /**
14776   * Add a constant `o.Expression` to the compilation and return its index in the `consts` array.
14777   */
14778  addConst(newConst, initializers) {
14779    for (let idx = 0; idx < this.consts.length; idx++) {
14780      if (this.consts[idx].isEquivalent(newConst)) {
14781        return idx;
14782      }
14783    }
14784    const idx = this.consts.length;
14785    this.consts.push(newConst);
14786    if (initializers) {
14787      this.constsInitializers.push(...initializers);
14788    }
14789    return idx;
14790  }
14791}
14792/**
14793 * A compilation unit is compiled into a template function. Some example units are views and host
14794 * bindings.
14795 */
14796class CompilationUnit {
14797  constructor(xref) {
14798    this.xref = xref;
14799    /**
14800     * List of creation operations for this view.
14801     *
14802     * Creation operations may internally contain other operations, including update operations.
14803     */
14804    this.create = new OpList();
14805    /**
14806     * List of update operations for this view.
14807     */
14808    this.update = new OpList();
14809    /**
14810     * Name of the function which will be generated for this unit.
14811     *
14812     * May be `null` if not yet determined.
14813     */
14814    this.fnName = null;
14815    /**
14816     * Number of variable slots used within this view, or `null` if variables have not yet been
14817     * counted.
14818     */
14819    this.vars = null;
14820  }
14821  /**
14822   * Iterate over all `ir.Op`s within this view.
14823   *
14824   * Some operations may have child operations, which this iterator will visit.
14825   */
14826  *ops() {
14827    for (const op of this.create) {
14828      yield op;
14829      if (op.kind === OpKind.Listener || op.kind === OpKind.TwoWayListener) {
14830        for (const listenerOp of op.handlerOps) {
14831          yield listenerOp;
14832        }
14833      }
14834    }
14835    for (const op of this.update) {
14836      yield op;
14837    }
14838  }
14839}
14840/**
14841 * Compilation-in-progress of an individual view within a template.
14842 */
14843class ViewCompilationUnit extends CompilationUnit {
14844  constructor(job, xref, parent) {
14845    super(xref);
14846    this.job = job;
14847    this.parent = parent;
14848    /**
14849     * Map of declared variables available within this view to the property on the context object
14850     * which they alias.
14851     */
14852    this.contextVariables = new Map();
14853    /**
14854     * Set of aliases available within this view. An alias is a variable whose provided expression is
14855     * inlined at every location it is used. It may also depend on context variables, by name.
14856     */
14857    this.aliases = new Set();
14858    /**
14859     * Number of declaration slots used within this view, or `null` if slots have not yet been
14860     * allocated.
14861     */
14862    this.decls = null;
14863  }
14864}
14865/**
14866 * Compilation-in-progress of a host binding, which contains a single unit for that host binding.
14867 */
14868class HostBindingCompilationJob extends CompilationJob {
14869  constructor(componentName, pool, compatibility) {
14870    super(componentName, pool, compatibility);
14871    this.kind = CompilationJobKind.Host;
14872    this.fnSuffix = 'HostBindings';
14873    this.root = new HostBindingCompilationUnit(this);
14874  }
14875  get units() {
14876    return [this.root];
14877  }
14878}
14879class HostBindingCompilationUnit extends CompilationUnit {
14880  constructor(job) {
14881    super(0);
14882    this.job = job;
14883    /**
14884     * Much like an element can have attributes, so can a host binding function.
14885     */
14886    this.attributes = null;
14887  }
14888}
14889
14890/**
14891 * Find any function calls to `$any`, excluding `this.$any`, and delete them, since they have no
14892 * runtime effects.
14893 */
14894function deleteAnyCasts(job) {
14895  for (const unit of job.units) {
14896    for (const op of unit.ops()) {
14897      transformExpressionsInOp(op, removeAnys, VisitorContextFlag.None);
14898    }
14899  }
14900}
14901function removeAnys(e) {
14902  if (e instanceof InvokeFunctionExpr && e.fn instanceof LexicalReadExpr && e.fn.name === '$any') {
14903    if (e.args.length !== 1) {
14904      throw new Error('The $any builtin function expects exactly one argument.');
14905    }
14906    return e.args[0];
14907  }
14908  return e;
14909}
14910
14911/**
14912 * Adds apply operations after i18n expressions.
14913 */
14914function applyI18nExpressions(job) {
14915  const i18nContexts = new Map();
14916  for (const unit of job.units) {
14917    for (const op of unit.create) {
14918      if (op.kind === OpKind.I18nContext) {
14919        i18nContexts.set(op.xref, op);
14920      }
14921    }
14922  }
14923  for (const unit of job.units) {
14924    for (const op of unit.update) {
14925      // Only add apply after expressions that are not followed by more expressions.
14926      if (op.kind === OpKind.I18nExpression && needsApplication(i18nContexts, op)) {
14927        // TODO: what should be the source span for the apply op?
14928        OpList.insertAfter(createI18nApplyOp(op.i18nOwner, op.handle, null), op);
14929      }
14930    }
14931  }
14932}
14933/**
14934 * Checks whether the given expression op needs to be followed with an apply op.
14935 */
14936function needsApplication(i18nContexts, op) {
14937  // If the next op is not another expression, we need to apply.
14938  if (op.next?.kind !== OpKind.I18nExpression) {
14939    return true;
14940  }
14941  const context = i18nContexts.get(op.context);
14942  const nextContext = i18nContexts.get(op.next.context);
14943  if (context === undefined) {
14944    throw new Error('AssertionError: expected an I18nContextOp to exist for the I18nExpressionOp\'s context');
14945  }
14946  if (nextContext === undefined) {
14947    throw new Error('AssertionError: expected an I18nContextOp to exist for the next I18nExpressionOp\'s context');
14948  }
14949  // If the next op is an expression targeting a different i18n block (or different element, in the
14950  // case of i18n attributes), we need to apply.
14951  // First, handle the case of i18n blocks.
14952  if (context.i18nBlock !== null) {
14953    // This is a block context. Compare the blocks.
14954    if (context.i18nBlock !== nextContext.i18nBlock) {
14955      return true;
14956    }
14957    return false;
14958  }
14959  // Second, handle the case of i18n attributes.
14960  if (op.i18nOwner !== op.next.i18nOwner) {
14961    return true;
14962  }
14963  return false;
14964}
14965
14966/**
14967 * Updates i18n expression ops to target the last slot in their owning i18n block, and moves them
14968 * after the last update instruction that depends on that slot.
14969 */
14970function assignI18nSlotDependencies(job) {
14971  for (const unit of job.units) {
14972    // The first update op.
14973    let updateOp = unit.update.head;
14974    // I18n expressions currently being moved during the iteration.
14975    let i18nExpressionsInProgress = [];
14976    // Non-null  while we are iterating through an i18nStart/i18nEnd pair
14977    let state = null;
14978    for (const createOp of unit.create) {
14979      if (createOp.kind === OpKind.I18nStart) {
14980        state = {
14981          blockXref: createOp.xref,
14982          lastSlotConsumer: createOp.xref
14983        };
14984      } else if (createOp.kind === OpKind.I18nEnd) {
14985        for (const op of i18nExpressionsInProgress) {
14986          op.target = state.lastSlotConsumer;
14987          OpList.insertBefore(op, updateOp);
14988        }
14989        i18nExpressionsInProgress.length = 0;
14990        state = null;
14991      }
14992      if (hasConsumesSlotTrait(createOp)) {
14993        if (state !== null) {
14994          state.lastSlotConsumer = createOp.xref;
14995        }
14996        while (true) {
14997          if (updateOp.next === null) {
14998            break;
14999          }
15000          if (state !== null && updateOp.kind === OpKind.I18nExpression && updateOp.usage === I18nExpressionFor.I18nText && updateOp.i18nOwner === state.blockXref) {
15001            const opToRemove = updateOp;
15002            updateOp = updateOp.next;
15003            OpList.remove(opToRemove);
15004            i18nExpressionsInProgress.push(opToRemove);
15005            continue;
15006          }
15007          if (hasDependsOnSlotContextTrait(updateOp) && updateOp.target !== createOp.xref) {
15008            break;
15009          }
15010          updateOp = updateOp.next;
15011        }
15012      }
15013    }
15014  }
15015}
15016
15017/**
15018 * Gets a map of all elements in the given view by their xref id.
15019 */
15020function createOpXrefMap(unit) {
15021  const map = new Map();
15022  for (const op of unit.create) {
15023    if (!hasConsumesSlotTrait(op)) {
15024      continue;
15025    }
15026    map.set(op.xref, op);
15027    // TODO(dylhunn): `@for` loops with `@empty` blocks need to be special-cased here,
15028    // because the slot consumer trait currently only supports one slot per consumer and we
15029    // need two. This should be revisited when making the refactors mentioned in:
15030    // https://github.com/angular/angular/pull/53620#discussion_r1430918822
15031    if (op.kind === OpKind.RepeaterCreate && op.emptyView !== null) {
15032      map.set(op.emptyView, op);
15033    }
15034  }
15035  return map;
15036}
15037
15038/**
15039 * Find all extractable attribute and binding ops, and create ExtractedAttributeOps for them.
15040 * In cases where no instruction needs to be generated for the attribute or binding, it is removed.
15041 */
15042function extractAttributes(job) {
15043  for (const unit of job.units) {
15044    const elements = createOpXrefMap(unit);
15045    for (const op of unit.ops()) {
15046      switch (op.kind) {
15047        case OpKind.Attribute:
15048          extractAttributeOp(unit, op, elements);
15049          break;
15050        case OpKind.Property:
15051          if (!op.isAnimationTrigger) {
15052            let bindingKind;
15053            if (op.i18nMessage !== null && op.templateKind === null) {
15054              // If the binding has an i18n context, it is an i18n attribute, and should have that
15055              // kind in the consts array.
15056              bindingKind = BindingKind.I18n;
15057            } else if (op.isStructuralTemplateAttribute) {
15058              bindingKind = BindingKind.Template;
15059            } else {
15060              bindingKind = BindingKind.Property;
15061            }
15062            OpList.insertBefore(
15063            // Deliberately null i18nMessage value
15064            createExtractedAttributeOp(op.target, bindingKind, null, op.name, /* expression */null, /* i18nContext */null, /* i18nMessage */null, op.securityContext), lookupElement$2(elements, op.target));
15065          }
15066          break;
15067        case OpKind.TwoWayProperty:
15068          OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.TwoWayProperty, null, op.name, /* expression */null, /* i18nContext */null, /* i18nMessage */null, op.securityContext), lookupElement$2(elements, op.target));
15069          break;
15070        case OpKind.StyleProp:
15071        case OpKind.ClassProp:
15072          // TODO: Can style or class bindings be i18n attributes?
15073          // The old compiler treated empty style bindings as regular bindings for the purpose of
15074          // directive matching. That behavior is incorrect, but we emulate it in compatibility
15075          // mode.
15076          if (unit.job.compatibility === CompatibilityMode.TemplateDefinitionBuilder && op.expression instanceof EmptyExpr) {
15077            OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.Property, null, op.name, /* expression */null, /* i18nContext */null, /* i18nMessage */null, SecurityContext.STYLE), lookupElement$2(elements, op.target));
15078          }
15079          break;
15080        case OpKind.Listener:
15081          if (!op.isAnimationListener) {
15082            const extractedAttributeOp = createExtractedAttributeOp(op.target, BindingKind.Property, null, op.name, /* expression */null, /* i18nContext */null, /* i18nMessage */null, SecurityContext.NONE);
15083            if (job.kind === CompilationJobKind.Host) {
15084              if (job.compatibility) {
15085                // TemplateDefinitionBuilder does not extract listener bindings to the const array
15086                // (which is honestly pretty inconsistent).
15087                break;
15088              }
15089              // This attribute will apply to the enclosing host binding compilation unit, so order
15090              // doesn't matter.
15091              unit.create.push(extractedAttributeOp);
15092            } else {
15093              OpList.insertBefore(extractedAttributeOp, lookupElement$2(elements, op.target));
15094            }
15095          }
15096          break;
15097        case OpKind.TwoWayListener:
15098          // Two-way listeners aren't supported in host bindings.
15099          if (job.kind !== CompilationJobKind.Host) {
15100            const extractedAttributeOp = createExtractedAttributeOp(op.target, BindingKind.Property, null, op.name, /* expression */null, /* i18nContext */null, /* i18nMessage */null, SecurityContext.NONE);
15101            OpList.insertBefore(extractedAttributeOp, lookupElement$2(elements, op.target));
15102          }
15103          break;
15104      }
15105    }
15106  }
15107}
15108/**
15109 * Looks up an element in the given map by xref ID.
15110 */
15111function lookupElement$2(elements, xref) {
15112  const el = elements.get(xref);
15113  if (el === undefined) {
15114    throw new Error('All attributes should have an element-like target.');
15115  }
15116  return el;
15117}
15118/**
15119 * Extracts an attribute binding.
15120 */
15121function extractAttributeOp(unit, op, elements) {
15122  if (op.expression instanceof Interpolation) {
15123    return;
15124  }
15125  let extractable = op.isTextAttribute || op.expression.isConstant();
15126  if (unit.job.compatibility === CompatibilityMode.TemplateDefinitionBuilder) {
15127    // TemplateDefinitionBuilder only extracts text attributes. It does not extract attriibute
15128    // bindings, even if they are constants.
15129    extractable &&= op.isTextAttribute;
15130  }
15131  if (extractable) {
15132    const extractedAttributeOp = createExtractedAttributeOp(op.target, op.isStructuralTemplateAttribute ? BindingKind.Template : BindingKind.Attribute, op.namespace, op.name, op.expression, op.i18nContext, op.i18nMessage, op.securityContext);
15133    if (unit.job.kind === CompilationJobKind.Host) {
15134      // This attribute will apply to the enclosing host binding compilation unit, so order doesn't
15135      // matter.
15136      unit.create.push(extractedAttributeOp);
15137    } else {
15138      const ownerOp = lookupElement$2(elements, op.target);
15139      OpList.insertBefore(extractedAttributeOp, ownerOp);
15140    }
15141    OpList.remove(op);
15142  }
15143}
15144
15145/**
15146 * Looks up an element in the given map by xref ID.
15147 */
15148function lookupElement$1(elements, xref) {
15149  const el = elements.get(xref);
15150  if (el === undefined) {
15151    throw new Error('All attributes should have an element-like target.');
15152  }
15153  return el;
15154}
15155function specializeBindings(job) {
15156  const elements = new Map();
15157  for (const unit of job.units) {
15158    for (const op of unit.create) {
15159      if (!isElementOrContainerOp(op)) {
15160        continue;
15161      }
15162      elements.set(op.xref, op);
15163    }
15164  }
15165  for (const unit of job.units) {
15166    for (const op of unit.ops()) {
15167      if (op.kind !== OpKind.Binding) {
15168        continue;
15169      }
15170      switch (op.bindingKind) {
15171        case BindingKind.Attribute:
15172          if (op.name === 'ngNonBindable') {
15173            OpList.remove(op);
15174            const target = lookupElement$1(elements, op.target);
15175            target.nonBindable = true;
15176          } else {
15177            const [namespace, name] = splitNsName(op.name);
15178            OpList.replace(op, createAttributeOp(op.target, namespace, name, op.expression, op.securityContext, op.isTextAttribute, op.isStructuralTemplateAttribute, op.templateKind, op.i18nMessage, op.sourceSpan));
15179          }
15180          break;
15181        case BindingKind.Property:
15182        case BindingKind.Animation:
15183          if (job.kind === CompilationJobKind.Host) {
15184            OpList.replace(op, createHostPropertyOp(op.name, op.expression, op.bindingKind === BindingKind.Animation, op.i18nContext, op.securityContext, op.sourceSpan));
15185          } else {
15186            OpList.replace(op, createPropertyOp(op.target, op.name, op.expression, op.bindingKind === BindingKind.Animation, op.securityContext, op.isStructuralTemplateAttribute, op.templateKind, op.i18nContext, op.i18nMessage, op.sourceSpan));
15187          }
15188          break;
15189        case BindingKind.TwoWayProperty:
15190          if (!(op.expression instanceof Expression)) {
15191            // We shouldn't be able to hit this code path since interpolations in two-way bindings
15192            // result in a parser error. We assert here so that downstream we can assume that
15193            // the value is always an expression.
15194            throw new Error(`Expected value of two-way property binding "${op.name}" to be an expression`);
15195          }
15196          OpList.replace(op, createTwoWayPropertyOp(op.target, op.name, op.expression, op.securityContext, op.isStructuralTemplateAttribute, op.templateKind, op.i18nContext, op.i18nMessage, op.sourceSpan));
15197          break;
15198        case BindingKind.I18n:
15199        case BindingKind.ClassName:
15200        case BindingKind.StyleProperty:
15201          throw new Error(`Unhandled binding of kind ${BindingKind[op.bindingKind]}`);
15202      }
15203    }
15204  }
15205}
15206const CHAINABLE = new Set([Identifiers.attribute, Identifiers.classProp, Identifiers.element, Identifiers.elementContainer, Identifiers.elementContainerEnd, Identifiers.elementContainerStart, Identifiers.elementEnd, Identifiers.elementStart, Identifiers.hostProperty, Identifiers.i18nExp, Identifiers.listener, Identifiers.listener, Identifiers.property, Identifiers.styleProp, Identifiers.stylePropInterpolate1, Identifiers.stylePropInterpolate2, Identifiers.stylePropInterpolate3, Identifiers.stylePropInterpolate4, Identifiers.stylePropInterpolate5, Identifiers.stylePropInterpolate6, Identifiers.stylePropInterpolate7, Identifiers.stylePropInterpolate8, Identifiers.stylePropInterpolateV, Identifiers.syntheticHostListener, Identifiers.syntheticHostProperty, Identifiers.templateCreate, Identifiers.twoWayProperty, Identifiers.twoWayListener]);
15207/**
15208 * Post-process a reified view compilation and convert sequential calls to chainable instructions
15209 * into chain calls.
15210 *
15211 * For example, two `elementStart` operations in sequence:
15212 *
15213 * ```typescript
15214 * elementStart(0, 'div');
15215 * elementStart(1, 'span');
15216 * ```
15217 *
15218 * Can be called as a chain instead:
15219 *
15220 * ```typescript
15221 * elementStart(0, 'div')(1, 'span');
15222 * ```
15223 */
15224function chain(job) {
15225  for (const unit of job.units) {
15226    chainOperationsInList(unit.create);
15227    chainOperationsInList(unit.update);
15228  }
15229}
15230function chainOperationsInList(opList) {
15231  let chain = null;
15232  for (const op of opList) {
15233    if (op.kind !== OpKind.Statement || !(op.statement instanceof ExpressionStatement)) {
15234      // This type of statement isn't chainable.
15235      chain = null;
15236      continue;
15237    }
15238    if (!(op.statement.expr instanceof InvokeFunctionExpr) || !(op.statement.expr.fn instanceof ExternalExpr)) {
15239      // This is a statement, but not an instruction-type call, so not chainable.
15240      chain = null;
15241      continue;
15242    }
15243    const instruction = op.statement.expr.fn.value;
15244    if (!CHAINABLE.has(instruction)) {
15245      // This instruction isn't chainable.
15246      chain = null;
15247      continue;
15248    }
15249    // This instruction can be chained. It can either be added on to the previous chain (if
15250    // compatible) or it can be the start of a new chain.
15251    if (chain !== null && chain.instruction === instruction) {
15252      // This instruction can be added onto the previous chain.
15253      const expression = chain.expression.callFn(op.statement.expr.args, op.statement.expr.sourceSpan, op.statement.expr.pure);
15254      chain.expression = expression;
15255      chain.op.statement = expression.toStmt();
15256      OpList.remove(op);
15257    } else {
15258      // Leave this instruction alone for now, but consider it the start of a new chain.
15259      chain = {
15260        op,
15261        instruction,
15262        expression: op.statement.expr
15263      };
15264    }
15265  }
15266}
15267
15268/**
15269 * Attribute interpolations of the form `[attr.foo]="{{foo}}""` should be "collapsed" into a plain
15270 * attribute instruction, instead of an `attributeInterpolate` instruction.
15271 *
15272 * (We cannot do this for singleton property interpolations, because `propertyInterpolate`
15273 * stringifies its expression.)
15274 *
15275 * The reification step is also capable of performing this transformation, but doing it early in the
15276 * pipeline allows other phases to accurately know what instruction will be emitted.
15277 */
15278function collapseSingletonInterpolations(job) {
15279  for (const unit of job.units) {
15280    for (const op of unit.update) {
15281      const eligibleOpKind = op.kind === OpKind.Attribute;
15282      if (eligibleOpKind && op.expression instanceof Interpolation && op.expression.strings.length === 2 && op.expression.strings.every(s => s === '')) {
15283        op.expression = op.expression.expressions[0];
15284      }
15285    }
15286  }
15287}
15288
15289/**
15290 * Collapse the various conditions of conditional ops (if, switch) into a single test expression.
15291 */
15292function generateConditionalExpressions(job) {
15293  for (const unit of job.units) {
15294    for (const op of unit.ops()) {
15295      if (op.kind !== OpKind.Conditional) {
15296        continue;
15297      }
15298      let test;
15299      // Any case with a `null` condition is `default`. If one exists, default to it instead.
15300      const defaultCase = op.conditions.findIndex(cond => cond.expr === null);
15301      if (defaultCase >= 0) {
15302        const slot = op.conditions.splice(defaultCase, 1)[0].targetSlot;
15303        test = new SlotLiteralExpr(slot);
15304      } else {
15305        // By default, a switch evaluates to `-1`, causing no template to be displayed.
15306        test = literal(-1);
15307      }
15308      // Switch expressions assign their main test to a temporary, to avoid re-executing it.
15309      let tmp = op.test == null ? null : new AssignTemporaryExpr(op.test, job.allocateXrefId());
15310      // For each remaining condition, test whether the temporary satifies the check. (If no temp is
15311      // present, just check each expression directly.)
15312      for (let i = op.conditions.length - 1; i >= 0; i--) {
15313        let conditionalCase = op.conditions[i];
15314        if (conditionalCase.expr === null) {
15315          continue;
15316        }
15317        if (tmp !== null) {
15318          const useTmp = i === 0 ? tmp : new ReadTemporaryExpr(tmp.xref);
15319          conditionalCase.expr = new BinaryOperatorExpr(BinaryOperator.Identical, useTmp, conditionalCase.expr);
15320        } else if (conditionalCase.alias !== null) {
15321          const caseExpressionTemporaryXref = job.allocateXrefId();
15322          conditionalCase.expr = new AssignTemporaryExpr(conditionalCase.expr, caseExpressionTemporaryXref);
15323          op.contextValue = new ReadTemporaryExpr(caseExpressionTemporaryXref);
15324        }
15325        test = new ConditionalExpr(conditionalCase.expr, new SlotLiteralExpr(conditionalCase.targetSlot), test);
15326      }
15327      // Save the resulting aggregate Joost-expression.
15328      op.processed = test;
15329      // Clear the original conditions array, since we no longer need it, and don't want it to
15330      // affect subsequent phases (e.g. pipe creation).
15331      op.conditions = [];
15332    }
15333  }
15334}
15335const BINARY_OPERATORS = new Map([['&&', BinaryOperator.And], ['>', BinaryOperator.Bigger], ['>=', BinaryOperator.BiggerEquals], ['|', BinaryOperator.BitwiseOr], ['&', BinaryOperator.BitwiseAnd], ['/', BinaryOperator.Divide], ['==', BinaryOperator.Equals], ['===', BinaryOperator.Identical], ['<', BinaryOperator.Lower], ['<=', BinaryOperator.LowerEquals], ['-', BinaryOperator.Minus], ['%', BinaryOperator.Modulo], ['*', BinaryOperator.Multiply], ['!=', BinaryOperator.NotEquals], ['!==', BinaryOperator.NotIdentical], ['??', BinaryOperator.NullishCoalesce], ['||', BinaryOperator.Or], ['+', BinaryOperator.Plus]]);
15336function namespaceForKey(namespacePrefixKey) {
15337  const NAMESPACES = new Map([['svg', Namespace.SVG], ['math', Namespace.Math]]);
15338  if (namespacePrefixKey === null) {
15339    return Namespace.HTML;
15340  }
15341  return NAMESPACES.get(namespacePrefixKey) ?? Namespace.HTML;
15342}
15343function keyForNamespace(namespace) {
15344  const NAMESPACES = new Map([['svg', Namespace.SVG], ['math', Namespace.Math]]);
15345  for (const [k, n] of NAMESPACES.entries()) {
15346    if (n === namespace) {
15347      return k;
15348    }
15349  }
15350  return null; // No namespace prefix for HTML
15351}
15352function prefixWithNamespace(strippedTag, namespace) {
15353  if (namespace === Namespace.HTML) {
15354    return strippedTag;
15355  }
15356  return `:${keyForNamespace(namespace)}:${strippedTag}`;
15357}
15358function literalOrArrayLiteral(value) {
15359  if (Array.isArray(value)) {
15360    return literalArr(value.map(literalOrArrayLiteral));
15361  }
15362  return literal(value);
15363}
15364
15365/**
15366 * Converts the semantic attributes of element-like operations (elements, templates) into constant
15367 * array expressions, and lifts them into the overall component `consts`.
15368 */
15369function collectElementConsts(job) {
15370  // Collect all extracted attributes.
15371  const allElementAttributes = new Map();
15372  for (const unit of job.units) {
15373    for (const op of unit.create) {
15374      if (op.kind === OpKind.ExtractedAttribute) {
15375        const attributes = allElementAttributes.get(op.target) || new ElementAttributes(job.compatibility);
15376        allElementAttributes.set(op.target, attributes);
15377        attributes.add(op.bindingKind, op.name, op.expression, op.namespace, op.trustedValueFn);
15378        OpList.remove(op);
15379      }
15380    }
15381  }
15382  // Serialize the extracted attributes into the const array.
15383  if (job instanceof ComponentCompilationJob) {
15384    for (const unit of job.units) {
15385      for (const op of unit.create) {
15386        // TODO: Simplify and combine these cases.
15387        if (op.kind == OpKind.Projection) {
15388          const attributes = allElementAttributes.get(op.xref);
15389          if (attributes !== undefined) {
15390            const attrArray = serializeAttributes(attributes);
15391            if (attrArray.entries.length > 0) {
15392              op.attributes = attrArray;
15393            }
15394          }
15395        } else if (isElementOrContainerOp(op)) {
15396          op.attributes = getConstIndex(job, allElementAttributes, op.xref);
15397          // TODO(dylhunn): `@for` loops with `@empty` blocks need to be special-cased here,
15398          // because the slot consumer trait currently only supports one slot per consumer and we
15399          // need two. This should be revisited when making the refactors mentioned in:
15400          // https://github.com/angular/angular/pull/53620#discussion_r1430918822
15401          if (op.kind === OpKind.RepeaterCreate && op.emptyView !== null) {
15402            op.emptyAttributes = getConstIndex(job, allElementAttributes, op.emptyView);
15403          }
15404        }
15405      }
15406    }
15407  } else if (job instanceof HostBindingCompilationJob) {
15408    // TODO: If the host binding case further diverges, we may want to split it into 
15408its own
15409    // phase.
15410    for (const [xref, attributes] of allElementAttributes.entries()) {
15411      if (xref !== job.root.xref) {
15412        throw new Error(`An attribute would be const collected into the host binding's template function, but is not associated with the root xref.`);
15413      }
15414      const attrArray = serializeAttributes(attributes);
15415      if (attrArray.entries.length > 0) {
15416        job.root.attributes = attrArray;
15417      }
15418    }
15419  }
15420}
15421function getConstIndex(job, allElementAttributes, xref) {
15422  const attributes = allElementAttributes.get(xref);
15423  if (attributes !== undefined) {
15424    const attrArray = serializeAttributes(attributes);
15425    if (attrArray.entries.length > 0) {
15426      return job.addConst(attrArray);
15427    }
15428  }
15429  return null;
15430}
15431/**
15432 * Shared instance of an empty array to avoid unnecessary array allocations.
15433 */
15434const FLYWEIGHT_ARRAY = Object.freeze([]);
15435/**
15436 * Container for all of the various kinds of attributes which are applied on an element.
15437 */
15438class ElementAttributes {
15439  get attributes() {
15440    return this.byKind.get(BindingKind.Attribute) ?? FLYWEIGHT_ARRAY;
15441  }
15442  get classes() {
15443    return this.byKind.get(BindingKind.ClassName) ?? FLYWEIGHT_ARRAY;
15444  }
15445  get styles() {
15446    return this.byKind.get(BindingKind.StyleProperty) ?? FLYWEIGHT_ARRAY;
15447  }
15448  get bindings() {
15449    return this.propertyBindings ?? FLYWEIGHT_ARRAY;
15450  }
15451  get template() {
15452    return this.byKind.get(BindingKind.Template) ?? FLYWEIGHT_ARRAY;
15453  }
15454  get i18n() {
15455    return this.byKind.get(BindingKind.I18n) ?? FLYWEIGHT_ARRAY;
15456  }
15457  constructor(compatibility) {
15458    this.compatibility = compatibility;
15459    this.known = new Map();
15460    this.byKind = new Map();
15461    this.propertyBindings = null;
15462    this.projectAs = null;
15463  }
15464  isKnown(kind, name) {
15465    const nameToValue = this.known.get(kind) ?? new Set();
15466    this.known.set(kind, nameToValue);
15467    if (nameToValue.has(name)) {
15468      return true;
15469    }
15470    nameToValue.add(name);
15471    return false;
15472  }
15473  add(kind, name, value, namespace, trustedValueFn) {
15474    // TemplateDefinitionBuilder puts duplicate attribute, class, and style values into the consts
15475    // array. This seems inefficient, we can probably keep just the first one or the last value
15476    // (whichever actually gets applied when multiple values are listed for the same attribute).
15477    const allowDuplicates = this.compatibility === CompatibilityMode.TemplateDefinitionBuilder && (kind === BindingKind.Attribute || kind === BindingKind.ClassName || kind === BindingKind.StyleProperty);
15478    if (!allowDuplicates && this.isKnown(kind, name)) {
15479      return;
15480    }
15481    // TODO: Can this be its own phase
15482    if (name === 'ngProjectAs') {
15483      if (value === null || !(value instanceof LiteralExpr) || value.value == null || typeof value.value?.toString() !== 'string') {
15484        throw Error('ngProjectAs must have a string literal value');
15485      }
15486      this.projectAs = value.value.toString();
15487      // TODO: TemplateDefinitionBuilder allows `ngProjectAs` to also be assigned as a literal
15488      // attribute. Is this sane?
15489    }
15490    const array = this.arrayFor(kind);
15491    array.push(...getAttributeNameLiterals$1(namespace, name));
15492    if (kind === BindingKind.Attribute || kind === BindingKind.StyleProperty) {
15493      if (value === null) {
15494        throw Error('Attribute, i18n attribute, & style element attributes must have a value');
15495      }
15496      if (trustedValueFn !== null) {
15497        if (!isStringLiteral(value)) {
15498          throw Error('AssertionError: extracted attribute value should be string literal');
15499        }
15500        array.push(taggedTemplate(trustedValueFn, new TemplateLiteral([new TemplateLiteralElement(value.value)], []), undefined, value.sourceSpan));
15501      } else {
15502        array.push(value);
15503      }
15504    }
15505  }
15506  arrayFor(kind) {
15507    if (kind === BindingKind.Property || kind === BindingKind.TwoWayProperty) {
15508      this.propertyBindings ??= [];
15509      return this.propertyBindings;
15510    } else {
15511      if (!this.byKind.has(kind)) {
15512        this.byKind.set(kind, []);
15513      }
15514      return this.byKind.get(kind);
15515    }
15516  }
15517}
15518/**
15519 * Gets an array of literal expressions representing the attribute's namespaced name.
15520 */
15521function getAttributeNameLiterals$1(namespace, name) {
15522  const nameLiteral = literal(name);
15523  if (namespace) {
15524    return [literal(0 /* core.AttributeMarker.NamespaceURI */), literal(namespace), nameLiteral];
15525  }
15526  return [nameLiteral];
15527}
15528/**
15529 * Serializes an ElementAttributes object into an array expression.
15530 */
15531function serializeAttributes({
15532  attributes,
15533  bindings,
15534  classes,
15535  i18n,
15536  projectAs,
15537  styles,
15538  template
15539}) {
15540  const attrArray = [...attributes];
15541  if (projectAs !== null) {
15542    // Parse the attribute value into a CssSelectorList. Note that we only take the
15543    // first selector, because we don't support multiple selectors in ngProjectAs.
15544    const parsedR3Selector = parseSelectorToR3Selector(projectAs)[0];
15545    attrArray.push(literal(5 /* core.AttributeMarker.ProjectAs */), literalOrArrayLiteral(parsedR3Selector));
15546  }
15547  if (classes.length > 0) {
15548    attrArray.push(literal(1 /* core.AttributeMarker.Classes */), ...classes);
15549  }
15550  if (styles.length > 0) {
15551    attrArray.push(literal(2 /* core.AttributeMarker.Styles */), ...styles);
15552  }
15553  if (bindings.length > 0) {
15554    attrArray.push(literal(3 /* core.AttributeMarker.Bindings */), ...bindings);
15555  }
15556  if (template.length > 0) {
15557    attrArray.push(literal(4 /* core.AttributeMarker.Template */), ...template);
15558  }
15559  if (i18n.length > 0) {
15560    attrArray.push(literal(6 /* core.AttributeMarker.I18n */), ...i18n);
15561  }
15562  return literalArr(attrArray);
15563}
15564
15565/**
15566 * Some binding instructions in the update block may actually correspond to i18n bindings. In that
15567 * case, they should be replaced with i18nExp instructions for the dynamic portions.
15568 */
15569function convertI18nBindings(job) {
15570  const i18nAttributesByElem = new Map();
15571  for (const unit of job.units) {
15572    for (const op of unit.create) {
15573      if (op.kind === OpKind.I18nAttributes) {
15574        i18nAttributesByElem.set(op.target, op);
15575      }
15576    }
15577    for (const op of unit.update) {
15578      switch (op.kind) {
15579        case OpKind.Property:
15580        case OpKind.Attribute:
15581          if (op.i18nContext === null) {
15582            continue;
15583          }
15584          if (!(op.expression instanceof Interpolation)) {
15585            continue;
15586          }
15587          const i18nAttributesForElem = i18nAttributesByElem.get(op.target);
15588          if (i18nAttributesForElem === undefined) {
15589            throw new Error('AssertionError: An i18n attribute binding instruction requires the owning element to have an I18nAttributes create instruction');
15590          }
15591          if (i18nAttributesForElem.target !== op.target) {
15592            throw new Error('AssertionError: Expected i18nAttributes target element to match binding target element');
15593          }
15594          const ops = [];
15595          for (let i = 0; i < op.expression.expressions.length; i++) {
15596            const expr = op.expression.expressions[i];
15597            if (op.expression.i18nPlaceholders.length !== op.expression.expressions.length) {
15598              throw new Error(`AssertionError: An i18n attribute binding instruction requires the same number of expressions and placeholders, but found ${op.expression.i18nPlaceholders.length} placeholders and ${op.expression.expressions.length} expressions`);
15599            }
15600            ops.push(createI18nExpressionOp(op.i18nContext, i18nAttributesForElem.target, i18nAttributesForElem.xref, i18nAttributesForElem.handle, expr, null, op.expression.i18nPlaceholders[i], I18nParamResolutionTime.Creation, I18nExpressionFor.I18nAttribute, op.name, op.sourceSpan));
15601          }
15602          OpList.replaceWithMany(op, ops);
15603          break;
15604      }
15605    }
15606  }
15607}
15608
15609/**
15610 * Create extracted deps functions for defer ops.
15611 */
15612function createDeferDepsFns(job) {
15613  for (const unit of job.units) {
15614    for (const op of unit.create) {
15615      if (op.kind === OpKind.Defer) {
15616        if (op.metadata.deps.length === 0) {
15617          continue;
15618        }
15619        if (op.resolverFn !== null) {
15620          continue;
15621        }
15622        const dependencies = [];
15623        for (const dep of op.metadata.deps) {
15624          if (dep.isDeferrable) {
15625            // Callback function, e.g. `m () => m.MyCmp;`.
15626            const innerFn = arrowFn(
15627            // Default imports are always accessed through the `default` property.
15628            [new FnParam('m', DYNAMIC_TYPE)], variable('m').prop(dep.isDefaultImport ? 'default' : dep.symbolName));
15629            // Dynamic import, e.g. `import('./a').then(...)`.
15630            const importExpr = new DynamicImportExpr(dep.importPath).prop('then').callFn([innerFn]);
15631            dependencies.push(importExpr);
15632          } else {
15633            // Non-deferrable symbol, just use a reference to the type.
15634            dependencies.push(dep.type);
15635          }
15636        }
15637        const depsFnExpr = arrowFn([], literalArr(dependencies));
15638        if (op.handle.slot === null) {
15639          throw new Error('AssertionError: slot must be assigned bfore extracting defer deps functions');
15640        }
15641        const fullPathName = unit.fnName?.replace(`_Template`, ``);
15642        op.resolverFn = job.pool.getSharedFunctionReference(depsFnExpr, `${fullPathName}_Defer_${op.handle.slot}_DepsFn`, /* Don't use unique names for TDB compatibility */false);
15643      }
15644    }
15645  }
15646}
15647
15648/**
15649 * Create one helper context op per i18n block (including generate descending blocks).
15650 *
15651 * Also, if an ICU exists inside an i18n block that also contains other localizable content (such as
15652 * string), create an additional helper context op for the ICU.
15653 *
15654 * These context ops are later used for generating i18n messages. (Although we generate at least one
15655 * context op per nested view, we will collect them up the tree later, to generate a top-level
15656 * message.)
15657 */
15658function createI18nContexts(job) {
15659  // Create i18n context ops for i18n attrs.
15660  const attrContextByMessage = new Map();
15661  for (const unit of job.units) {
15662    for (const op of unit.ops()) {
15663      switch (op.kind) {
15664        case OpKind.Binding:
15665        case OpKind.Property:
15666        case OpKind.Attribute:
15667        case OpKind.ExtractedAttribute:
15668          if (op.i18nMessage === null) {
15669            continue;
15670          }
15671          if (!attrContextByMessage.has(op.i18nMessage)) {
15672            const i18nContext = createI18nContextOp(I18nContextKind.Attr, job.allocateXrefId(), null, op.i18nMessage, null);
15673            unit.create.push(i18nContext);
15674            attrContextByMessage.set(op.i18nMessage, i18nContext.xref);
15675          }
15676          op.i18nContext = attrContextByMessage.get(op.i18nMessage);
15677          break;
15678      }
15679    }
15680  }
15681  // Create i18n context ops for root i18n blocks.
15682  const blockContextByI18nBlock = new Map();
15683  for (const unit of job.units) {
15684    for (const op of unit.create) {
15685      switch (op.kind) {
15686        case OpKind.I18nStart:
15687          if (op.xref === op.root) {
15688            const contextOp = createI18nContextOp(I18nContextKind.RootI18n, job.allocateXrefId(), op.xref, op.message, null);
15689            unit.create.push(contextOp);
15690            op.context = contextOp.xref;
15691            blockContextByI18nBlock.set(op.xref, contextOp);
15692          }
15693          break;
15694      }
15695    }
15696  }
15697  // Assign i18n contexts for child i18n blocks. These don't need their own conext, instead they
15698  // should inherit from their root i18n block.
15699  for (const unit of job.units) {
15700    for (const op of unit.create) {
15701      if (op.kind === OpKind.I18nStart && op.xref !== op.root) {
15702        const rootContext = blockContextByI18nBlock.get(op.root);
15703        if (rootContext === undefined) {
15704          throw Error('AssertionError: Root i18n block i18n context should have been created.');
15705        }
15706        op.context = rootContext.xref;
15707        blockContextByI18nBlock.set(op.xref, rootContext);
15708      }
15709    }
15710  }
15711  // Create or assign i18n contexts for ICUs.
15712  let currentI18nOp = null;
15713  for (const unit of job.units) {
15714    for (const op of unit.create) {
15715      switch (op.kind) {
15716        case OpKind.I18nStart:
15717          currentI18nOp = op;
15718          break;
15719        case OpKind.I18nEnd:
15720          currentI18nOp = null;
15721          break;
15722        case OpKind.IcuStart:
15723          if (currentI18nOp === null) {
15724            throw Error('AssertionError: Unexpected ICU outside of an i18n block.');
15725          }
15726          if (op.message.id !== currentI18nOp.message.id) {
15727            // This ICU is a sub-message inside its parent i18n block message. We need to give it
15728            // its own context.
15729            const contextOp = createI18nContextOp(I18nContextKind.Icu, job.allocateXrefId(), currentI18nOp.root, op.message, null);
15730            unit.create.push(contextOp);
15731            op.context = contextOp.xref;
15732          } else {
15733            // This ICU is the only translatable content in its parent i18n block. We need to
15734            // convert the parent's context into an ICU context.
15735            op.context = currentI18nOp.context;
15736            blockContextByI18nBlock.get(currentI18nOp.xref).contextKind = I18nContextKind.Icu;
15737          }
15738          break;
15739      }
15740    }
15741  }
15742}
15743
15744/**
15745 * Deduplicate text bindings, e.g. <div class="cls1" class="cls2">
15746 */
15747function deduplicateTextBindings(job) {
15748  const seen = new Map();
15749  for (const unit of job.units) {
15750    for (const op of unit.update.reversed()) {
15751      if (op.kind === OpKind.Binding && op.isTextAttribute) {
15752        const seenForElement = seen.get(op.target) || new Set();
15753        if (seenForElement.has(op.name)) {
15754          if (job.compatibility === CompatibilityMode.TemplateDefinitionBuilder) {
15755            // For most duplicated attributes, TemplateDefinitionBuilder lists all of the values in
15756            // the consts array. However, for style and class attributes it only keeps the last one.
15757            // We replicate that behavior here since it has actual consequences for apps with
15758            // duplicate class or style attrs.
15759            if (op.name === 'style' || op.name === 'class') {
15760              OpList.remove(op);
15761            }
15762          } else {
15763            // TODO: Determine the correct behavior. It would probably make sense to merge multiple
15764            // style and class attributes. Alternatively we could just throw an error, as HTML
15765            // doesn't permit duplicate attributes.
15766          }
15767        }
15768        seenForElement.add(op.name);
15769        seen.set(op.target, seenForElement);
15770      }
15771    }
15772  }
15773}
15774
15775/**
15776 * Defer instructions take a configuration array, which should be collected into the component
15777 * consts. This phase finds the config options, and creates the corresponding const array.
15778 */
15779function configureDeferInstructions(job) {
15780  for (const unit of job.units) {
15781    for (const op of unit.create) {
15782      if (op.kind !== OpKind.Defer) {
15783        continue;
15784      }
15785      if (op.placeholderMinimumTime !== null) {
15786        op.placeholderConfig = new ConstCollectedExpr(literalOrArrayLiteral([op.placeholderMinimumTime]));
15787      }
15788      if (op.loadingMinimumTime !== null || op.loadingAfterTime !== null) {
15789        op.loadingConfig = new ConstCollectedExpr(literalOrArrayLiteral([op.loadingMinimumTime, op.loadingAfterTime]));
15790      }
15791    }
15792  }
15793}
15794
15795/**
15796 * Some `defer` conditions can reference other elements in the template, using their local reference
15797 * names. However, the semantics are quite different from the normal local reference system: in
15798 * particular, we need to look at local reference names in enclosing views. This phase resolves
15799 * all such references to actual xrefs.
15800 */
15801function resolveDeferTargetNames(job) {
15802  const scopes = new Map();
15803  function getScopeForView(view) {
15804    if (scopes.has(view.xref)) {
15805      return scopes.get(view.xref);
15806    }
15807    const scope = new Scope$1();
15808    for (const op of view.create) {
15809      // add everything that can be referenced.
15810      if (!isElementOrContainerOp(op) || op.localRefs === null) {
15811        continue;
15812      }
15813      if (!Array.isArray(op.localRefs)) {
15814        throw new Error('LocalRefs were already processed, but were needed to resolve defer targets.');
15815      }
15816      for (const ref of op.localRefs) {
15817        if (ref.target !== '') {
15818          continue;
15819        }
15820        scope.targets.set(ref.name, {
15821          xref: op.xref,
15822          slot: op.handle
15823        });
15824      }
15825    }
15826    scopes.set(view.xref, scope);
15827    return scope;
15828  }
15829  function resolveTrigger(deferOwnerView, op, placeholderView) {
15830    switch (op.trigger.kind) {
15831      case DeferTriggerKind.Idle:
15832      case DeferTriggerKind.Immediate:
15833      case DeferTriggerKind.Timer:
15834        return;
15835      case DeferTriggerKind.Hover:
15836      case DeferTriggerKind.Interaction:
15837      case DeferTriggerKind.Viewport:
15838        if (op.trigger.targetName === null) {
15839          // A `null` target name indicates we should default to the first element in the
15840          // placeholder block.
15841          if (placeholderView === null) {
15842            throw new Error('defer on trigger with no target name must have a placeholder block');
15843          }
15844          const placeholder = job.views.get(placeholderView);
15845          if (placeholder == undefined) {
15846            throw new Error('AssertionError: could not find placeholder view for defer on trigger');
15847          }
15848          for (const placeholderOp of placeholder.create) {
15849            if (hasConsumesSlotTrait(placeholderOp) && (isElementOrContainerOp(placeholderOp) || placeholderOp.kind === OpKind.Projection)) {
15850              op.trigger.targetXref = placeholderOp.xref;
15851              op.trigger.targetView = placeholderView;
15852              op.trigger.targetSlotViewSteps = -1;
15853              op.trigger.targetSlot = placeholderOp.handle;
15854              return;
15855            }
15856          }
15857          return;
15858        }
15859        let view = placeholderView !== null ? job.views.get(placeholderView) : deferOwnerView;
15860        let step = placeholderView !== null ? -1 : 0;
15861        while (view !== null) {
15862          const scope = getScopeForView(view);
15863          if (scope.targets.has(op.trigger.targetName)) {
15864            const {
15865              xref,
15866              slot
15867            } = scope.targets.get(op.trigger.targetName);
15868            op.trigger.targetXref = xref;
15869            op.trigger.targetView = view.xref;
15870            op.trigger.targetSlotViewSteps = step;
15871            op.trigger.targetSlot = slot;
15872            return;
15873          }
15874          view = view.parent !== null ? job.views.get(view.parent) : null;
15875          step++;
15876        }
15877        break;
15878      default:
15879        throw new Error(`Trigger kind ${op.trigger.kind} not handled`);
15880    }
15881  }
15882  // Find the defer ops, and assign the data about their targets.
15883  for (const unit of job.units) {
15884    const defers = new Map();
15885    for (const op of unit.create) {
15886      switch (op.kind) {
15887        case OpKind.Defer:
15888          defers.set(op.xref, op);
15889          break;
15890        case OpKind.DeferOn:
15891          const deferOp = defers.get(op.defer);
15892          resolveTrigger(unit, op, deferOp.placeholderView);
15893          break;
15894      }
15895    }
15896  }
15897}
15898class Scope$1 {
15899  constructor() {
15900    this.targets = new Map();
15901  }
15902}
15903const REPLACEMENTS = new Map([[OpKind.ElementEnd, [OpKind.ElementStart, OpKind.Element]], [OpKind.ContainerEnd, [OpKind.ContainerStart, OpKind.Container]], [OpKind.I18nEnd, [OpKind.I18nStart, OpKind.I18n]]]);
15904/**
15905 * Op kinds that should not prevent merging of start/end ops.
15906 */
15907const IGNORED_OP_KINDS = new Set([OpKind.Pipe]);
15908/**
15909 * Replace sequences of mergable instructions (e.g. `ElementStart` and `ElementEnd`) with a
15910 * consolidated instruction (e.g. `Element`).
15911 */
15912function collapseEmptyInstructions(job) {
15913  for (const unit of job.units) {
15914    for (const op of unit.create) {
15915      // Find end ops that may be able to be merged.
15916      const opReplacements = REPLACEMENTS.get(op.kind);
15917      if (opReplacements === undefined) {
15918        continue;
15919      }
15920      const [startKind, mergedKind] = opReplacements;
15921      // Locate the previous (non-ignored) op.
15922      let prevOp = op.prev;
15923      while (prevOp !== null && IGNORED_OP_KINDS.has(prevOp.kind)) {
15924        prevOp = prevOp.prev;
15925      }
15926      // If the previous op is the corresponding start op, we can megre.
15927      if (prevOp !== null && prevOp.kind === startKind) {
15928        // Transmute the start instruction to the merged version. This is safe as they're designed
15929        // to be identical apart from the `kind`.
15930        prevOp.kind = mergedKind;
15931        // Remove the end instruction.
15932        OpList.remove(op);
15933      }
15934    }
15935  }
15936}
15937
15938/**
15939 * Safe read expressions such as `a?.b` have different semantics in Angular templates as
15940 * compared to JavaScript. In particular, they default to `null` instead of `undefined`. This phase
15941 * finds all unresolved safe read expressions, and converts them into the appropriate output AST
15942 * reads, guarded by null checks. We generate temporaries as needed, to avoid re-evaluating the same
15943 * sub-expression multiple times.
15944 */
15945function expandSafeReads(job) {
15946  for (const unit of job.units) {
15947    for (const op of unit.ops()) {
15948      transformExpressionsInOp(op, e => safeTransform(e, {
15949        job
15950      }), VisitorContextFlag.None);
15951      transformExpressionsInOp(op, ternaryTransform, VisitorContextFlag.None);
15952    }
15953  }
15954}
15955// A lookup set of all the expression kinds that require a temporary variable to be generated.
15956const requiresTemporary = [InvokeFunctionExpr, LiteralArrayExpr, LiteralMapExpr, SafeInvokeFunctionExpr, PipeBindingExpr].map(e => e.constructor.name);
15957function needsTemporaryInSafeAccess(e) {
15958  // TODO: We probably want to use an expression visitor to recursively visit all descendents.
15959  // However, that would potentially do a lot of extra work (because it cannot short circuit), so we
15960  // implement the logic ourselves for now.
15961  if (e instanceof UnaryOperatorExpr) {
15962    return needsTemporaryInSafeAccess(e.expr);
15963  } else if (e instanceof BinaryOperatorExpr) {
15964    return needsTemporaryInSafeAccess(e.lhs) || needsTemporaryInSafeAccess(e.rhs);
15965  } else if (e instanceof ConditionalExpr) {
15966    if (e.falseCase && needsTemporaryInSafeAccess(e.falseCase)) return true;
15967    return needsTemporaryInSafeAccess(e.condition) || needsTemporaryInSafeAccess(e.trueCase);
15968  } else if (e instanceof NotExpr) {
15969    return needsTemporaryInSafeAccess(e.condition);
15970  } else if (e instanceof AssignTemporaryExpr) {
15971    return needsTemporaryInSafeAccess(e.expr);
15972  } else if (e instanceof ReadPropExpr) {
15973    return needsTemporaryInSafeAccess(e.receiver);
15974  } else if (e instanceof ReadKeyExpr) {
15975    return needsTemporaryInSafeAccess(e.receiver) || needsTemporaryInSafeAccess(e.index);
15976  }
15977  // TODO: Switch to a method which is exhaustive of newly added expression subtypes.
15978  return e instanceof InvokeFunctionExpr || e instanceof LiteralArrayExpr || e instanceof LiteralMapExpr || e instanceof SafeInvokeFunctionExpr || e instanceof PipeBindingExpr;
15979}
15980function temporariesIn(e) {
15981  const temporaries = new Set();
15982  // TODO: Although it's not currently supported by the transform helper, we should be able to
15983  // short-circuit exploring the tree to do less work. In particular, we don't have to penetrate
15984  // into the subexpressions of temporary assignments.
15985  transformExpressionsInExpression(e, e => {
15986    if (e instanceof AssignTemporaryExpr) {
15987      temporaries.add(e.xref);
15988    }
15989    return e;
15990  }, VisitorContextFlag.None);
15991  return temporaries;
15992}
15993function eliminateTemporaryAssignments(e, tmps, ctx) {
15994  // TODO: We can be more efficient than the transform helper here. We don't need to visit any
15995  // descendents of temporary assignments.
15996  transformExpressionsInExpression(e, e => {
15997    if (e instanceof AssignTemporaryExpr && tmps.has(e.xref)) {
15998      const read = new ReadTemporaryExpr(e.xref);
15999      // `TemplateDefinitionBuilder` has the (accidental?) behavior of generating assignments of
16000      // temporary variables to themselves. This happens because some subexpression that the
16001      // temporary refers to, possibly through nested temporaries, has a function call. We copy that
16002      // behavior here.
16003      return ctx.job.compatibility === CompatibilityMode.TemplateDefinitionBuilder ? new AssignTemporaryExpr(read, read.xref) : read;
16004    }
16005    return e;
16006  }, VisitorContextFlag.None);
16007  return e;
16008}
16009/**
16010 * Creates a safe ternary guarded by the input expression, and with a body generated by the provided
16011 * callback on the input expression. Generates a temporary variable assignment if needed, and
16012 * deduplicates nested temporary assignments if needed.
16013 */
16014function safeTernaryWithTemporary(guard, body, ctx) {
16015  let result;
16016  if (needsTemporaryInSafeAccess(guard)) {
16017    const xref = ctx.job.allocateXrefId();
16018    result = [new AssignTemporaryExpr(guard, xref), new ReadTemporaryExpr(xref)];
16019  } else {
16020    result = [guard, guard.clone()];
16021    // Consider an expression like `a?.[b?.c()]?.d`. The `b?.c()` will be transformed first,
16022    // introducing a temporary assignment into the key. Then, as part of expanding the `?.d`. That
16023    // assignment will be duplicated into both the guard and expression sides. We de-duplicate it,
16024    // by transforming it from an assignment into a read on the expression side.
16025    eliminateTemporaryAssignments(result[1], temporariesIn(result[0]), ctx);
16026  }
16027  return new SafeTernaryExpr(result[0], body(result[1]));
16028}
16029function isSafeAccessExpression(e) {
16030  return e instanceof SafePropertyReadExpr || e instanceof SafeKeyedReadExpr || e instanceof SafeInvokeFunctionExpr;
16031}
16032function isUnsafeAccessExpression(e) {
16033  return e instanceof ReadPropExpr || e instanceof ReadKeyExpr || e instanceof InvokeFunctionExpr;
16034}
16035function isAccessExpression(e) {
16036  return isSafeAccessExpression(e) || isUnsafeAccessExpression(e);
16037}
16038function deepestSafeTernary(e) {
16039  if (isAccessExpression(e) && e.receiver instanceof SafeTernaryExpr) {
16040    let st = e.receiver;
16041    while (st.expr instanceof SafeTernaryExpr) {
16042      st = st.expr;
16043    }
16044    return st;
16045  }
16046  return null;
16047}
16048// TODO: When strict compatibility with TemplateDefinitionBuilder is not required, we can use `&&`
16049// instead to save some code size.
16050function safeTransform(e, ctx) {
16051  if (!isAccessExpression(e)) {
16052    return e;
16053  }
16054  const dst = deepestSafeTernary(e);
16055  if (dst) {
16056    if (e instanceof InvokeFunctionExpr) {
16057      dst.expr = dst.expr.callFn(e.args);
16058      return e.receiver;
16059    }
16060    if (e instanceof ReadPropExpr) {
16061      dst.expr = dst.expr.prop(e.name);
16062      return e.receiver;
16063    }
16064    if (e instanceof ReadKeyExpr) {
16065      dst.expr = dst.expr.key(e.index);
16066      return e.receiver;
16067    }
16068    if (e instanceof SafeInvokeFunctionExpr) {
16069      dst.expr = safeTernaryWithTemporary(dst.expr, r => r.callFn(e.args), ctx);
16070      return e.receiver;
16071    }
16072    if (e instanceof SafePropertyReadExpr) {
16073      dst.expr = safeTernaryWithTemporary(dst.expr, r => r.prop(e.name), ctx);
16074      return e.receiver;
16075    }
16076    if (e instanceof SafeKeyedReadExpr) {
16077      dst.expr = safeTernaryWithTemporary(dst.expr, r => r.key(e.index), ctx);
16078      return e.receiver;
16079    }
16080  } else {
16081    if (e instanceof SafeInvokeFunctionExpr) {
16082      return safeTernaryWithTemporary(e.receiver, r => r.callFn(e.args), ctx);
16083    }
16084    if (e instanceof SafePropertyReadExpr) {
16085      return safeTernaryWithTemporary(e.receiver, r => r.prop(e.name), ctx);
16086    }
16087    if (e instanceof SafeKeyedReadExpr) {
16088      return safeTernaryWithTemporary(e.receiver, r => r.key(e.index), ctx);
16089    }
16090  }
16091  return e;
16092}
16093function ternaryTransform(e) {
16094  if (!(e instanceof SafeTernaryExpr)) {
16095    return e;
16096  }
16097  return new ConditionalExpr(new BinaryOperatorExpr(BinaryOperator.Equals, e.guard, NULL_EXPR), NULL_EXPR, e.expr);
16098}
16099
16100/**
16101 * The escape sequence used indicate message param values.
16102 */
16103const ESCAPE$1 = '\uFFFD';
16104/**
16105 * Marker used to indicate an element tag.
16106 */
16107const ELEMENT_MARKER = '#';
16108/**
16109 * Marker used to indicate a template tag.
16110 */
16111const TEMPLATE_MARKER = '*';
16112/**
16113 * Marker used to indicate closing of an element or template tag.
16114 */
16115const TAG_CLOSE_MARKER = '/';
16116/**
16117 * Marker used to indicate the sub-template context.
16118 */
16119const CONTEXT_MARKER = ':';
16120/**
16121 * Marker used to indicate the start of a list of values.
16122 */
16123const LIST_START_MARKER = '[';
16124/**
16125 * Marker used to indicate the end of a list of values.
16126 */
16127const LIST_END_MARKER = ']';
16128/**
16129 * Delimiter used to separate multiple values in a list.
16130 */
16131const LIST_DELIMITER = '|';
16132/**
16133 * Formats the param maps on extracted message ops into a maps of `Expression` objects that can be
16134 * used in the final output.
16135 */
16136function extractI18nMessages(job) {
16137  // Create an i18n message for each context.
16138  // TODO: Merge the context op with the message op since they're 1:1 anyways.
16139  const i18nMessagesByContext = new Map();
16140  const i18nBlocks = new Map();
16141  const i18nContexts = new Map();
16142  for (const unit of job.units) {
16143    for (const op of unit.create) {
16144      switch (op.kind) {
16145        case OpKind.I18nContext:
16146          const i18nMessageOp = createI18nMessage(job, op);
16147          unit.create.push(i18nMessageOp);
16148          i18nMessagesByContext.set(op.xref, i18nMessageOp);
16149          i18nContexts.set(op.xref, op);
16150          break;
16151        case OpKind.I18nStart:
16152          i18nBlocks.set(op.xref, op);
16153          break;
16154      }
16155    }
16156  }
16157  // Associate sub-messages for ICUs with their root message. At this point we can also remove the
16158  // ICU start/end ops, as they are no longer needed.
16159  let currentIcu = null;
16160  for (const unit of job.units) {
16161    for (const op of unit.create) {
16162      switch (op.kind) {
16163        case OpKind.IcuStart:
16164          currentIcu = op;
16165          OpList.remove(op);
16166          // Skip any contexts not associated with an ICU.
16167          const icuContext = i18nContexts.get(op.context);
16168          if (icuContext.contextKind !== I18nContextKind.Icu) {
16169            continue;
16170          }
16171          // Skip ICUs that share a context with their i18n message. These represent root-level
16172          // ICUs, not sub-messages.
16173          const i18nBlock = i18nBlocks.get(icuContext.i18nBlock);
16174          if (i18nBlock.context === icuContext.xref) {
16175            continue;
16176          }
16177          // Find the root message and push this ICUs message as a sub-message.
16178          const rootI18nBlock = i18nBlocks.get(i18nBlock.root);
16179          const rootMessage = i18nMessagesByContext.get(rootI18nBlock.context);
16180          if (rootMessage === undefined) {
16181            throw Error('AssertionError: ICU sub-message should belong to a root message.');
16182          }
16183          const subMessage = i18nMessagesByContext.get(icuContext.xref);
16184          subMessage.messagePlaceholder = op.messagePlaceholder;
16185          rootMessage.subMessages.push(subMessage.xref);
16186          break;
16187        case OpKind.IcuEnd:
16188          currentIcu = null;
16189          OpList.remove(op);
16190          break;
16191        case OpKind.IcuPlaceholder:
16192          // Add ICU placeholders to the message, then remove the ICU placeholder ops.
16193          if (currentIcu === null || currentIcu.context == null) {
16194            throw Error('AssertionError: Unexpected ICU placeholder outside of i18n context');
16195          }
16196          const msg = i18nMessagesByContext.get(currentIcu.context);
16197          msg.postprocessingParams.set(op.name, literal(formatIcuPlaceholder(op)));
16198          OpList.remove(op);
16199          break;
16200      }
16201    }
16202  }
16203}
16204/**
16205 * Create an i18n message op from an i18n context op.
16206 */
16207function createI18nMessage(job, context, messagePlaceholder) {
16208  let formattedParams = formatParams(context.params);
16209  const formattedPostprocessingParams = formatParams(context.postprocessingParams);
16210  let needsPostprocessing = [...context.params.values()].some(v => v.length > 1);
16211  return createI18nMessageOp(job.allocateXrefId(), context.xref, context.i18nBlock, context.message, messagePlaceholder ?? null, formattedParams, formattedPostprocessingParams, needsPostprocessing);
16212}
16213/**
16214 * Formats an ICU placeholder into a single string with expression placeholders.
16215 */
16216function formatIcuPlaceholder(op) {
16217  if (op.strings.length !== op.expressionPlaceholders.length + 1) {
16218    throw Error(`AssertionError: Invalid ICU placeholder with ${op.strings.length} strings and ${op.expressionPlaceholders.length} expressions`);
16219  }
16220  const values = op.expressionPlaceholders.map(formatValue);
16221  return op.strings.flatMap((str, i) => [str, values[i] || '']).join('');
16222}
16223/**
16224 * Formats a map of `I18nParamValue[]` values into a map of `Expression` values.
16225 */
16226function formatParams(params) {
16227  const formattedParams = new Map();
16228  for (const [placeholder, placeholderValues] of params) {
16229    const serializedValues = formatParamValues(placeholderValues);
16230    if (serializedValues !== null) {
16231      formattedParams.set(placeholder, literal(serializedValues));
16232    }
16233  }
16234  return formattedParams;
16235}
16236/**
16237 * Formats an `I18nParamValue[]` into a string (or null for empty array).
16238 */
16239function formatParamValues(values) {
16240  if (values.length === 0) {
16241    return null;
16242  }
16243  const serializedValues = values.map(value => formatValue(value));
16244  return serializedValues.length === 1 ? serializedValues[0] : `${LIST_START_MARKER}${serializedValues.join(LIST_DELIMITER)}${LIST_END_MARKER}`;
16245}
16246/**
16247 * Formats a single `I18nParamValue` into a string
16248 */
16249function formatValue(value) {
16250  // Element tags with a structural directive use a special form that concatenates the element and
16251  // template values.
16252  if (value.flags & I18nParamValueFlags.ElementTag && value.flags & I18nParamValueFlags.TemplateTag) {
16253    if (typeof value.value !== 'object') {
16254      throw Error('AssertionError: Expected i18n param value to have an element and template slot');
16255    }
16256    const elementValue = formatValue({
16257      ...value,
16258      value: value.value.element,
16259      flags: value.flags & ~I18nParamValueFlags.TemplateTag
16260    });
16261    const templateValue = formatValue({
16262      ...value,
16263      value: value.value.template,
16264      flags: value.flags & ~I18nParamValueFlags.ElementTag
16265    });
16266    // TODO(mmalerba): This is likely a bug in TemplateDefinitionBuilder, we should not need to
16267    // record the template value twice. For now I'm re-implementing the behavior here to keep the
16268    // output consistent with TemplateDefinitionBuilder.
16269    if (value.flags & I18nParamValueFlags.OpenTag && value.flags & I18nParamValueFlags.CloseTag) {
16270      return `${templateValue}${elementValue}${templateValue}`;
16271    }
16272    // To match the TemplateDefinitionBuilder output, flip the order depending on whether the
16273    // values represent a closing or opening tag (or both).
16274    // TODO(mmalerba): Figure out if this makes a difference in terms of either functionality,
16275    // or the resulting message ID. If not, we can remove the special-casing in the future.
16276    return value.flags & I18nParamValueFlags.CloseTag ? `${elementValue}${templateValue}` : `${templateValue}${elementValue}`;
16277  }
16278  // Self-closing tags use a special form that concatenates the start and close tag values.
16279  if (value.flags & I18nParamValueFlags.OpenTag && value.flags & I18nParamValueFlags.CloseTag) {
16280    return `${formatValue({
16281      ...value,
16282      flags: value.flags & ~I18nParamValueFlags.CloseTag
16283    })}${formatValue({
16284      ...value,
16285      flags: value.flags & ~I18nParamValueFlags.OpenTag
16286    })}`;
16287  }
16288  // If there are no special flags, just return the raw value.
16289  if (value.flags === I18nParamValueFlags.None) {
16290    return `${value.value}`;
16291  }
16292  // Encode the remaining flags as part of the value.
16293  let tagMarker = '';
16294  let closeMarker = '';
16295  if (value.flags & I18nParamValueFlags.ElementTag) {
16296    tagMarker = ELEMENT_MARKER;
16297  } else if (value.flags & I18nParamValueFlags.TemplateTag) {
16298    tagMarker = TEMPLATE_MARKER;
16299  }
16300  if (tagMarker !== '') {
16301    closeMarker = value.flags & I18nParamValueFlags.CloseTag ? TAG_CLOSE_MARKER : '';
16302  }
16303  const context = value.subTemplateIndex === null ? '' : `${CONTEXT_MARKER}${value.subTemplateIndex}`;
16304  return `${ESCAPE$1}${closeMarker}${tagMarker}${value.value}${context}${ESCAPE$1}`;
16305}
16306
16307/**
16308 * Generate `ir.AdvanceOp`s in between `ir.UpdateOp`s that ensure the runtime's implicit slot
16309 * context will be advanced correctly.
16310 */
16311function generateAdvance(job) {
16312  for (const unit of job.units) {
16313    // First build a map of all of the declarations in the view that have assigned slots.
16314    const slotMap = new Map();
16315    for (const op of unit.create) {
16316      if (!hasConsumesSlotTrait(op)) {
16317        continue;
16318      } else if (op.handle.slot === null) {
16319        throw new Error(`AssertionError: expected slots to have been allocated before generating advance() calls`);
16320      }
16321      slotMap.set(op.xref, op.handle.slot);
16322    }
16323    // Next, step through the update operations and generate `ir.AdvanceOp`s as required to ensure
16324    // the runtime's implicit slot counter will be set to the correct slot before executing each
16325    // update operation which depends on it.
16326    //
16327    // To do that, we track what the runtime's slot counter will be through the update operations.
16328    let slotContext = 0;
16329    for (const op of unit.update) {
16330      if (!hasDependsOnSlotContextTrait(op)) {
16331        // `op` doesn't depend on the slot counter, so it can be skipped.
16332        continue;
16333      } else if (!slotMap.has(op.target)) {
16334        // We expect ops that _do_ depend on the slot counter to point at declarations that exist in
16335        // the `slotMap`.
16336        throw new Error(`AssertionError: reference to unknown slot for target ${op.target}`);
16337      }
16338      const slot = slotMap.get(op.target);
16339      // Does the slot counter need to be adjusted?
16340      if (slotContext !== slot) {
16341        // If so, generate an `ir.AdvanceOp` to advance the counter.
16342        const delta = slot - slotContext;
16343        if (delta < 0) {
16344          throw new Error(`AssertionError: slot counter should never need to move backwards`);
16345        }
16346        OpList.insertBefore(createAdvanceOp(delta, op.sourceSpan), op);
16347        slotContext = slot;
16348      }
16349    }
16350  }
16351}
16352
16353/**
16354 * Locate projection slots, populate the each component's `ngContentSelectors` literal field,
16355 * populate `project` arguments, and generate the required `projectionDef` instruction for the job's
16356 * root view.
16357 */
16358function generateProjectionDefs(job) {
16359  // TODO: Why does TemplateDefinitionBuilder force a shared constant?
16360  const share = job.compatibility === CompatibilityMode.TemplateDefinitionBuilder;
16361  // Collect all selectors from this component, and its nested views. Also, assign each projection a
16362  // unique ascending projection slot index.
16363  const selectors = [];
16364  let projectionSlotIndex = 0;
16365  for (const unit of job.units) {
16366    for (const op of unit.create) {
16367      if (op.kind === OpKind.Projection) {
16368        selectors.push(op.selector);
16369        op.projectionSlotIndex = projectionSlotIndex++;
16370      }
16371    }
16372  }
16373  if (selectors.length > 0) {
16374    // Create the projectionDef array. If we only found a single wildcard selector, then we use the
16375    // default behavior with no arguments instead.
16376    let defExpr = null;
16377    if (selectors.length > 1 || selectors[0] !== '*') {
16378      const def = selectors.map(s => s === '*' ? s : parseSelectorToR3Selector(s));
16379      defExpr = job.pool.getConstLiteral(literalOrArrayLiteral(def), share);
16380    }
16381    // Create the ngContentSelectors constant.
16382    job.contentSelectors = job.pool.getConstLiteral(literalOrArrayLiteral(selectors), share);
16383    // The projection def instruction goes at the beginning of the root view, before any
16384    // `projection` instructions.
16385    job.root.create.prepend([createProjectionDefOp(defExpr)]);
16386  }
16387}
16388
16389/**
16390 * Generate a preamble sequence for each view creation block and listener function which declares
16391 * any variables that be referenced in other operations in the block.
16392 *
16393 * Variables generated include:
16394 *   * a saved view context to be used to restore the current view in event listeners.
16395 *   * the context of the restored view within event listener handlers.
16396 *   * context variables from the current view as well as all parent views (including the root
16397 *     context if needed).
16398 *   * local references from elements within the current view and any lexical parents.
16399 *
16400 * Variables are generated here unconditionally, and may optimized away in future operations if it
16401 * turns out their values (and any side effects) are unused.
16402 */
16403function generateVariables(job) {
16404  recursivelyProcessView(job.root, /* there is no parent scope for the root view */null);
16405}
16406/**
16407 * Process the given `ViewCompilation` and generate preambles for it and any listeners that it
16408 * declares.
16409 *
16410 * @param `parentScope` a scope extracted from the parent view which captures any variables which
16411 *     should be inherited by this view. `null` if the current view is the root view.
16412 */
16413function recursivelyProcessView(view, parentScope) {
16414  // Extract a `Scope` from this view.
16415  const scope = getScopeForView(view, parentScope);
16416  for (const op of view.create) {
16417    switch (op.kind) {
16418      case OpKind.Template:
16419        // Descend into child embedded views.
16420        recursivelyProcessView(view.job.views.get(op.xref), scope);
16421        break;
16422      case OpKind.RepeaterCreate:
16423        // Descend into child embedded views.
16424        recursivelyProcessView(view.job.views.get(op.xref), scope);
16425        if (op.emptyView) {
16426          recursivelyProcessView(view.job.views.get(op.emptyView), scope);
16427        }
16428        break;
16429      case OpKind.Listener:
16430      case OpKind.TwoWayListener:
16431        // Prepend variables to listener handler functions.
16432        op.handlerOps.prepend(generateVariablesInScopeForView(view, scope));
16433        break;
16434    }
16435  }
16436  // Prepend the declarations for all available variables in scope to the `update` block.
16437  const preambleOps = generateVariablesInScopeForView(view, scope);
16438  view.update.prepend(preambleOps);
16439}
16440/**
16441 * Process a view and generate a `Scope` representing the variables available for reference within
16442 * that view.
16443 */
16444function getScopeForView(view, parent) {
16445  const scope = {
16446    view: view.xref,
16447    viewContextVariable: {
16448      kind: SemanticVariableKind.Context,
16449      name: null,
16450      view: view.xref
16451    },
16452    contextVariables: new Map(),
16453    aliases: view.aliases,
16454    references: [],
16455    parent
16456  };
16457  for (const identifier of view.contextVariables.keys()) {
16458    scope.contextVariables.set(identifier, {
16459      kind: SemanticVariableKind.Identifier,
16460      name: null,
16461      identifier
16462    });
16463  }
16464  for (const op of view.create) {
16465    switch (op.kind) {
16466      case OpKind.ElementStart:
16467      case OpKind.Template:
16468        if (!Array.isArray(op.localRefs)) {
16469          throw new Error(`AssertionError: expected localRefs to be an array`);
16470        }
16471        // Record available local references from this element.
16472        for (let offset = 0; offset < op.localRefs.length; offset++) {
16473          scope.references.push({
16474            name: op.localRefs[offset].name,
16475            targetId: op.xref,
16476            targetSlot: op.handle,
16477            offset,
16478            variable: {
16479              kind: SemanticVariableKind.Identifier,
16480              name: null,
16481              identifier: op.localRefs[offset].name
16482            }
16483          });
16484        }
16485        break;
16486    }
16487  }
16488  return scope;
16489}
16490/**
16491 * Generate declarations for all variables that are in scope for a given view.
16492 *
16493 * This is a recursive process, as views inherit variables available from their parent view, which
16494 * itself may have inherited variables, etc.
16495 */
16496function generateVariablesInScopeForView(view, scope) {
16497  const newOps = [];
16498  if (scope.view !== view.xref) {
16499    // Before generating variables for a parent view, we need to switch to the context of the parent
16500    // view with a `nextContext` expression. This context switching operation itself declares a
16501    // variable, because the context of the view may be referenced directly.
16502    newOps.push(createVariableOp(view.job.allocateXrefId(), scope.viewContextVariable, new NextContextExpr(), VariableFlags.None));
16503  }
16504  // Add variables for all context variables available in this scope's view.
16505  const scopeView = view.job.views.get(scope.view);
16506  for (const [name, value] of scopeView.contextVariables) {
16507    const context = new ContextExpr(scope.view);
16508    // We either read the context, or, if the variable is CTX_REF, use the context directly.
16509    const variable = value === CTX_REF ? context : new ReadPropExpr(context, value);
16510    // Add the variable declaration.
16511    newOps.push(createVariableOp(view.job.allocateXrefId(), scope.contextVariables.get(name), variable, VariableFlags.None));
16512  }
16513  for (const alias of scopeView.aliases) {
16514    newOps.push(createVariableOp(view.job.allocateXrefId(), alias, alias.expression.clone(), VariableFlags.AlwaysInline));
16515  }
16516  // Add variables for all local references declared for elements in this scope.
16517  for (const ref of scope.references) {
16518    newOps.push(createVariableOp(view.job.allocateXrefId(), ref.variable, new ReferenceExpr(ref.targetId, ref.targetSlot, ref.offset), VariableFlags.None));
16519  }
16520  if (scope.parent !== null) {
16521    // Recursively add variables from the parent scope.
16522    newOps.push(...generateVariablesInScopeForView(view, scope.parent));
16523  }
16524  return newOps;
16525}
16526
16527/**
16528 * `ir.ConstCollectedExpr` may be present in any IR expression. This means that expression needs to
16529 * be lifted into the component const array, and replaced with a reference to the const array at its
16530 *
16531 * usage site. This phase walks the IR and performs this transformation.
16532 */
16533function collectConstExpressions(job) {
16534  for (const unit of job.units) {
16535    for (const op of unit.ops()) {
16536      transformExpressionsInOp(op, expr => {
16537        if (!(expr instanceof ConstCollectedExpr)) {
16538          return expr;
16539        }
16540        return literal(job.addConst(expr.expr));
16541      }, VisitorContextFlag.None);
16542    }
16543  }
16544}
16545const STYLE_DOT = 'style.';
16546const CLASS_DOT = 'class.';
16547const STYLE_BANG = 'style!';
16548const CLASS_BANG = 'class!';
16549const BANG_IMPORTANT = '!important';
16550/**
16551 * Host bindings are compiled using a different parser entrypoint, and are parsed quite differently
16552 * as a result. Therefore, we need to do some extra parsing for host style properties, as compared
16553 * to non-host style properties.
16554 * TODO: Unify host bindings and non-host bindings in the parser.
16555 */
16556function parseHostStyleProperties(job) {
16557  for (const op of job.root.update) {
16558    if (!(op.kind === OpKind.Binding && op.bindingKind === BindingKind.Property)) {
16559      continue;
16560    }
16561    if (op.name.endsWith(BANG_IMPORTANT)) {
16562      // Delete any `!important` suffixes from the binding name.
16563      op.name = op.name.substring(0, op.name.length - BANG_IMPORTANT.length);
16564    }
16565    if (op.name.startsWith(STYLE_DOT)) {
16566      op.bindingKind = BindingKind.StyleProperty;
16567      op.name = op.name.substring(STYLE_DOT.length);
16568      if (!isCssCustomProperty$1(op.name)) {
16569        op.name = hyphenate$1(op.name);
16570      }
16571      const {
16572        property,
16573        suffix
16574      } = parseProperty$1(op.name);
16575      op.name = property;
16576      op.unit = suffix;
16577    } else if (op.name.startsWith(STYLE_BANG)) {
16578      op.bindingKind = BindingKind.StyleProperty;
16579      op.name = 'style';
16580    } else if (op.name.startsWith(CLASS_DOT)) {
16581      op.bindingKind = BindingKind.ClassName;
16582      op.name = parseProperty$1(op.name.substring(CLASS_DOT.length)).property;
16583    } else if (op.name.startsWith(CLASS_BANG)) {
16584      op.bindingKind = BindingKind.ClassName;
16585      op.name = parseProperty$1(op.name.substring(CLASS_BANG.length)).property;
16586    }
16587  }
16588}
16589/**
16590 * Checks whether property name is a custom CSS property.
16591 * See: https://www.w3.org/TR/css-variables-1
16592 */
16593function isCssCustomProperty$1(name) {
16594  return name.startsWith('--');
16595}
16596function hyphenate$1(value) {
16597  return value.replace(/[a-z][A-Z]/g, v => {
16598    return v.charAt(0) + '-' + v.charAt(1);
16599  }).toLowerCase();
16600}
16601function parseProperty$1(name) {
16602  const overrideIndex = name.indexOf('!important');
16603  if (overrideIndex !== -1) {
16604    name = overrideIndex > 0 ? name.substring(0, overrideIndex) : '';
16605  }
16606  let suffix = null;
16607  let property = name;
16608  const unitIndex = name.lastIndexOf('.');
16609  if (unitIndex > 0) {
16610    suffix = name.slice(unitIndex + 1);
16611    property = name.substring(0, unitIndex);
16612  }
16613  return {
16614    property,
16615    suffix
16616  };
16617}
16618function mapEntry(key, value) {
16619  return {
16620    key,
16621    value,
16622    quoted: false
16623  };
16624}
16625function mapLiteral(obj, quoted = false) {
16626  return literalMap(Object.keys(obj).map(key => ({
16627    key,
16628    quoted,
16629    value: obj[key]
16630  })));
16631}
16632class IcuSerializerVisitor {
16633  visitText(text) {
16634    return text.value;
16635  }
16636  visitContainer(container) {
16637    return container.children.map(child => child.visit(this)).join('');
16638  }
16639  visitIcu(icu) {
16640    const strCases = Object.keys(icu.cases).map(k => `${k} {${icu.cases[k].visit(this)}}`);
16641    const result = `{${icu.expressionPlaceholder}, ${icu.type}, ${strCases.join(' ')}}`;
16642    return result;
16643  }
16644  visitTagPlaceholder(ph) {
16645    return ph.isVoid ? this.formatPh(ph.startName) : `${this.formatPh(ph.startName)}${ph.children.map(child => child.visit(this)).join('')}${this.formatPh(ph.closeName)}`;
16646  }
16647  visitPlaceholder(ph) {
16648    return this.formatPh(ph.name);
16649  }
16650  visitBlockPlaceholder(ph) {
16651    return `${this.formatPh(ph.startName)}${ph.children.map(child => child.visit(this)).join('')}${this.formatPh(ph.closeName)}`;
16652  }
16653  visitIcuPlaceholder(ph, context) {
16654    return this.formatPh(ph.name);
16655  }
16656  formatPh(value) {
16657    return `{${formatI18nPlaceholderName(value, /* useCamelCase */false)}}`;
16658  }
16659}
16660const serializer = new IcuSerializerVisitor();
16661function serializeIcuNode(icu) {
16662  return icu.visit(serializer);
16663}
16664var TokenType;
16665(function (TokenType) {
16666  TokenType[TokenType["Character"] = 0] = "Character";
16667  TokenType[TokenType["Identifier"] = 1] = "Identifier";
16668  TokenType[TokenType["PrivateIdentifier"] = 2] = "PrivateIdentifier";
16669  TokenType[TokenType["Keyword"] = 3] = "Keyword";
16670  TokenType[TokenType["String"] = 4] = "String";
16671  TokenType[TokenType["Operator"] = 5] = "Operator";
16672  TokenType[TokenType["Number"] = 6] = "Number";
16673  TokenType[TokenType["Error"] = 7] = "Error";
16674})(TokenType || (TokenType = {}));
16675const KEYWORDS = ['var', 'let', 'as', 'null', 'undefined', 'true', 'false', 'if', 'else', 'this'];
16676class Lexer {
16677  tokenize(text) {
16678    const scanner = new _Scanner(text);
16679    const tokens = [];
16680    let token = scanner.scanToken();
16681    while (token != null) {
16682      tokens.push(token);
16683      token = scanner.scanToken();
16684    }
16685    return tokens;
16686  }
16687}
16688class Token {
16689  constructor(index, end, type, numValue, strValue) {
16690    this.index = index;
16691    this.end = end;
16692    this.type = type;
16693    this.numValue = numValue;
16694    this.strValue = strValue;
16695  }
16696  isCharacter(code) {
16697    return this.type == TokenType.Character && this.numValue == code;
16698  }
16699  isNumber() {
16700    return this.type == TokenType.Number;
16701  }
16702  isString() {
16703    return this.type == TokenType.String;
16704  }
16705  isOperator(operator) {
16706    return this.type == TokenType.Operator && this.strValue == operator;
16707  }
16708  isIdentifier() {
16709    return this.type == TokenType.Identifier;
16710  }
16711  isPrivateIdentifier() {
16712    return this.type == TokenType.PrivateIdentifier;
16713  }
16714  isKeyword() {
16715    return this.type == TokenType.Keyword;
16716  }
16717  isKeywordLet() {
16718    return this.type == TokenType.Keyword && this.strValue == 'let';
16719  }
16720  isKeywordAs() {
16721    return this.type == TokenType.Keyword && this.strValue == 'as';
16722  }
16723  isKeywordNull() {
16724    return this.type == TokenType.Keyword && this.strValue == 'null';
16725  }
16726  isKeywordUndefined() {
16727    return this.type == TokenType.Keyword && this.strValue == 'undefined';
16728  }
16729  isKeywordTrue() {
16730    return this.type == TokenType.Keyword && this.strValue == 'true';
16731  }
16732  isKeywordFalse() {
16733    return this.type == TokenType.Keyword && this.strValue == 'false';
16734  }
16735  isKeywordThis() {
16736    return this.type == TokenType.Keyword && this.strValue == 'this';
16737  }
16738  isError() {
16739    return this.type == TokenType.Error;
16740  }
16741  toNumber() {
16742    return this.type == TokenType.Number ? this.numValue : -1;
16743  }
16744  toString() {
16745    switch (this.type) {
16746      case TokenType.Character:
16747      case TokenType.Identifier:
16748      case TokenType.Keyword:
16749      case TokenType.Operator:
16750      case TokenType.PrivateIdentifier:
16751      case TokenType.String:
16752      case TokenType.Error:
16753        return this.strValue;
16754      case TokenType.Number:
16755        return this.numValue.toString();
16756      default:
16757        return null;
16758    }
16759  }
16760}
16761function newCharacterToken(index, end, code) {
16762  return new Token(index, end, TokenType.Character, code, String.fromCharCode(code));
16763}
16764function newIdentifierToken(index, end, text) {
16765  return new Token(index, end, TokenType.Identifier, 0, text);
16766}
16767function newPrivateIdentifierToken(index, end, text) {
16768  return new Token(index, end, TokenType.PrivateIdentifier, 0, text);
16769}
16770function newKeywordToken(index, end, text) {
16771  return new Token(index, end, TokenType.Keyword, 0, text);
16772}
16773function newOperatorToken(index, end, text) {
16774  return new Token(index, end, TokenType.Operator, 0, text);
16775}
16776function newStringToken(index, end, text) {
16777  return new Token(index, end, TokenType.String, 0, text);
16778}
16779function newNumberToken(index, end, n) {
16780  return new Token(index, end, TokenType.Number, n, '');
16781}
16782function newErrorToken(index, end, message) {
16783  return new Token(index, end, TokenType.Error, 0, message);
16784}
16785const EOF = new Token(-1, -1, TokenType.Character, 0, '');
16786class _Scanner {
16787  constructor(input) {
16788    this.input = input;
16789    this.peek = 0;
16790    this.index = -1;
16791    this.length = input.length;
16792    this.advance();
16793  }
16794  advance() {
16795    this.peek = ++this.index >= this.length ? $EOF : this.input.charCodeAt(this.index);
16796  }
16797  scanToken() {
16798    const input = this.input,
16799      length = this.length;
16800    let peek = this.peek,
16801      index = this.index;
16802    // Skip whitespace.
16803    while (peek <= $SPACE) {
16804      if (++index >= length) {
16805        peek = $EOF;
16806        break;
16807      } else {
16808        peek = input.charCodeAt(index);
16809      }
16810    }
16811    this.peek = peek;
16812    this.index = index;
16813    if (index >= length) {
16814      return null;
16815    }
16816    // Handle identifiers and numbers.
16817    if (isIdentifierStart(peek)) return this.scanIdentifier();
16818    if (isDigit(peek)) return this.scanNumber(index);
16819    const start = index;
16820    switch (peek) {
16821      case $PERIOD:
16822        this.advance();
16823        return isDigit(this.peek) ? this.scanNumber(start) : newCharacterToken(start, this.index, $PERIOD);
16824      case $LPAREN:
16825      case $RPAREN:
16826      case $LBRACE:
16827      case $RBRACE:
16828      case $LBRACKET:
16829      case $RBRACKET:
16830      case $COMMA:
16831      case $COLON:
16832      case $SEMICOLON:
16833        return this.scanCharacter(start, peek);
16834      case $SQ:
16835      case $DQ:
16836        return this.scanString();
16837      case $HASH:
16838        return this.scanPrivateIdentifier();
16839      case $PLUS:
16840      case $MINUS:
16841      case $STAR:
16842      case $SLASH:
16843      case $PERCENT:
16844      case $CARET:
16845        return this.scanOperator(start, String.fromCharCode(peek));
16846      case $QUESTION:
16847        return this.scanQuestion(start);
16848      case $LT:
16849      case $GT:
16850        return this.scanComplexOperator(start, String.fromCharCode(peek), $EQ, '=');
16851      case $BANG:
16852      case $EQ:
16853        return this.scanComplexOperator(start, String.fromCharCode(peek), $EQ, '=', $EQ, '=');
16854      case $AMPERSAND:
16855        return this.scanComplexOperator(start, '&', $AMPERSAND, '&');
16856      case $BAR:
16857        return this.scanComplexOperator(start, '|', $BAR, '|');
16858      case $NBSP:
16859        while (isWhitespace(this.peek)) this.advance();
16860        return this.scanToken();
16861    }
16862    this.advance();
16863    return this.error(`Unexpected character [${String.fromCharCode(peek)}]`, 0);
16864  }
16865  scanCharacter(start, code) {
16866    this.advance();
16867    return newCharacterToken(start, this.index, code);
16868  }
16869  scanOperator(start, str) {
16870    this.advance();
16871    return newOperatorToken(start, this.index, str);
16872  }
16873  /**
16874   * Tokenize a 2/3 char long operator
16875   *
16876   * @param start start index in the expression
16877   * @param one first symbol (always part of the operator)
16878   * @param twoCode code point for the second symbol
16879   * @param two second symbol (part of the operator when the second code point matches)
16880   * @param threeCode code point for the third symbol
16881   * @param three third symbol (part of the operator when provided and matches source expression)
16882   */
16883  scanComplexOperator(start, one, twoCode, two, threeCode, three) {
16884    this.advance();
16885    let str = one;
16886    if (this.peek == twoCode) {
16887      this.advance();
16888      str += two;
16889    }
16890    if (threeCode != null && this.peek == threeCode) {
16891      this.advance();
16892      str += three;
16893    }
16894    return newOperatorToken(start, this.index, str);
16895  }
16896  scanIdentifier() {
16897    const start = this.index;
16898    this.advance();
16899    while (isIdentifierPart(this.peek)) this.advance();
16900    const str = this.input.substring(start, this.index);
16901    return KEYWORDS.indexOf(str) > -1 ? newKeywordToken(start, this.index, str) : newIdentifierToken(start, this.index, str);
16902  }
16903  /** Scans an ECMAScript private identifier. */
16904  scanPrivateIdentifier() {
16905    const start = this.index;
16906    this.advance();
16907    if (!isIdentifierStart(this.peek)) {
16908      return this.error('Invalid character [#]', -1);
16909    }
16910    while (isIdentifierPart(this.peek)) this.advance();
16911    const identifierName = this.input.substring(start, this.index);
16912    return newPrivateIdentifierToken(start, this.index, identifierName);
16913  }
16914  scanNumber(start) {
16915    let simple = this.index === start;
16916    let hasSeparators = false;
16917    this.advance(); // Skip initial digit.
16918    while (true) {
16919      if (isDigit(this.peek)) {
16920        // Do nothing.
16921      } else if (this.peek === $_) {
16922        // Separators are only valid when they're surrounded by digits. E.g. `1_0_1` is
16923        // valid while `_101` and `101_` are not. The separator can't be next to the decimal
16924        // point or another separator either. Note that it's unlikely that we'll hit a case where
16925        // the underscore is at the start, because that's a valid identifier and it will be picked
16926        // up earlier in the parsing. We validate for it anyway just in case.
16927        if (!isDigit(this.input.charCodeAt(this.index - 1)) || !isDigit(this.input.charCodeAt(this.index + 1))) {
16928          return this.error('Invalid numeric separator', 0);
16929        }
16930        hasSeparators = true;
16931      } else if (this.peek === $PERIOD) {
16932        simple = false;
16933      } else if (isExponentStart(this.peek)) {
16934        this.advance();
16935        if (isExponentSign(this.peek)) this.advance();
16936        if (!isDigit(this.peek)) return this.error('Invalid exponent', -1);
16937        simple = false;
16938      } else {
16939        break;
16940      }
16941      this.advance();
16942    }
16943    let str = this.input.substring(start, this.index);
16944    if (hasSeparators) {
16945      str = str.replace(/_/g, '');
16946    }
16947    const value = simple ? parseIntAutoRadix(str) : parseFloat(str);
16948    return newNumberToken(start, this.index, value);
16949  }
16950  scanString() {
16951    const start = this.index;
16952    const quote = this.peek;
16953    this.advance(); // Skip initial quote.
16954    let buffer = '';
16955    let marker = this.index;
16956    const input = this.input;
16957    while (this.peek != quote) {
16958      if (this.peek == $BACKSLASH) {
16959        buffer += input.substring(marker, this.index);
16960        let unescapedCode;
16961        this.advance(); // mutates this.peek
16962        // @ts-expect-error see microsoft/TypeScript#9998
16963        if (this.peek == $u) {
16964          // 4 character hex code for unicode character.
16965          const hex = input.substring(this.index + 1, this.index + 5);
16966          if (/^[0-9a-f]+$/i.test(hex)) {
16967            unescapedCode = parseInt(hex, 16);
16968          } else {
16969            return this.error(`Invalid unicode escape [\\u${hex}]`, 0);
16970          }
16971          for (let i = 0; i < 5; i++) {
16972            this.advance();
16973          }
16974        } else {
16975          unescapedCode = unescape(this.peek);
16976          this.advance();
16977        }
16978        buffer += String.fromCharCode(unescapedCode);
16979        marker = this.index;
16980      } else if (this.peek == $EOF) {
16981        return this.error('Unterminated quote', 0);
16982      } else {
16983        this.advance();
16984      }
16985    }
16986    const last = input.substring(marker, this.index);
16987    this.advance(); // Skip terminating quote.
16988    return newStringToken(start, this.index, buffer + last);
16989  }
16990  scanQuestion(start) {
16991    this.advance();
16992    let str = '?';
16993    // Either `a ?? b` or 'a?.b'.
16994    if (this.peek === $QUESTION || this.peek === $PERIOD) {
16995      str += this.peek === $PERIOD ? '.' : '?';
16996      this.advance();
16997    }
16998    return newOperatorToken(start, this.index, str);
16999  }
17000  error(message, offset) {
17001    const position = this.index + offset;
17002    return newErrorToken(position, this.index, `Lexer Error: ${message} at column ${position} in expression [${this.input}]`);
17003  }
17004}
17005function isIdentifierStart(code) {
17006  return $a <= code && code <= $z || $A <= code && code <= $Z || code == $_ || code == $$;
17007}
17008function isIdentifier(input) {
17009  if (input.length == 0) return false;
17010  const scanner = new _Scanner(input);
17011  if (!isIdentifierStart(scanner.peek)) return false;
17012  scanner.advance();
17013  while (scanner.peek !== $EOF) {
17014    if (!isIdentifierPart(scanner.peek)) return false;
17015    scanner.advance();
17016  }
17017  return true;
17018}
17019function isIdentifierPart(code) {
17020  return isAsciiLetter(code) || isDigit(code) || code == $_ || code == $$;
17021}
17022function isExponentStart(code) {
17023  return code == $e || code == $E;
17024}
17025function isExponentSign(code) {
17026  return code == $MINUS || code == $PLUS;
17027}
17028function unescape(code) {
17029  switch (code) {
17030    case $n:
17031      return $LF;
17032    case $f:
17033      return $FF;
17034    case $r:
17035      return $CR;
17036    case $t:
17037      return $TAB;
17038    case $v:
17039      return $VTAB;
17040    default:
17041      return code;
17042  }
17043}
17044function parseIntAutoRadix(text) {
17045  const result = parseInt(text);
17046  if (isNaN(result)) {
17047    throw new Error('Invalid integer literal when parsing ' + text);
17048  }
17049  return result;
17050}
17051class SplitInterpolation {
17052  constructor(strings, expressions, offsets) {
17053    this.strings = strings;
17054    this.expressions = expressions;
17055    this.offsets = offsets;
17056  }
17057}
17058class TemplateBindingParseResult {
17059  constructor(templateBindings, warnings, errors) {
17060    this.templateBindings = templateBindings;
17061    this.warnings = warnings;
17062    this.errors = errors;
17063  }
17064}
17065class Parser$1 {
17066  constructor(_lexer) {
17067    this._lexer = _lexer;
17068    this.errors = [];
17069  }
17070  parseAction(input, location, absoluteOffset, interpolationConfig = DEFAULT_INTERPOLATION_CONFIG) {
17071    this._checkNoInterpolation(input, location, interpolationConfig);
17072    const sourceToLex = this._stripComments(input);
17073    const tokens = this._lexer.tokenize(sourceToLex);
17074    const ast = new _ParseAST(input, location, absoluteOffset, tokens, 1 /* ParseFlags.Action */, this.errors, 0).parseChain();
17075    return new ASTWithSource(ast, input, location, absoluteOffset, this.errors);
17076  }
17077  parseBinding(input, location, absoluteOffset, interpolationConfig = DEFAULT_INTERPOLATION_CONFIG) {
17078    const ast = this._parseBindingAst(input, location, absoluteOffset, interpolationConfig);
17079    return new ASTWithSource(ast, input, location, absoluteOffset, this.errors);
17080  }
17081  checkSimpleExpression(ast) {
17082    const checker = new SimpleExpressionChecker();
17083    ast.visit(checker);
17084    return checker.errors;
17085  }
17086  // Host bindings parsed here
17087  parseSimpleBinding(input, location, absoluteOffset, interpolationConfig = DEFAULT_INTERPOLATION_CONFIG) {
17088    const ast = this._parseBindingAst(input, location, absoluteOffset, interpolationConfig);
17089    const errors = this.checkSimpleExpression(ast);
17090    if (errors.length > 0) {
17091      this._reportError(`Host binding expression cannot contain ${errors.join(' ')}`, input, location);
17092    }
17093    return new ASTWithSource(ast, input, location, absoluteOffset, this.errors);
17094  }
17095  _reportError(message, input, errLocation, ctxLocation) {
17096    this.errors.push(new ParserError(message, input, errLocation, ctxLocation));
17097  }
17098  _parseBindingAst(input, location, absoluteOffset, interpolationConfig) {
17099    this._checkNoInterpolation(input, location, interpolationConfig);
17100    const sourceToLex = this._stripComments(input);
17101    const tokens = this._lexer.tokenize(sourceToLex);
17102    return new _ParseAST(input, location, absoluteOffset, tokens, 0 /* ParseFlags.None */, this.errors, 0).parseChain();
17103  }
17104  /**
17105   * Parse microsyntax template expression and return a list of bindings or
17106   * parsing errors in case the given expression is invalid.
17107   *
17108   * For example,
17109   * ```
17110   *   <div *ngFor="let item of items">
17111   *         ^      ^ absoluteValueOffset for `templateValue`
17112   *         absoluteKeyOffset for `templateKey`
17113   * ```
17114   * contains three bindings:
17115   * 1. ngFor -> null
17116   * 2. item -> NgForOfContext.$implicit
17117   * 3. ngForOf -> items
17118   *
17119   * This is apparent from the de-sugared template:
17120   * ```
17121   *   <ng-template ngFor let-item [ngForOf]="items">
17122   * ```
17123   *
17124   * @param templateKey name of directive, without the * prefix. For example: ngIf, ngFor
17125   * @param templateValue RHS of the microsyntax attribute
17126   * @param templateUrl template filename if it's external, component filename if it's inline
17127   * @param absoluteKeyOffset start of the `templateKey`
17128   * @param absoluteValueOffset start of the `templateValue`
17129   */
17130  parseTemplateBindings(templateKey, templateValue, templateUrl, absoluteKeyOffset, absoluteValueOffset) {
17131    const tokens = this._lexer.tokenize(templateValue);
17132    const parser = new _ParseAST(templateValue, templateUrl, absoluteValueOffset, tokens, 0 /* ParseFlags.None */, this.errors, 0 /* relative offset */);
17133    return parser.parseTemplateBindings({
17134      source: templateKey,
17135      span: new AbsoluteSourceSpan(absoluteKeyOffset, absoluteKeyOffset + templateKey.length)
17136    });
17137  }
17138  parseInterpolation(input, location, absoluteOffset, interpolatedTokens, interpolationConfig = DEFAULT_INTERPOLATION_CONFIG) {
17139    const {
17140      strings,
17141      expressions,
17142      offsets
17143    } = this.splitInterpolation(input, location, interpolatedTokens, interpolationConfig);
17144    if (expressions.length === 0) return null;
17145    const expressionNodes = [];
17146    for (let i = 0; i < expressions.length; ++i) {
17147      const expressionText = expressions[i].text;
17148      const sourceToLex = this._stripComments(expressionText);
17149      const tokens = this._lexer.tokenize(sourceToLex);
17150      const ast = new _ParseAST(input, location, absoluteOffset, tokens, 0 /* ParseFlags.None */, this.errors, offsets[i]).parseChain();
17151      expressionNodes.push(ast);
17152    }
17153    return this.createInterpolationAst(strings.map(s => s.text), expressionNodes, input, location, absoluteOffset);
17154  }
17155  /**
17156   * Similar to `parseInterpolation`, but treats the provided string as a single expression
17157   * element that would normally appear within the interpolation prefix and suffix (`{{` and `}}`).
17158   * This is used for parsing the switch expression in ICUs.
17159   */
17160  parseInterpolationExpression(expression, location, absoluteOffset) {
17161    const sourceToLex = this._stripComments(expression);
17162    const tokens = this._lexer.tokenize(sourceToLex);
17163    const ast = new _ParseAST(expression, location, absoluteOffset, tokens, 0 /* ParseFlags.None */, this.errors, 0).parseChain();
17164    const strings = ['', '']; // The prefix and suffix strings are both empty
17165    return this.createInterpolationAst(strings, [ast], expression, location, absoluteOffset);
17166  }
17167  createInterpolationAst(strings, expressions, input, location, absoluteOffset) {
17168    const span = new ParseSpan(0, input.length);
17169    const interpolation = new Interpolation$1(span, span.toAbsolute(absoluteOffset), strings, expressions);
17170    return new ASTWithSource(interpolation, input, location, absoluteOffset, this.errors);
17171  }
17172  /**
17173   * Splits a string of text into "raw" text segments and expressions present in interpolations in
17174   * the string.
17175   * Returns `null` if there are no interpolations, otherwise a
17176   * `SplitInterpolation` with splits that look like
17177   *   <raw text> <expression> <raw text> ... <raw text> <expression> <raw text>
17178   */
17179  splitInterpolation(input, location, interpolatedTokens, interpolationConfig = DEFAULT_INTERPOLATION_CONFIG) {
17180    const strings = [];
17181    const expressions = [];
17182    const offsets = [];
17183    const inputToTemplateIndexMap = interpolatedTokens ? getIndexMapForOriginalTemplate(interpolatedTokens) : null;
17184    let i = 0;
17185    let atInterpolation = false;
17186    let extendLastString = false;
17187    let {
17188      start: interpStart,
17189      end: interpEnd
17190    } = interpolationConfig;
17191    while (i < input.length) {
17192      if (!atInterpolation) {
17193        // parse until starting {{
17194        const start = i;
17195        i = input.indexOf(interpStart, i);
17196        if (i === -1) {
17197          i = input.length;
17198        }
17199        const text = input.substring(start, i);
17200        strings.push({
17201          text,
17202          start,
17203          end: i
17204        });
17205        atInterpolation = true;
17206      } else {
17207        // parse from starting {{ to ending }} while ignoring content inside quotes.
17208        const fullStart = i;
17209        const exprStart = fullStart + interpStart.length;
17210        const exprEnd = this._getInterpolationEndIndex(input, interpEnd, exprStart);
17211        if (exprEnd === -1) {
17212          // Could not find the end of the interpolation; do not parse an expression.
17213          // Instead we should extend the content on the last raw string.
17214          atInterpolation = false;
17215          extendLastString = true;
17216          break;
17217        }
17218        const fullEnd = exprEnd + interpEnd.length;
17219        const text = input.substring(exprStart, exprEnd);
17220        if (text.trim().length === 0) {
17221          this._reportError('Blank expressions are not allowed in interpolated strings', input, `at column ${i} in`, location);
17222        }
17223        expressions.push({
17224          text,
17225          start: fullStart,
17226          end: fullEnd
17227        });
17228        const startInOriginalTemplate = inputToTemplateIndexMap?.get(fullStart) ?? fullStart;
17229        const offset = startInOriginalTemplate + interpStart.length;
17230        offsets.push(offset);
17231        i = fullEnd;
17232        atInterpolation = false;
17233      }
17234    }
17235    if (!atInterpolation) {
17236      // If we are now at a text section, add the remaining content as a raw string.
17237      if (extendLastString) {
17238        const piece = strings[strings.length - 1];
17239        piece.text += input.substring(i);
17240        piece.end = input.length;
17241      } else {
17242        strings.push({
17243          text: input.substring(i),
17244          start: i,
17245          end: input.length
17246        });
17247      }
17248    }
17249    return new SplitInterpolation(strings, expressions, offsets);
17250  }
17251  wrapLiteralPrimitive(input, location, absoluteOffset) {
17252    const span = new ParseSpan(0, input == null ? 0 : input.length);
17253    return new ASTWithSource(new LiteralPrimitive(span, span.toAbsolute(absoluteOffset), input), input, location, absoluteOffset, this.errors);
17254  }
17255  _stripComments(input) {
17256    const i = this._commentStart(input);
17257    return i != null ? input.substring(0, i) : input;
17258  }
17259  _commentStart(input) {
17260    let outerQuote = null;
17261    for (let i = 0; i < input.length - 1; i++) {
17262      const char = input.charCodeAt(i);
17263      const nextChar = input.charCodeAt(i + 1);
17264      if (char === $SLASH && nextChar == $SLASH && outerQuote == null) return i;
17265      if (outerQuote === char) {
17266        outerQuote = null;
17267      } else if (outerQuote == null && isQuote(char)) {
17268        outerQuote = char;
17269      }
17270    }
17271    return null;
17272  }
17273  _checkNoInterpolation(input, location, {
17274    start,
17275    end
17276  }) {
17277    let startIndex = -1;
17278    let endIndex = -1;
17279    for (const charIndex of this._forEachUnquotedChar(input, 0)) {
17280      if (startIndex === -1) {
17281        if (input.startsWith(start)) {
17282          startIndex = charIndex;
17283        }
17284      } else {
17285        endIndex = this._getInterpolationEndIndex(input, end, charIndex);
17286        if (endIndex > -1) {
17287          break;
17288        }
17289      }
17290    }
17291    if (startIndex > -1 && endIndex > -1) {
17292      this._reportError(`Got interpolation (${start}${end}) where expression was expected`, input, `at column ${startIndex} in`, location);
17293    }
17294  }
17295  /**
17296   * Finds the index of the end of an interpolation expression
17297   * while ignoring comments and quoted content.
17298   */
17299  _getInterpolationEndIndex(input, expressionEnd, start) {
17300    for (const charIndex of this._forEachUnquotedChar(input, start)) {
17301      if (input.startsWith(expressionEnd, charIndex)) {
17302        return charIndex;
17303      }
17304      // Nothing else in the expression matters after we've
17305      // hit a comment so look directly for the end token.
17306      if (input.startsWith('//', charIndex)) {
17307        return input.indexOf(expressionEnd, charIndex);
17308      }
17309    }
17310    return -1;
17311  }
17312  /**
17313   * Generator used to iterate over the character indexes of a string that are outside of quotes.
17314   * @param input String to loop through.
17315   * @param start Index within the string at which to start.
17316   */
17317  *_forEachUnquotedChar(input, start) {
17318    let currentQuote = null;
17319    let escapeCount = 0;
17320    for (let i = start; i < input.length; i++) {
17321      const char = input[i];
17322      // Skip the characters inside quotes. Note that we only care about the outer-most
17323      // quotes matching up and we need to account for escape characters.
17324      if (isQuote(input.charCodeAt(i)) && (currentQuote === null || currentQuote === char) && escapeCount % 2 === 0) {
17325        currentQuote = currentQuote === null ? char : null;
17326      } else if (currentQuote === null) {
17327        yield i;
17328      }
17329      escapeCount = char === '\\' ? escapeCount + 1 : 0;
17330    }
17331  }
17332}
17333/** Describes a stateful context an expression parser is in. */
17334var ParseContextFlags;
17335(function (ParseContextFlags) {
17336  ParseContextFlags[ParseContextFlags["None"] = 0] = "None";
17337  /**
17338   * A Writable context is one in which a value may be written to an lvalue.
17339   * For example, after we see a property access, we may expect a write to the
17340   * property via the "=" operator.
17341   *   prop
17342   *        ^ possible "=" after
17343   */
17344  ParseContextFlags[ParseContextFlags["Writable"] = 1] = "Writable";
17345})(ParseContextFlags || (ParseContextFlags = {}));
17346class _ParseAST {
17347  constructor(input, location, absoluteOffset, tokens, parseFlags, errors, offset) {
17348    this.input = input;
17349    this.location = location;
17350    this.absoluteOffset = absoluteOffset;
17351    this.tokens = tokens;
17352    this.parseFlags = parseFlags;
17353    this.errors = errors;
17354    this.offset = offset;
17355    this.rparensExpected = 0;
17356    this.rbracketsExpected = 0;
17357    this.rbracesExpected = 0;
17358    this.context = ParseContextFlags.None;
17359    // Cache of expression start and input indeces to the absolute source span they map to, used to
17360    // prevent creating superfluous source spans in `sourceSpan`.
17361    // A serial of the expression start and input index is used for mapping because both are stateful
17362    // and may change for subsequent expressions visited by the parser.
17363    this.sourceSpanCache = new Map();
17364    this.index = 0;
17365  }
17366  peek(offset) {
17367    const i = this.index + offset;
17368    return i < this.tokens.length ? this.tokens[i] : EOF;
17369  }
17370  get next() {
17371    return this.peek(0);
17372  }
17373  /** Whether all the parser input has been processed. */
17374  get atEOF() {
17375    return this.index >= this.tokens.length;
17376  }
17377  /**
17378   * Index of the next token to be processed, or the end of the last token if all have been
17379   * processed.
17380   */
17381  get inputIndex() {
17382    return this.atEOF ? this.currentEndIndex : this.next.index + this.offset;
17383  }
17384  /**
17385   * End index of the last processed token, or the start of the first token if none have been
17386   * processed.
17387   */
17388  get currentEndIndex() {
17389    if (this.index > 0) {
17390      const curToken = this.peek(-1);
17391      return curToken.end + this.offset;
17392    }
17393    // No tokens have been processed yet; return the next token's start or the length of the input
17394    // if there is no token.
17395    if (this.tokens.length === 0) {
17396      return this.input.length + this.offset;
17397    }
17398    return this.next.index + this.offset;
17399  }
17400  /**
17401   * Returns the absolute offset of the start of the current token.
17402   */
17403  get currentAbsoluteOffset() {
17404    return this.absoluteOffset + this.inputIndex;
17405  }
17406  /**
17407   * Retrieve a `ParseSpan` from `start` to the current position (or to `artificialEndIndex` if
17408   * provided).
17409   *
17410   * @param start Position from which the `ParseSpan` will start.
17411   * @param artificialEndIndex Optional ending index to be used if provided (and if greater than the
17412   *     natural ending index)
17413   */
17414  span(start, artificialEndIndex) {
17415    let endIndex = this.currentEndIndex;
17416    if (artificialEndIndex !== undefined && artificialEndIndex > this.currentEndIndex) {
17417      endIndex = artificialEndIndex;
17418    }
17419    // In some unusual parsing scenarios (like when certain tokens are missing and an `EmptyExpr` is
17420    // being created), the current token may already be advanced beyond the `currentEndIndex`. This
17421    // appears to be a deep-seated parser bug.
17422    //
17423    // As a workaround for now, swap the start and end indices to ensure a valid `ParseSpan`.
17424    // TODO(alxhub): fix the bug upstream in the parser state, and remove this workaround.
17425    if (start > endIndex) {
17426      const tmp = endIndex;
17427      endIndex = start;
17428      start = tmp;
17429    }
17430    return new ParseSpan(start, endIndex);
17431  }
17432  sourceSpan(start, artificialEndIndex) {
17433    const serial = `${start}@${this.inputIndex}:${artificialEndIndex}`;
17434    if (!this.sourceSpanCache.has(serial)) {
17435      this.sourceSpanCache.set(serial, this.span(start, artificialEndIndex).toAbsolute(this.absoluteOffset));
17436    }
17437    return this.sourceSpanCache.get(serial);
17438  }
17439  advance() {
17440    this.index++;
17441  }
17442  /**
17443   * Executes a callback in the provided context.
17444   */
17445  withContext(context, cb) {
17446    this.context |= context;
17447    const ret = cb();
17448    this.context ^= context;
17449    return ret;
17450  }
17451  consumeOptionalCharacter(code) {
17452    if (this.next.isCharacter(code)) {
17453      this.advance();
17454      return true;
17455    } else {
17456      return false;
17457    }
17458  }
17459  peekKeywordLet() {
17460    return this.next.isKeywordLet();
17461  }
17462  peekKeywordAs() {
17463    return this.next.isKeywordAs();
17464  }
17465  /**
17466   * Consumes an expected character, otherwise emits an error about the missing expected character
17467   * and skips over the token stream until reaching a recoverable point.
17468   *
17469   * See `this.error` and `this.skip` for more details.
17470   */
17471  expectCharacter(code) {
17472    if (this.consumeOptionalCharacter(code)) return;
17473    this.error(`Missing expected ${String.fromCharCode(code)}`);
17474  }
17475  consumeOptionalOperator(op) {
17476    if (this.next.isOperator(op)) {
17477      this.advance();
17478      return true;
17479    } else {
17480      return false;
17481    }
17482  }
17483  expectOperator(operator) {
17484    if (this.consumeOptionalOperator(operator)) return;
17485    this.error(`Missing expected operator ${operator}`);
17486  }
17487  prettyPrintToken(tok) {
17488    return tok === EOF ? 'end of input' : `token ${tok}`;
17489  }
17490  expectIdentifierOrKeyword() {
17491    const n = this.next;
17492    if (!n.isIdentifier() && !n.isKeyword()) {
17493      if (n.isPrivateIdentifier()) {
17494        this._reportErrorForPrivateIdentifier(n, 'expected identifier or keyword');
17495      } else {
17496        this.error(`Unexpected ${this.prettyPrintToken(n)}, expected identifier or keyword`);
17497      }
17498      return null;
17499    }
17500    this.advance();
17501    return n.toString();
17502  }
17503  expectIdentifierOrKeywordOrString() {
17504    const n = this.next;
17505    if (!n.isIdentifier() && !n.isKeyword() && !n.isString()) {
17506      if (n.isPrivateIdentifier()) {
17507        this._reportErrorForPrivateIdentifier(n, 'expected identifier, keyword or string');
17508      } else {
17509        this.error(`Unexpected ${this.prettyPrintToken(n)}, expected identifier, keyword, or string`);
17510      }
17511      return '';
17512    }
17513    this.advance();
17514    return n.toString();
17515  }
17516  parseChain() {
17517    const exprs = [];
17518    const start = this.inputIndex;
17519    while (this.index < this.tokens.length) {
17520      const expr = this.parsePipe();
17521      exprs.push(expr);
17522      if (this.consumeOptionalCharacter($SEMICOLON)) {
17523        if (!(this.parseFlags & 1 /* ParseFlags.Action */)) {
17524          this.error('Binding expression cannot contain chained expression');
17525        }
17526        while (this.consumeOptionalCharacter($SEMICOLON)) {} // read all semicolons
17527      } else if (this.index < this.tokens.length) {
17528        const errorIndex = this.index;
17529        this.error(`Unexpected token '${this.next}'`);
17530        // The `error` call above will skip ahead to the next recovery point in an attempt to
17531        // recover part of the expression, but that might be the token we started from which will
17532        // lead to an infinite loop. If that's the case, break the loop assuming that we can't
17533        // parse further.
17534        if (this.index === errorIndex) {
17535          break;
17536        }
17537      }
17538    }
17539    if (exprs.length === 0) {
17540      // We have no expressions so create an empty expression that spans the entire input length
17541      const artificialStart = this.offset;
17542      const artificialEnd = this.offset + this.input.length;
17543      return new EmptyExpr$1(this.span(artificialStart, artificialEnd), this.sourceSpan(artificialStart, artificialEnd));
17544    }
17545    if (exprs.length == 1) return exprs[0];
17546    return new Chain(this.span(start), this.sourceSpan(start), exprs);
17547  }
17548  parsePipe() {
17549    const start = this.inputIndex;
17550    let result = this.parseExpression();
17551    if (this.consumeOptionalOperator('|')) {
17552      if (this.parseFlags & 1 /* ParseFlags.Action */) {
17553        this.error(`Cannot have a pipe in an action expression`);
17554      }
17555      do {
17556        const nameStart = this.inputIndex;
17557        let nameId = this.expectIdentifierOrKeyword();
17558        let nameSpan;
17559        let fullSpanEnd = undefined;
17560        if (nameId !== null) {
17561          nameSpan = this.sourceSpan(nameStart);
17562        } else {
17563          // No valid identifier was found, so we'll assume an empty pipe name ('').
17564          nameId = '';
17565          // However, there may have been whitespace present between the pipe character and the next
17566          // token in the sequence (or the end of input). We want to track this whitespace so that
17567          // the `BindingPipe` we produce covers not just the pipe character, but any trailing
17568          // whitespace beyond it. Another way of thinking about this is that the zero-length name
17569          // is assumed to be at the end of any whitespace beyond the pipe character.
17570          //
17571          // Therefore, we push the end of the `ParseSpan` for this pipe all the way up to the
17572          // beginning of the next token, or until the end of input if the next token is EOF.
17573          fullSpanEnd = this.next.index !== -1 ? this.next.index : this.input.length + this.offset;
17574          // The `nameSpan` for an empty pipe name is zero-length at the end of any whitespace
17575          // beyond the pipe character.
17576          nameSpan = new ParseSpan(fullSpanEnd, fullSpanEnd).toAbsolute(this.absoluteOffset);
17577        }
17578        const args = [];
17579        while (this.consumeOptionalCharacter($COLON)) {
17580          args.push(this.parseExpression());
17581          // If there are additional expressions beyond the name, then the artificial end for the
17582          // name is no longer relevant.
17583        }
17584        result = new BindingPipe(this.span(start), this.sourceSpan(start, fullSpanEnd), result, nameId, args, nameSpan);
17585      } while (this.consumeOptionalOperator('|'));
17586    }
17587    return result;
17588  }
17589  parseExpression() {
17590    return this.parseConditional();
17591  }
17592  parseConditional() {
17593    const start = this.inputIndex;
17594    const result = this.parseLogicalOr();
17595    if (this.consumeOptionalOperator('?')) {
17596      const yes = this.parsePipe();
17597      let no;
17598      if (!this.consumeOptionalCharacter($COLON)) {
17599        const end = this.inputIndex;
17600        const expression = this.input.substring(start, end);
17601        this.error(`Conditional expression ${expression} requires all 3 expressions`);
17602        no = new EmptyExpr$1(this.span(start), this.sourceSpan(start));
17603      } else {
17604        no = this.parsePipe();
17605      }
17606      return new Conditional(this.span(start), this.sourceSpan(start), result, yes, no);
17607    } else {
17608      return result;
17609    }
17610  }
17611  parseLogicalOr() {
17612    // '||'
17613    const start = this.inputIndex;
17614    let result = this.parseLogicalAnd();
17615    while (this.consumeOptionalOperator('||')) {
17616      const right = this.parseLogicalAnd();
17617      result = new Binary(this.span(start), this.sourceSpan(start), '||', result, right);
17618    }
17619    return result;
17620  }
17621  parseLogicalAnd() {
17622    // '&&'
17623    const start = this.inputIndex;
17624    let result = this.parseNullishCoalescing();
17625    while (this.consumeOptionalOperator('&&')) {
17626      const right = this.parseNullishCoalescing();
17627      result = new Binary(this.span(start), this.sourceSpan(start), '&&', result, right);
17628    }
17629    return result;
17630  }
17631  parseNullishCoalescing() {
17632    // '??'
17633    const start = this.inputIndex;
17634    let result = this.parseEquality();
17635    while (this.consumeOptionalOperator('??')) {
17636      const right = this.parseEquality();
17637      result = new Binary(this.span(start), this.sourceSpan(start), '??', result, right);
17638    }
17639    return result;
17640  }
17641  parseEquality() {
17642    // '==','!=','===','!=='
17643    const start = this.inputIndex;
17644    let result = this.parseRelational();
17645    while (this.next.type == TokenType.Operator) {
17646      const operator = this.next.strValue;
17647      switch (operator) {
17648        case '==':
17649        case '===':
17650        case '!=':
17651        case '!==':
17652          this.advance();
17653          const right = this.parseRelational();
17654          result = new Binary(this.span(start), this.sourceSpan(start), operator, result, right);
17655          continue;
17656      }
17657      break;
17658    }
17659    return result;
17660  }
17661  parseRelational() {
17662    // '<', '>', '<=', '>='
17663    const start = this.inputIndex;
17664    let result = this.parseAdditive();
17665    while (this.next.type == TokenType.Operator) {
17666      const operator = this.next.strValue;
17667      switch (operator) {
17668        case '<':
17669        case '>':
17670        case '<=':
17671        case '>=':
17672          this.advance();
17673          const right = this.parseAdditive();
17674          result = new Binary(this.span(start), this.sourceSpan(start), operator, result, right);
17675          continue;
17676      }
17677      break;
17678    }
17679    return result;
17680  }
17681  parseAdditive() {
17682    // '+', '-'
17683    const start = this.inputIndex;
17684    let result = this.parseMultiplicative();
17685    while (this.next.type == TokenType.Operator) {
17686      const operator = this.next.strValue;
17687      switch (operator) {
17688        case '+':
17689        case '-':
17690          this.advance();
17691          let right = this.parseMultiplicative();
17692          result = new Binary(this.span(start), this.sourceSpan(start), operator, result, right);
17693          continue;
17694      }
17695      break;
17696    }
17697    return result;
17698  }
17699  parseMultiplicative() {
17700    // '*', '%', '/'
17701    const start = this.inputIndex;
17702    let result = this.parsePrefix();
17703    while (this.next.type == TokenType.Operator) {
17704      const operator = this.next.strValue;
17705      switch (operator) {
17706        case '*':
17707        case '%':
17708        case '/':
17709          this.advance();
17710          let right = this.parsePrefix();
17711          result = new Binary(this.span(start), this.sourceSpan(start), operator, result, right);
17712          continue;
17713      }
17714      break;
17715    }
17716    return result;
17717  }
17718  parsePrefix() {
17719    if (this.next.type == TokenType.Operator) {
17720      const start = this.inputIndex;
17721      const operator = this.next.strValue;
17722      let result;
17723      switch (operator) {
17724        case '+':
17725          this.advance();
17726          result = this.parsePrefix();
17727          return Unary.createPlus(this.span(start), this.sourceSpan(start), result);
17728        case '-':
17729          this.advance();
17730          result = this.parsePrefix();
17731          return Unary.createMinus(this.span(start), this.sourceSpan(start), result);
17732        case '!':
17733          this.advance();
17734          result = this.parsePrefix();
17735          return new PrefixNot(this.span(start), this.sourceSpan(start), result);
17736      }
17737    }
17738    return this.parseCallChain();
17739  }
17740  parseCallChain() {
17741    const start = this.inputIndex;
17742    let result = this.parsePrimary();
17743    while (true) {
17744      if (this.consumeOptionalCharacter($PERIOD)) {
17745        result = this.parseAccessMember(result, start, false);
17746      } else if (this.consumeOptionalOperator('?.')) {
17747        if (this.consumeOptionalCharacter($LPAREN)) {
17748          result = this.parseCall(result, start, true);
17749        } else {
17750          result = this.consumeOptionalCharacter($LBRACKET) ? this.parseKeyedReadOrWrite(result, start, true) : this.parseAccessMember(result, start, true);
17751        }
17752      } else if (this.consumeOptionalCharacter($LBRACKET)) {
17753        result = this.parseKeyedReadOrWrite(result, start, false);
17754      } else if (this.consumeOptionalCharacter($LPAREN)) {
17755        result = this.parseCall(result, start, false);
17756      } else if (this.consumeOptionalOperator('!')) {
17757        result = new NonNullAssert(this.span(start), this.sourceSpan(start), result);
17758      } else {
17759        return result;
17760      }
17761    }
17762  }
17763  parsePrimary() {
17764    const start = this.inputIndex;
17765    if (this.consumeOptionalCharacter($LPAREN)) {
17766      this.rparensExpected++;
17767      const result = this.parsePipe();
17768      this.rparensExpected--;
17769      this.expectCharacter($RPAREN);
17770      return result;
17771    } else if (this.next.isKeywordNull()) {
17772      this.advance();
17773      return new LiteralPrimitive(this.span(start), this.sourceSpan(start), null);
17774    } else if (this.next.isKeywordUndefined()) {
17775      this.advance();
17776      return new LiteralPrimitive(this.span(start), this.sourceSpan(start), void 0);
17777    } else if (this.next.isKeywordTrue()) {
17778      this.advance();
17779      return new LiteralPrimitive(this.span(start), this.sourceSpan(start), true);
17780    } else if (this.next.isKeywordFalse()) {
17781      this.advance();
17782      return new LiteralPrimitive(this.span(start), this.sourceSpan(start), false);
17783    } else if (this.next.isKeywordThis()) {
17784      this.advance();
17785      return new ThisReceiver(this.span(start), this.sourceSpan(start));
17786    } else if (this.consumeOptionalCharacter($LBRACKET)) {
17787      this.rbracketsExpected++;
17788      const elements = this.parseExpressionList($RBRACKET);
17789      this.rbracketsExpected--;
17790      this.expectCharacter($RBRACKET);
17791      return new LiteralArray(this.span(start), this.sourceSpan(start), elements);
17792    } else if (this.next.isCharacter($LBRACE)) {
17793      return this.parseLiteralMap();
17794    } else if (this.next.isIdentifier()) {
17795      return this.parseAccessMember(new ImplicitReceiver(this.span(start), this.sourceSpan(start)), start, false);
17796    } else if (this.next.isNumber()) {
17797      const value = this.next.toNumber();
17798      this.advance();
17799      return new LiteralPrimitive(this.span(start), this.sourceSpan(start), value);
17800    } else if (this.next.isString()) {
17801      const literalValue = this.next.toString();
17802      this.advance();
17803      return new LiteralPrimitive(this.span(start), this.sourceSpan(start), literalValue);
17804    } else if (this.next.isPrivateIdentifier()) {
17805      this._reportErrorForPrivateIdentifier(this.next, null);
17806      return new EmptyExpr$1(this.span(start), this.sourceSpan(start));
17807    } else if (this.index >= this.tokens.length) {
17808      this.error(`Unexpected end of expression: ${this.input}`);
17809      return new EmptyExpr$1(this.span(start), this.sourceSpan(start));
17810    } else {
17811      this.error(`Unexpected token ${this.next}`);
17812      return new EmptyExpr$1(this.span(start), this.sourceSpan(start));
17813    }
17814  }
17815  parseExpressionList(terminator) {
17816    const result = [];
17817    do {
17818      if (!this.next.isCharacter(terminator)) {
17819        result.push(this.parsePipe());
17820      } else {
17821        break;
17822      }
17823    } while (this.consumeOptionalCharacter($COMMA));
17824    return result;
17825  }
17826  parseLiteralMap() {
17827    const keys = [];
17828    const values = [];
17829    const start = this.inputIndex;
17830    this.expectCharacter($LBRACE);
17831    if (!this.consumeOptionalCharacter($RBRACE)) {
17832      this.rbracesExpected++;
17833      do {
17834        const keyStart = this.inputIndex;
17835        const quoted = this.next.isString();
17836        const key = this.expectIdentifierOrKeywordOrString();
17837        keys.push({
17838          key,
17839          quoted
17840        });
17841        // Properties with quoted keys can't use the shorthand syntax.
17842        if (quoted) {
17843          this.expectCharacter($COLON);
17844          values.push(this.parsePipe());
17845        } else if (this.consumeOptionalCharacter($COLON)) {
17846          values.push(this.parsePipe());
17847        } else {
17848          const span = this.span(keyStart);
17849          const sourceSpan = this.sourceSpan(keyStart);
17850          values.push(new PropertyRead(span, sourceSpan, sourceSpan, new ImplicitReceiver(span, sourceSpan), key));
17851        }
17852      } while (this.consumeOptionalCharacter($COMMA) && !this.next.isCharacter($RBRACE));
17853      this.rbracesExpected--;
17854      this.expectCharacter($RBRACE);
17855    }
17856    return new LiteralMap(this.span(start), this.sourceSpan(start), keys, values);
17857  }
17858  parseAccessMember(readReceiver, start, isSafe) {
17859    const nameStart = this.inputIndex;
17860    const id = this.withContext(ParseContextFlags.Writable, () => {
17861      const id = this.expectIdentifierOrKeyword() ?? '';
17862      if (id.length === 0) {
17863        this.error(`Expected identifier for property access`, readReceiver.span.end);
17864      }
17865      return id;
17866    });
17867    const nameSpan = this.sourceSpan(nameStart);
17868    let receiver;
17869    if (isSafe) {
17870      if (this.consumeOptionalOperator('=')) {
17871        this.error('The \'?.\' operator cannot be used in the assignment');
17872        receiver = new EmptyExpr$1(this.span(start), this.sourceSpan(start));
17873      } else {
17874        receiver = new SafePropertyRead(this.span(start), this.sourceSpan(start), nameSpan, readReceiver, id);
17875      }
17876    } else {
17877      if (this.consumeOptionalOperator('=')) {
17878        if (!(this.parseFlags & 1 /* ParseFlags.Action */)) {
17879          this.error('Bindings cannot contain assignments');
17880          return new EmptyExpr$1(this.span(start), this.sourceSpan(start));
17881        }
17882        const value = this.parseConditional();
17883        receiver = new PropertyWrite(this.span(start), this.sourceSpan(start), nameSpan, readReceiver, id, value);
17884      } else {
17885        receiver = new PropertyRead(this.span(start), this.sourceSpan(start), nameSpan, readReceiver, id);
17886      }
17887    }
17888    return receiver;
17889  }
17890  parseCall(receiver, start, isSafe) {
17891    const argumentStart = this.inputIndex;
17892    this.rparensExpected++;
17893    const args = this.parseCallArguments();
17894    const argumentSpan = this.span(argumentStart, this.inputIndex).toAbsolute(this.absoluteOffset);
17895    this.expectCharacter($RPAREN);
17896    this.rparensExpected--;
17897    const span = this.span(start);
17898    const sourceSpan = this.sourceSpan(start);
17899    return isSafe ? new SafeCall(span, sourceSpan, receiver, args, argumentSpan) : new Call(span, sourceSpan, receiver, args, argumentSpan);
17900  }
17901  parseCallArguments() {
17902    if (this.next.isCharacter($RPAREN)) return [];
17903    const positionals = [];
17904    do {
17905      positionals.push(this.parsePipe());
17906    } while (this.consumeOptionalCharacter($COMMA));
17907    return positionals;
17908  }
17909  /**
17910   * Parses an identifier, a keyword, a string with an optional `-` in between,
17911   * and returns the string along with its absolute source span.
17912   */
17913  expectTemplateBindingKey() {
17914    let result = '';
17915    let operatorFound = false;
17916    const start = this.currentAbsoluteOffset;
17917    do {
17918      result += this.expectIdentifierOrKeywordOrString();
17919      operatorFound = this.consumeOptionalOperator('-');
17920      if (operatorFound) {
17921        result += '-';
17922      }
17923    } while (operatorFound);
17924    return {
17925      source: result,
17926      span: new AbsoluteSourceSpan(start, start + result.length)
17927    };
17928  }
17929  /**
17930   * Parse microsyntax template expression and return a list of bindings or
17931   * parsing errors in case the given expression is invalid.
17932   *
17933   * For example,
17934   * ```
17935   *   <div *ngFor="let item of items; index as i; trackBy: func">
17936   * ```
17937   * contains five bindings:
17938   * 1. ngFor -> null
17939   * 2. item -> NgForOfContext.$implicit
17940   * 3. ngForOf -> items
17941   * 4. i ->
17941 NgForOfContext.index
17942   * 5. ngForTrackBy -> func
17943   *
17944   * For a full description of the microsyntax grammar, see
17945   * https://gist.github.com/mhevery/d3530294cff2e4a1b3fe15ff75d08855
17946   *
17947   * @param templateKey name of the microsyntax directive, like ngIf, ngFor,
17948   * without the *, along with its absolute span.
17949   */
17950  parseTemplateBindings(templateKey) {
17951    const bindings = [];
17952    // The first binding is for the template key itself
17953    // In *ngFor="let item of items", key = "ngFor", value = null
17954    // In *ngIf="cond | pipe", key = "ngIf", value = "cond | pipe"
17955    bindings.push(...this.parseDirectiveKeywordBindings(templateKey));
17956    while (this.index < this.tokens.length) {
17957      // If it starts with 'let', then this must be variable declaration
17958      const letBinding = this.parseLetBinding();
17959      if (letBinding) {
17960        bindings.push(letBinding);
17961      } else {
17962        // Two possible cases here, either `value "as" key` or
17963        // "directive-keyword expression". We don't know which case, but both
17964        // "value" and "directive-keyword" are template binding key, so consume
17965        // the key first.
17966        const key = this.expectTemplateBindingKey();
17967        // Peek at the next token, if it is "as" then this must be variable
17968        // declaration.
17969        const binding = this.parseAsBinding(key);
17970        if (binding) {
17971          bindings.push(binding);
17972        } else {
17973          // Otherwise the key must be a directive keyword, like "of". Transform
17974          // the key to actual key. Eg. of -> ngForOf, trackBy -> ngForTrackBy
17975          key.source = templateKey.source + key.source.charAt(0).toUpperCase() + key.source.substring(1);
17976          bindings.push(...this.parseDirectiveKeywordBindings(key));
17977        }
17978      }
17979      this.consumeStatementTerminator();
17980    }
17981    return new TemplateBindingParseResult(bindings, [] /* warnings */, this.errors);
17982  }
17983  parseKeyedReadOrWrite(receiver, start, isSafe) {
17984    return this.withContext(ParseContextFlags.Writable, () => {
17985      this.rbracketsExpected++;
17986      const key = this.parsePipe();
17987      if (key instanceof EmptyExpr$1) {
17988        this.error(`Key access cannot be empty`);
17989      }
17990      this.rbracketsExpected--;
17991      this.expectCharacter($RBRACKET);
17992      if (this.consumeOptionalOperator('=')) {
17993        if (isSafe) {
17994          this.error('The \'?.\' operator cannot be used in the assignment');
17995        } else {
17996          const value = this.parseConditional();
17997          return new KeyedWrite(this.span(start), this.sourceSpan(start), receiver, key, value);
17998        }
17999      } else {
18000        return isSafe ? new SafeKeyedRead(this.span(start), this.sourceSpan(start), receiver, key) : new KeyedRead(this.span(start), this.sourceSpan(start), receiver, key);
18001      }
18002      return new EmptyExpr$1(this.span(start), this.sourceSpan(start));
18003    });
18004  }
18005  /**
18006   * Parse a directive keyword, followed by a mandatory expression.
18007   * For example, "of items", "trackBy: func".
18008   * The bindings are: ngForOf -> items, ngForTrackBy -> func
18009   * There could be an optional "as" binding that follows the expression.
18010   * For example,
18011   * ```
18012   *   *ngFor="let item of items | slice:0:1 as collection".
18013   *                    ^^ ^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^
18014   *               keyword    bound target   optional 'as' binding
18015   * ```
18016   *
18017   * @param key binding key, for example, ngFor, ngIf, ngForOf, along with its
18018   * absolute span.
18019   */
18020  parseDirectiveKeywordBindings(key) {
18021    const bindings = [];
18022    this.consumeOptionalCharacter($COLON); // trackBy: trackByFunction
18023    const value = this.getDirectiveBoundTarget();
18024    let spanEnd = this.currentAbsoluteOffset;
18025    // The binding could optionally be followed by "as". For example,
18026    // *ngIf="cond | pipe as x". In this case, the key in the "as" binding
18027    // is "x" and the value is the template key itself ("ngIf"). Note that the
18028    // 'key' in the current context now becomes the "value" in the next binding.
18029    const asBinding = this.parseAsBinding(key);
18030    if (!asBinding) {
18031      this.consumeStatementTerminator();
18032      spanEnd = this.currentAbsoluteOffset;
18033    }
18034    const sourceSpan = new AbsoluteSourceSpan(key.span.start, spanEnd);
18035    bindings.push(new ExpressionBinding(sourceSpan, key, value));
18036    if (asBinding) {
18037      bindings.push(asBinding);
18038    }
18039    return bindings;
18040  }
18041  /**
18042   * Return the expression AST for the bound target of a directive keyword
18043   * binding. For example,
18044   * ```
18045   *   *ngIf="condition | pipe"
18046   *          ^^^^^^^^^^^^^^^^ bound target for "ngIf"
18047   *   *ngFor="let item of items"
18048   *                       ^^^^^ bound target for "ngForOf"
18049   * ```
18050   */
18051  getDirectiveBoundTarget() {
18052    if (this.next === EOF || this.peekKeywordAs() || this.peekKeywordLet()) {
18053      return null;
18054    }
18055    const ast = this.parsePipe(); // example: "condition | async"
18056    const {
18057      start,
18058      end
18059    } = ast.span;
18060    const value = this.input.substring(start, end);
18061    return new ASTWithSource(ast, value, this.location, this.absoluteOffset + start, this.errors);
18062  }
18063  /**
18064   * Return the binding for a variable declared using `as`. Note that the order
18065   * of the key-value pair in this declaration is reversed. For example,
18066   * ```
18067   *   *ngFor="let item of items; index as i"
18068   *                              ^^^^^    ^
18069   *                              value    key
18070   * ```
18071   *
18072   * @param value name of the value in the declaration, "ngIf" in the example
18073   * above, along with its absolute span.
18074   */
18075  parseAsBinding(value) {
18076    if (!this.peekKeywordAs()) {
18077      return null;
18078    }
18079    this.advance(); // consume the 'as' keyword
18080    const key = this.expectTemplateBindingKey();
18081    this.consumeStatementTerminator();
18082    const sourceSpan = new AbsoluteSourceSpan(value.span.start, this.currentAbsoluteOffset);
18083    return new VariableBinding(sourceSpan, key, value);
18084  }
18085  /**
18086   * Return the binding for a variable declared using `let`. For example,
18087   * ```
18088   *   *ngFor="let item of items; let i=index;"
18089   *           ^^^^^^^^           ^^^^^^^^^^^
18090   * ```
18091   * In the first binding, `item` is bound to `NgForOfContext.$implicit`.
18092   * In the second binding, `i` is bound to `NgForOfContext.index`.
18093   */
18094  parseLetBinding() {
18095    if (!this.peekKeywordLet()) {
18096      return null;
18097    }
18098    const spanStart = this.currentAbsoluteOffset;
18099    this.advance(); // consume the 'let' keyword
18100    const key = this.expectTemplateBindingKey();
18101    let value = null;
18102    if (this.consumeOptionalOperator('=')) {
18103      value = this.expectTemplateBindingKey();
18104    }
18105    this.consumeStatementTerminator();
18106    const sourceSpan = new AbsoluteSourceSpan(spanStart, this.currentAbsoluteOffset);
18107    return new VariableBinding(sourceSpan, key, value);
18108  }
18109  /**
18110   * Consume the optional statement terminator: semicolon or comma.
18111   */
18112  consumeStatementTerminator() {
18113    this.consumeOptionalCharacter($SEMICOLON) || this.consumeOptionalCharacter($COMMA);
18114  }
18115  /**
18116   * Records an error and skips over the token stream until reaching a recoverable point. See
18117   * `this.skip` for more details on token skipping.
18118   */
18119  error(message, index = null) {
18120    this.errors.push(new ParserError(message, this.input, this.locationText(index), this.location));
18121    this.skip();
18122  }
18123  locationText(index = null) {
18124    if (index == null) index = this.index;
18125    return index < this.tokens.length ? `at column ${this.tokens[index].index + 1} in` : `at the end of the expression`;
18126  }
18127  /**
18128   * Records an error for an unexpected private identifier being discovered.
18129   * @param token Token representing a private identifier.
18130   * @param extraMessage Optional additional message being appended to the error.
18131   */
18132  _reportErrorForPrivateIdentifier(token, extraMessage) {
18133    let errorMessage = `Private identifiers are not supported. Unexpected private identifier: ${token}`;
18134    if (extraMessage !== null) {
18135      errorMessage += `, ${extraMessage}`;
18136    }
18137    this.error(errorMessage);
18138  }
18139  /**
18140   * Error recovery should skip tokens until it encounters a recovery point.
18141   *
18142   * The following are treated as unconditional recovery points:
18143   *   - end of input
18144   *   - ';' (parseChain() is always the root production, and it expects a ';')
18145   *   - '|' (since pipes may be chained and each pipe expression may be treated independently)
18146   *
18147   * The following are conditional recovery points:
18148   *   - ')', '}', ']' if one of calling productions is expecting one of these symbols
18149   *     - This allows skip() to recover from errors such as '(a.) + 1' allowing more of the AST to
18150   *       be retained (it doesn't skip any tokens as the ')' is retained because of the '(' begins
18151   *       an '(' <expr> ')' production).
18152   *       The recovery points of grouping symbols must be conditional as they must be skipped if
18153   *       none of the calling productions are not expecting the closing token else we will never
18154   *       make progress in the case of an extraneous group closing symbol (such as a stray ')').
18155   *       That is, we skip a closing symbol if we are not in a grouping production.
18156   *   - '=' in a `Writable` context
18157   *     - In this context, we are able to recover after seeing the `=` operator, which
18158   *       signals the presence of an independent rvalue expression following the `=` operator.
18159   *
18160   * If a production expects one of these token it increments the corresponding nesting count,
18161   * and then decrements it just prior to checking if the token is in the input.
18162   */
18163  skip() {
18164    let n = this.next;
18165    while (this.index < this.tokens.length && !n.isCharacter($SEMICOLON) && !n.isOperator('|') && (this.rparensExpected <= 0 || !n.isCharacter($RPAREN)) && (this.rbracesExpected <= 0 || !n.isCharacter($RBRACE)) && (this.rbracketsExpected <= 0 || !n.isCharacter($RBRACKET)) && (!(this.context & ParseContextFlags.Writable) || !n.isOperator('='))) {
18166      if (this.next.isError()) {
18167        this.errors.push(new ParserError(this.next.toString(), this.input, this.locationText(), this.location));
18168      }
18169      this.advance();
18170      n = this.next;
18171    }
18172  }
18173}
18174class SimpleExpressionChecker extends RecursiveAstVisitor {
18175  constructor() {
18176    super(...arguments);
18177    this.errors = [];
18178  }
18179  visitPipe() {
18180    this.errors.push('pipes');
18181  }
18182}
18183/**
18184 * Computes the real offset in the original template for indexes in an interpolation.
18185 *
18186 * Because templates can have encoded HTML entities and the input passed to the parser at this stage
18187 * of the compiler is the _decoded_ value, we need to compute the real offset using the original
18188 * encoded values in the interpolated tokens. Note that this is only a special case handling for
18189 * `MlParserTokenType.ENCODED_ENTITY` token types. All other interpolated tokens are expected to
18190 * have parts which exactly match the input string for parsing the interpolation.
18191 *
18192 * @param interpolatedTokens The tokens for the interpolated value.
18193 *
18194 * @returns A map of index locations in the decoded template to indexes in the original template
18195 */
18196function getIndexMapForOriginalTemplate(interpolatedTokens) {
18197  let offsetMap = new Map();
18198  let consumedInOriginalTemplate = 0;
18199  let consumedInInput = 0;
18200  let tokenIndex = 0;
18201  while (tokenIndex < interpolatedTokens.length) {
18202    const currentToken = interpolatedTokens[tokenIndex];
18203    if (currentToken.type === 9 /* MlParserTokenType.ENCODED_ENTITY */) {
18204      const [decoded, encoded] = currentToken.parts;
18205      consumedInOriginalTemplate += encoded.length;
18206      consumedInInput += decoded.length;
18207    } else {
18208      const lengthOfParts = currentToken.parts.reduce((sum, current) => sum + current.length, 0);
18209      consumedInInput += lengthOfParts;
18210      consumedInOriginalTemplate += lengthOfParts;
18211    }
18212    offsetMap.set(consumedInInput, consumedInOriginalTemplate);
18213    tokenIndex++;
18214  }
18215  return offsetMap;
18216}
18217class NodeWithI18n {
18218  constructor(sourceSpan, i18n) {
18219    this.sourceSpan = sourceSpan;
18220    this.i18n = i18n;
18221  }
18222}
18223class Text extends NodeWithI18n {
18224  constructor(value, sourceSpan, tokens, i18n) {
18225    super(sourceSpan, i18n);
18226    this.value = value;
18227    this.tokens = tokens;
18228  }
18229  visit(visitor, context) {
18230    return visitor.visitText(this, context);
18231  }
18232}
18233class Expansion extends NodeWithI18n {
18234  constructor(switchValue, type, cases, sourceSpan, switchValueSourceSpan, i18n) {
18235    super(sourceSpan, i18n);
18236    this.switchValue = switchValue;
18237    this.type = type;
18238    this.cases = cases;
18239    this.switchValueSourceSpan = switchValueSourceSpan;
18240  }
18241  visit(visitor, context) {
18242    return visitor.visitExpansion(this, context);
18243  }
18244}
18245class ExpansionCase {
18246  constructor(value, expression, sourceSpan, valueSourceSpan, expSourceSpan) {
18247    this.value = value;
18248    this.expression = expression;
18249    this.sourceSpan = sourceSpan;
18250    this.valueSourceSpan = valueSourceSpan;
18251    this.expSourceSpan = expSourceSpan;
18252  }
18253  visit(visitor, context) {
18254    return visitor.visitExpansionCase(this, context);
18255  }
18256}
18257class Attribute extends NodeWithI18n {
18258  constructor(name, value, sourceSpan, keySpan, valueSpan, valueTokens, i18n) {
18259    super(sourceSpan, i18n);
18260    this.name = name;
18261    this.value = value;
18262    this.keySpan = keySpan;
18263    this.valueSpan = valueSpan;
18264    this.valueTokens = valueTokens;
18265  }
18266  visit(visitor, context) {
18267    return visitor.visitAttribute(this, context);
18268  }
18269}
18270class Element extends NodeWithI18n {
18271  constructor(name, attrs, children, sourceSpan, startSourceSpan, endSourceSpan = null, i18n) {
18272    super(sourceSpan, i18n);
18273    this.name = name;
18274    this.attrs = attrs;
18275    this.children = children;
18276    this.startSourceSpan = startSourceSpan;
18277    this.endSourceSpan = endSourceSpan;
18278  }
18279  visit(visitor, context) {
18280    return visitor.visitElement(this, context);
18281  }
18282}
18283class Comment {
18284  constructor(value, sourceSpan) {
18285    this.value = value;
18286    this.sourceSpan = sourceSpan;
18287  }
18288  visit(visitor, context) {
18289    return visitor.visitComment(this, context);
18290  }
18291}
18292class Block extends NodeWithI18n {
18293  constructor(name, parameters, children, sourceSpan, nameSpan, startSourceSpan, endSourceSpan = null, i18n) {
18294    super(sourceSpan, i18n);
18295    this.name = name;
18296    this.parameters = parameters;
18297    this.children = children;
18298    this.nameSpan = nameSpan;
18299    this.startSourceSpan = startSourceSpan;
18300    this.endSourceSpan = endSourceSpan;
18301  }
18302  visit(visitor, context) {
18303    return visitor.visitBlock(this, context);
18304  }
18305}
18306class BlockParameter {
18307  constructor(expression, sourceSpan) {
18308    this.expression = expression;
18309    this.sourceSpan = sourceSpan;
18310  }
18311  visit(visitor, context) {
18312    return visitor.visitBlockParameter(this, context);
18313  }
18314}
18315function visitAll(visitor, nodes, context = null) {
18316  const result = [];
18317  const visit = visitor.visit ? ast => visitor.visit(ast, context) || ast.visit(visitor, context) : ast => ast.visit(visitor, context);
18318  nodes.forEach(ast => {
18319    const astResult = visit(ast);
18320    if (astResult) {
18321      result.push(astResult);
18322    }
18323  });
18324  return result;
18325}
18326class RecursiveVisitor {
18327  constructor() {}
18328  visitElement(ast, context) {
18329    this.visitChildren(context, visit => {
18330      visit(ast.attrs);
18331      visit(ast.children);
18332    });
18333  }
18334  visitAttribute(ast, context) {}
18335  visitText(ast, context) {}
18336  visitComment(ast, context) {}
18337  visitExpansion(ast, context) {
18338    return this.visitChildren(context, visit => {
18339      visit(ast.cases);
18340    });
18341  }
18342  visitExpansionCase(ast, context) {}
18343  visitBlock(block, context) {
18344    this.visitChildren(context, visit => {
18345      visit(block.parameters);
18346      visit(block.children);
18347    });
18348  }
18349  visitBlockParameter(ast, context) {}
18350  visitChildren(context, cb) {
18351    let results = [];
18352    let t = this;
18353    function visit(children) {
18354      if (children) results.push(visitAll(t, children, context));
18355    }
18356    cb(visit);
18357    return Array.prototype.concat.apply([], results);
18358  }
18359}
18360class ElementSchemaRegistry {}
18361const BOOLEAN = 'boolean';
18362const NUMBER = 'number';
18363const STRING = 'string';
18364const OBJECT = 'object';
18365/**
18366 * This array represents the DOM schema. It encodes inheritance, properties, and events.
18367 *
18368 * ## Overview
18369 *
18370 * Each line represents one kind of element. The `element_inheritance` and properties are joined
18371 * using `element_inheritance|properties` syntax.
18372 *
18373 * ## Element Inheritance
18374 *
18375 * The `element_inheritance` can be further subdivided as `element1,element2,...^parentElement`.
18376 * Here the individual elements are separated by `,` (commas). Every element in the list
18377 * has identical properties.
18378 *
18379 * An `element` may inherit additional properties from `parentElement` If no `^parentElement` is
18380 * specified then `""` (blank) element is assumed.
18381 *
18382 * NOTE: The blank element inherits from root `[Element]` element, the super element of all
18383 * elements.
18384 *
18385 * NOTE an element prefix such as `:svg:` has no special meaning to the schema.
18386 *
18387 * ## Properties
18388 *
18389 * Each element has a set of properties separated by `,` (commas). Each property can be prefixed
18390 * by a special character designating its type:
18391 *
18392 * - (no prefix): property is a string.
18393 * - `*`: property represents an event.
18394 * - `!`: property is a boolean.
18395 * - `#`: property is a number.
18396 * - `%`: property is an object.
18397 *
18398 * ## Query
18399 *
18400 * The class creates an internal squas representation which allows to easily answer the query of
18401 * if a given property exist on a given element.
18402 *
18403 * NOTE: We don't yet support querying for types or events.
18404 * NOTE: This schema is auto extracted from `schema_extractor.ts` located in the test folder,
18405 *       see dom_element_schema_registry_spec.ts
18406 */
18407// =================================================================================================
18408// =================================================================================================
18409// =========== S T O P   -  S T O P   -  S T O P   -  S T O P   -  S T O P   -  S T O P  ===========
18410// =================================================================================================
18411// =================================================================================================
18412//
18413//                       DO NOT EDIT THIS DOM SCHEMA WITHOUT A SECURITY REVIEW!
18414//
18415// Newly added properties must be security reviewed and assigned an appropriate SecurityContext in
18416// dom_security_schema.ts. Reach out to mprobst & rjamet for details.
18417//
18418// =================================================================================================
18419const SCHEMA = ['[Element]|textContent,%ariaAtomic,%ariaAutoComplete,%ariaBusy,%ariaChecked,%ariaColCount,%ariaColIndex,%ariaColSpan,%ariaCurrent,%ariaDescription,%ariaDisabled,%ariaExpanded,%ariaHasPopup,%ariaHidden,%ariaKeyShortcuts,%ariaLabel,%ariaLevel,%ariaLive,%ariaModal,%ariaMultiLine,%ariaMultiSelectable,%ariaOrientation,%ariaPlaceholder,%ariaPosInSet,%ariaPressed,%ariaReadOnly,%ariaRelevant,%ariaRequired,%ariaRoleDescription,%ariaRowCount,%ariaRowIndex,%ariaRowSpan,%ariaSelected,%ariaSetSize,%ariaSort,%ariaValueMax,%ariaValueMin,%ariaValueNow,%ariaValueText,%classList,className,elementTiming,id,innerHTML,*beforecopy,*beforecut,*beforepaste,*fullscreenchange,*fullscreenerror,*search,*webkitfullscreenchange,*webkitfullscreenerror,outerHTML,%part,#scrollLeft,#scrollTop,slot' + /* added manually to avoid breaking changes */
18420',*message,*mozfullscreenchange,*mozfullscreenerror,*mozpointerlockchange,*mozpointerlockerror,*webglcontextcreationerror,*webglcontextlost,*webglcontextrestored', '[HTMLElement]^[Element]|accessKey,autocapitalize,!autofocus,contentEditable,dir,!draggable,enterKeyHint,!hidden,!inert,innerText,inputMode,lang,nonce,*abort,*animationend,*animationiteration,*animationstart,*auxclick,*beforexrselect,*blur,*cancel,*canplay,*canplaythrough,*change,*click,*close,*contextmenu,*copy,*cuechange,*cut,*dblclick,*drag,*dragend,*dragenter,*dragleave,*dragover,*dragstart,*drop,*durationchange,*emptied,*ended,*error,*focus,*formdata,*gotpointercapture,*input,*invalid,*keydown,*keypress,*keyup,*load,*loadeddata,*loadedmetadata,*loadstart,*lostpointercapture,*mousedown,*mouseenter,*mouseleave,*mousemove,*mouseout,*mouseover,*mouseup,*mousewheel,*paste,*pause,*play,*playing,*pointercancel,*pointerdown,*pointerenter,*pointerleave,*pointermove,*pointerout,*pointerover,*pointerrawupdate,*pointerup,*progress,*ratechange,*reset,*resize,*scroll,*securitypolicyviolation,*seeked,*seeking,*select,*selectionchange,*selectstart,*slotchange,*stalled,*submit,*suspend,*timeupdate,*toggle,*transitioncancel,*transitionend,*transitionrun,*transitionstart,*volumechange,*waiting,*webkitanimationend,*webkitanimationiteration,*webkitanimationstart,*webkittransitionend,*wheel,outerText,!spellcheck,%style,#tabIndex,title,!translate,virtualKeyboardPolicy', 'abbr,address,article,aside,b,bdi,bdo,cite,content,code,dd,dfn,dt,em,figcaption,figure,footer,header,hgroup,i,kbd,main,mark,nav,noscript,rb,rp,rt,rtc,ruby,s,samp,section,small,strong,sub,sup,u,var,wbr^[HTMLElement]|accessKey,autocapitalize,!autofocus,contentEditable,dir,!draggable,enterKeyHint,!hidden,innerText,inputMode,lang,nonce,*abort,*animationend,*animationiteration,*animationstart,*auxclick,*beforexrselect,*blur,*cancel,*canplay,*canplaythrough,*change,*click,*close,*contextmenu,*copy,*cuechange,*cut,*dblclick,*drag,*dragend,*dragenter,*dragleave,*dragover,*dragstart,*drop,*durationchange,*emptied,*ended,*error,*focus,*formdata,*gotpointercapture,*input,*invalid,*keydown,*keypress,*keyup,*load,*loadeddata,*loadedmetadata,*loadstart,*lostpointercapture,*mousedown,*mouseenter,*mouseleave,*mousemove,*mouseout,*mouseover,*mouseup,*mousewheel,*paste,*pause,*play,*playing,*pointercancel,*pointerdown,*pointerenter,*pointerleave,*pointermove,*pointerout,*pointerover,*pointerrawupdate,*pointerup,*progress,*ratechange,*reset,*resize,*scroll,*securitypolicyviolation,*seeked,*seeking,*select,*selectionchange,*selectstart,*slotchange,*stalled,*submit,*suspend,*timeupdate,*toggle,*transitioncancel,*transitionend,*transitionrun,*transitionstart,*volumechange,*waiting,*webkitanimationend,*webkitanimationiteration,*webkitanimationstart,*webkittransitionend,*wheel,outerText,!spellcheck,%style,#tabIndex,title,!translate,virtualKeyboardPolicy', 'media^[HTMLElement]|!autoplay,!controls,%controlsList,%crossOrigin,#currentTime,!defaultMuted,#defaultPlaybackRate,!disableRemotePlayback,!loop,!muted,*encrypted,*waitingforkey,#playbackRate,preload,!preservesPitch,src,%srcObject,#volume', ':svg:^[HTMLElement]|!autofocus,nonce,*abort,*animationend,*animationiteration,*animationstart,*auxclick,*beforexrselect,*blur,*cancel,*canplay,*canplaythrough,*change,*click,*close,*contextmenu,*copy,*cuechange,*cut,*dblclick,*drag,*dragend,*dragenter,*dragleave,*dragover,*dragstart,*drop,*durationchange,*emptied,*ended,*error,*focus,*formdata,*gotpointercapture,*input,*invalid,*keydown,*keypress,*keyup,*load,*loadeddata,*loadedmetadata,*loadstart,*lostpointercapture,*mousedown,*mouseenter,*mouseleave,*mousemove,*mouseout,*mouseover,*mouseup,*mousewheel,*paste,*pause,*play,*playing,*pointercancel,*pointerdown,*p
18420ointerenter,*pointerleave,*pointermove,*pointerout,*pointerover,*pointerrawupdate,*pointerup,*progress,*ratechange,*reset,*resize,*scroll,*securitypolicyviolation,*seeked,*seeking,*select,*selectionchange,*selectstart,*slotchange,*stalled,*submit,*suspend,*timeupdate,*toggle,*transitioncancel,*transitionend,*transitionrun,*transitionstart,*volumechange,*waiting,*webkitanimationend,*webkitanimationiteration,*webkitanimationstart,*webkittransitionend,*wheel,%style,#tabIndex', ':svg:graphics^:svg:|', ':svg:animation^:svg:|*begin,*end,*repeat', ':svg:geometry^:svg:|', ':svg:componentTransferFunction^:svg:|', ':svg:gradient^:svg:|', ':svg:textContent^:svg:graphics|', ':svg:textPositioning^:svg:textContent|', 'a^[HTMLElement]|charset,coords,download,hash,host,hostname,href,hreflang,name,password,pathname,ping,port,protocol,referrerPolicy,rel,%relList,rev,search,shape,target,text,type,username', 'area^[HTMLElement]|alt,coords,download,hash,host,hostname,href,!noHref,password,pathname,ping,port,protocol,referrerPolicy,rel,%relList,search,shape,target,username', 'audio^media|', 'br^[HTMLElement]|clear', 'base^[HTMLElement]|href,target', 'body^[HTMLElement]|aLink,background,bgColor,link,*afterprint,*beforeprint,*beforeunload,*blur,*error,*focus,*hashchange,*languagechange,*load,*message,*messageerror,*offline,*online,*pagehide,*pageshow,*popstate,*rejectionhandled,*resize,*scroll,*storage,*unhandledrejection,*unload,text,vLink', 'button^[HTMLElement]|!disabled,formAction,formEnctype,formMethod,!formNoValidate,formTarget,name,type,value', 'canvas^[HTMLElement]|#height,#width', 'content^[HTMLElement]|select', 'dl^[HTMLElement]|!compact', 'data^[HTMLElement]|value', 'datalist^[HTMLElement]|', 'details^[HTMLElement]|!open', 'dialog^[HTMLElement]|!open,returnValue', 'dir^[HTMLElement]|!compact', 'div^[HTMLElement]|align', 'embed^[HTMLElement]|align,height,name,src,type,width', 'fieldset^[HTMLElement]|!disabled,name', 'font^[HTMLElement]|color,face,size', 'form^[HTMLElement]|acceptCharset,action,autocomplete,encoding,enctype,method,name,!noValidate,target', 'frame^[HTMLElement]|frameBorder,longDesc,marginHeight,marginWidth,name,!noResize,scrolling,src', 'frameset^[HTMLElement]|cols,*afterprint,*beforeprint,*beforeunload,*blur,*error,*focus,*hashchange,*languagechange,*load,*message,*messageerror,*offline,*online,*pagehide,*pageshow,*popstate,*rejectionhandled,*resize,*scroll,*storage,*unhandledrejection,*unload,rows', 'hr^[HTMLElement]|align,color,!noShade,size,width', 'head^[HTMLElement]|', 'h1,h2,h3,h4,h5,h6^[HTMLElement]|align', 'html^[HTMLElement]|version', 'iframe^[HTMLElement]|align,allow,!allowFullscreen,!allowPaymentRequest,csp,frameBorder,height,loading,longDesc,marginHeight,marginWidth,name,referrerPolicy,%sandbox,scrolling,src,srcdoc,width', 'img^[HTMLElement]|align,alt,border,%crossOrigin,decoding,#height,#hspace,!isMap,loading,longDesc,lowsrc,name,referrerPolicy,sizes,src,srcset,useMap,#vspace,#width', 'input^[HTMLElement]|accept,align,alt,autocomplete,!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', 'li^[HTMLElement]|type,#value', 'label^[HTMLElement]|htmlFor', 'legend^[HTMLElement]|align', 'link^[HTMLElement]|as,charset,%crossOrigin,!disabled,href,hreflang,imageSizes,imageSrcset,integrity,media,referrerPolicy,rel,%relList,rev,%sizes,target,type', 'map^[HTMLElement]|name', 'marquee^[HTMLElement]|behavior,bgColor,direction,height,#hspace,#loop,#scrollAmount,#scrollDelay,!trueSpeed,#vspace,width', 'menu^[HTMLElement]|!compact', 'meta^[HTMLElement]|content,httpEquiv,media,name,scheme', 'meter^[HTMLElement]|#high,#low,#max,#min,#optimum,#value', 'ins,del^[HTMLElement]|cite,dateTime', 'ol^[HTMLElement]|!compact,!reversed,#start,type', 'object^[HTMLElement]|align,archive,border,code,codeBase,codeType,data,!declare,height,#hspace,name,standby,type,useMap,#vspace,width', 'optgroup^[HTMLElement]|!disabled,label', 'option^[HTMLElement]|!defaultSelected,!disabled,label,!selected,text,value', 'output^[HTMLElement]|defaultValue,%htmlFor,name,value', 'p^[HTMLElement]|align', 'param^[HTMLElement]|name,type,value,valueType', 'picture^[HTMLElement]|', 'pre^[HTMLElement]|#width', 'progress^[HTMLElement]|#max,#value', 'q,blockquote,cite^[HTMLElement]|', 'script^[HTMLElement]|!async,charset,%crossOrigin,!defer,event,htmlFor,integrity,!noModule,%referrerPolicy,src,text,type', 'select^[HTMLElement]|autocomplete,!disabled,#length,!multiple,name,!required,#selectedIndex,#size,value', 'slot^[HTMLElement]|name', 'source^[HTMLElement]|#height,media,sizes,src,srcset,type,#width', 'span^[HTMLElement]|', 'style^[HTMLElement]|!disabled,media,type', 'caption^[HTMLElement]|align', 'th,td^[HTMLElement]|abbr,align,axis,bgColor,ch,chOff,#colSpan,headers,height,!noWrap,#rowSpan,scope,vAlign,width', 'col,colgroup^[HTMLElement]|align,ch,chOff,#span,vAlign,width', 'table^[HTMLElement]|align,bgColor,border,%caption,cellPadding,cellSpacing,frame,rules,summary,%tFoot,%tHead,width', 'tr^[HTMLElement]|align,bgColor,ch,chOff,vAlign', 'tfoot,thead,tbody^[HTMLElement]|align,ch,chOff,vAlign', 'template^[HTMLElement]|', 'textarea^[HTMLElement]|autocomplete,#cols,defaultValue,dirName,!disabled,#maxLength,#minLength,name,placeholder,!readOnly,!required,#rows,selectionDirection,#selectionEnd,#selectionStart,value,wrap', 'time^[HTMLElement]|dateTime', 'title^[HTMLElement]|text', 'track^[HTMLElement]|!default,kind,label,src,srclang', 'ul^[HTMLElement]|!compact,type', 'unknown^[HTMLElement]|', 'video^media|!disablePictureInPicture,#height,*enterpictureinpicture,*leavepictureinpicture,!playsInline,poster,#width', ':svg:a^:svg:graphics|', ':svg:animate^:svg:animation|', ':svg:animateMotion^:svg:animation|', ':svg:animateTransform^:svg:animation|', ':svg:circle^:svg:geometry|', ':svg:clipPath^:svg:graphics|', ':svg:defs^:svg:graphics|', ':svg:desc^:svg:|', ':svg:discard^:svg:|', ':svg:ellipse^:svg:geometry|', ':svg:feBlend^:svg:|', ':svg:feColorMatrix^:svg:|', ':svg:feComponentTransfer^:svg:|', ':svg:feComposite^:svg:|', ':svg:feConvolveMatrix^:svg:|', ':svg:feDiffuseLighting^:svg:|', ':svg:feDisplacementMap^:svg:|', ':svg:feDistantLight^:svg:|', ':svg:feDropShadow^:svg:|', ':svg:feFlood^:svg:|', ':svg:feFuncA^:svg:componentTransferFunction|', ':svg:feFuncB^:svg:componentTransferFunction|', ':svg:feFuncG^:svg:componentTransferFunction|', ':svg:feFuncR^:svg:componentTransferFunction|', ':svg:feGaussianBlur^:svg:|', ':svg:feImage^:svg:|', ':svg:feMerge^:svg:|', ':svg:feMergeNode^:svg:|', ':svg:feMorphology^:svg:|', ':svg:feOffset^:svg:|', ':svg:fePointLight^:svg:|', ':svg:feSpecularLighting^:svg:|', ':svg:feSpotLight^:svg:|', ':svg:feTile^:svg:|', ':svg:feTurbulence^:svg:|', ':svg:filter^:svg:|', ':svg:foreignObject^:svg:graphics|', ':svg:g^:svg:graphics|', ':svg:image^:svg:graphics|decoding', ':svg:line^:svg:geometry|', ':svg:linearGradient^:svg:gradient|', ':svg:mpath^:svg:|', ':svg:marker^:svg:|', ':svg:mask^:svg:|', ':svg:metadata^:svg:|', ':svg:path^:svg:geometry|', ':svg:pattern^:svg:|', ':svg:polygon^:svg:geometry|', ':svg:polyline^:svg:geometry|', ':svg:radialGradient^:svg:gradient|', ':svg:rect^:svg:geometry|', ':svg:svg^:svg:graphics|#currentScale,#zoomAndPan', ':svg:script^:svg:|type', ':svg:set^:svg:animation|', ':svg:stop^:svg:|', ':svg:style^:svg:|!disabled,media,title,type', ':svg:switch^:svg:graphics|', ':svg:symbol^:svg:|', ':svg:tspan^:svg:textPositioning|', ':svg:text^:svg:textPositioning|', ':svg:textPath^:svg:textContent|', ':svg:title^:svg:|', ':svg:use^:svg:graphics|', ':svg:view^:svg:|#zoomAndPan', 'data^[HTMLElement]|value', 'keygen^[HTMLElement]|!autofocus,challenge,!disabled,form,keytype,name', 'menuitem^[HTMLElement]|type,label,icon,!disabled,!checked,radiogroup,!default', 'summary^[HTMLElement]|', 'time^[HTMLElement]|dateTime', ':svg:cursor^:svg:|', ':math:^[HTMLElement]|!autofocus,nonce,*abort,*animationend,*animationiteration,*animationstart,*auxcl
18420ick,*beforeinput,*beforematch,*beforetoggle,*beforexrselect,*blur,*cancel,*canplay,*canplaythrough,*change,*click,*close,*contentvisibilityautostatechange,*contextlost,*contextmenu,*contextrestored,*copy,*cuechange,*cut,*dblclick,*drag,*dragend,*dragenter,*dragleave,*dragover,*dragstart,*drop,*durationchange,*emptied,*ended,*error,*focus,*formdata,*gotpointercapture,*input,*invalid,*keydown,*keypress,*keyup,*load,*loadeddata,*loadedmetadata,*loadstart,*lostpointercapture,*mousedown,*mouseenter,*mouseleave,*mousemove,*mouseout,*mouseover,*mouseup,*mousewheel,*paste,*pause,*play,*playing,*pointercancel,*pointerdown,*pointerenter,*pointerleave,*pointermove,*pointerout,*pointerover,*pointerrawupdate,*pointerup,*progress,*ratechange,*reset,*resize,*scroll,*scrollend,*securitypolicyviolation,*seeked,*seeking,*select,*selectionchange,*selectstart,*slotchange,*stalled,*submit,*suspend,*timeupdate,*toggle,*transitioncancel,*transitionend,*transitionrun,*transitionstart,*volumechange,*waiting,*webkitanimationend,*webkitanimationiteration,*webkitanimationstart,*webkittransitionend,*wheel,%style,#tabIndex', ':math:math^:math:|', ':math:maction^:math:|', ':math:menclose^:math:|', ':math:merror^:math:|', ':math:mfenced^:math:|', ':math:mfrac^:math:|', ':math:mi^:math:|', ':math:mmultiscripts^:math:|', ':math:mn^:math:|', ':math:mo^:math:|', ':math:mover^:math:|', ':math:mpadded^:math:|', ':math:mphantom^:math:|', ':math:mroot^:math:|', ':math:mrow^:math:|', ':math:ms^
18420:math:|', ':math:mspace^:math:|', ':math:msqrt^:math:|', ':math:mstyle^:math:|', ':math:msub^:math:|', ':math:msubsup^:math:|', ':math:msup^:math:|', ':math:mtable^:math:|', ':math:mtd^:math:|', ':math:mtext^:math:|', ':math:mtr^:math:|', ':math:munder^:math:|', ':math:munderover^:math:|', ':math:semantics^:math:|'];
18421const _ATTR_TO_PROP = new Map(Object.entries({
18422  'class': 'className',
18423  'for': 'htmlFor',
18424  'formaction': 'formAction',
18425  'innerHtml': 'innerHTML',
18426  'readonly': 'readOnly',
18427  'tabindex': 'tabIndex'
18428}));
18429// Invert _ATTR_TO_PROP.
18430const _PROP_TO_ATTR = Array.from(_ATTR_TO_PROP).reduce((inverted, [propertyName, attributeName]) => {
18431  inverted.set(propertyName, attributeName);
18432  return inverted;
18433}, new Map());
18434class DomElementSchemaRegistry extends ElementSchemaRegistry {
18435  constructor() {
18436    super();
18437    this._schema = new Map();
18438    // We don't allow binding to events for security reasons. Allowing event bindings would almost
18439    // certainly introduce bad XSS vulnerabilities. Instead, we store events in a separate schema.
18440    this._eventSchema = new Map();
18441    SCHEMA.forEach(encodedType => {
18442      const type = new Map();
18443      const events = new Set();
18444      const [strType, strProperties] = encodedType.split('|');
18445      const properties = strProperties.split(',');
18446      const [typeNames, superName] = strType.split('^');
18447      typeNames.split(',').forEach(tag => {
18448        this._schema.set(tag.toLowerCase(), type);
18449        this._eventSchema.set(tag.toLowerCase(), events);
18450      });
18451      const superType = superName && this._schema.get(superName.toLowerCase());
18452      if (superType) {
18453        for (const [prop, value] of superType) {
18454          type.set(prop, value);
18455        }
18456        for (const superEvent of this._eventSchema.get(superName.toLowerCase())) {
18457          events.add(superEvent);
18458        }
18459      }
18460      properties.forEach(property => {
18461        if (property.length > 0) {
18462          switch (property[0]) {
18463            case '*':
18464              events.add(property.substring(1));
18465              break;
18466            case '!':
18467              type.set(property.substring(1), BOOLEAN);
18468              break;
18469            case '#':
18470              type.set(property.substring(1), NUMBER);
18471              break;
18472            case '%':
18473              type.set(property.substring(1), OBJECT);
18474              break;
18475            default:
18476              type.set(property, STRING);
18477          }
18478        }
18479      });
18480    });
18481  }
18482  hasProperty(tagName, propName, schemaMetas) {
18483    if (schemaMetas.some(schema => schema.name === NO_ERRORS_SCHEMA.name)) {
18484      return true;
18485    }
18486    if (tagName.indexOf('-') > -1) {
18487      if (isNgContainer(tagName) || isNgContent(tagName)) {
18488        return false;
18489      }
18490      if (schemaMetas.some(schema => schema.name === CUSTOM_ELEMENTS_SCHEMA.name)) {
18491        // Can't tell now as we don't know which properties a custom element will get
18492        // once it is instantiated
18493        return true;
18494      }
18495    }
18496    const elementProperties = this._schema.get(tagName.toLowerCase()) || this._schema.get('unknown');
18497    return elementProperties.has(propName);
18498  }
18499  hasElement(tagName, schemaMetas) {
18500    if (schemaMetas.some(schema => schema.name === NO_ERRORS_SCHEMA.name)) {
18501      return true;
18502    }
18503    if (tagName.indexOf('-') > -1) {
18504      if (isNgContainer(tagName) || isNgContent(tagName)) {
18505        return true;
18506      }
18507      if (schemaMetas.some(schema => schema.name === CUSTOM_ELEMENTS_SCHEMA.name)) {
18508        // Allow any custom elements
18509        return true;
18510      }
18511    }
18512    return this._schema.has(tagName.toLowerCase());
18513  }
18514  /**
18515   * securityContext returns the security context for the given property on the given DOM tag.
18516   *
18517   * Tag and property name are statically known and cannot change at runtime, i.e. it is not
18518   * possible to bind a value into a changing attribute or tag name.
18519   *
18520   * The filtering is based on a list of allowed tags|attributes. All attributes in the schema
18521   * above are assumed to have the 'NONE' security context, i.e. that they are safe inert
18522   * string values. Only specific well known attack vectors are assigned their appropriate context.
18523   */
18524  securityContext(tagName, propName, isAttribute) {
18525    if (isAttribute) {
18526      // NB: For security purposes, use the mapped property name, not the attribute name.
18527      propName = this.getMappedPropName(propName);
18528    }
18529    // Make sure comparisons are case insensitive, so that case differences between attribute and
18530    // property names do not have a security impact.
18531    tagName = tagName.toLowerCase();
18532    propName = propName.toLowerCase();
18533    let ctx = SECURITY_SCHEMA()[tagName + '|' + propName];
18534    if (ctx) {
18535      return ctx;
18536    }
18537    ctx = SECURITY_SCHEMA()['*|' + propName];
18538    return ctx ? ctx : SecurityContext.NONE;
18539  }
18540  getMappedPropName(propName) {
18541    return _ATTR_TO_PROP.get(propName) ?? propName;
18542  }
18543  getDefaultComponentElementName() {
18544    return 'ng-component';
18545  }
18546  validateProperty(name) {
18547    if (name.toLowerCase().startsWith('on')) {
18548      const msg = `Binding to event property '${name}' is disallowed for security reasons, ` + `please use (${name.slice(2)})=...` + `\nIf '${name}' is a directive input, make sure the directive is imported by the` + ` current module.`;
18549      return {
18550        error: true,
18551        msg: msg
18552      };
18553    } else {
18554      return {
18555        error: false
18556      };
18557    }
18558  }
18559  validateAttribute(name) {
18560    if (name.toLowerCase().startsWith('on')) {
18561      const msg = `Binding to event attribute '${name}' is disallowed for security reasons, ` + `please use (${name.slice(2)})=...`;
18562      return {
18563        error: true,
18564        msg: msg
18565      };
18566    } else {
18567      return {
18568        error: false
18569      };
18570    }
18571  }
18572  allKnownElementNames() {
18573    return Array.from(this._schema.keys());
18574  }
18575  allKnownAttributesOfElement(tagName) {
18576    const elementProperties = this._schema.get(tagName.toLowerCase()) || this._schema.get('unknown');
18577    // Convert properties to attributes.
18578    return Array.from(elementProperties.keys()).map(prop => _PROP_TO_ATTR.get(prop) ?? prop);
18579  }
18580  allKnownEventsOfElement(tagName) {
18581    return Array.from(this._eventSchema.get(tagName.toLowerCase()) ?? []);
18582  }
18583  normalizeAnimationStyleProperty(propName) {
18584    return dashCaseToCamelCase(propName);
18585  }
18586  normalizeAnimationStyleValue(camelCaseProp, userProvidedProp, val) {
18587    let unit = '';
18588    const strVal = val.toString().trim();
18589    let errorMsg = null;
18590    if (_isPixelDimensionStyle(camelCaseProp) && val !== 0 && val !== '0') {
18591      if (typeof val === 'number') {
18592        unit = 'px';
18593      } else {
18594        const valAndSuffixMatch = val.match(/^[+-]?[\d\.]+([a-z]*)$/);
18595        if (valAndSuffixMatch && valAndSuffixMatch[1].length == 0) {
18596          errorMsg = `Please provide a CSS unit value for ${userProvidedProp}:${val}`;
18597        }
18598      }
18599    }
18600    return {
18601      error: errorMsg,
18602      value: strVal + unit
18603    };
18604  }
18605}
18606function _isPixelDimensionStyle(prop) {
18607  switch (prop) {
18608    case 'width':
18609    case 'height':
18610    case 'minWidth':
18611    case 'minHeight':
18612    case 'maxWidth':
18613    case 'maxHeight':
18614    case 'left':
18615    case 'top':
18616    case 'bottom':
18617    case 'right':
18618    case 'fontSize':
18619    case 'outlineWidth':
18620    case 'outlineOffset':
18621    case 'paddingTop':
18622    case 'paddingLeft':
18623    case 'paddingBottom':
18624    case 'paddingRight':
18625    case 'marginTop':
18626    case 'marginLeft':
18627    case 'marginBottom':
18628    case 'marginRight':
18629    case 'borderRadius':
18630    case 'borderWidth':
18631    case 'borderTopWidth':
18632    case 'borderLeftWidth':
18633    case 'borderRightWidth':
18634    case 'borderBottomWidth':
18635    case 'textIndent':
18636      return true;
18637    default:
18638      return false;
18639  }
18640}
18641class HtmlTagDefinition {
18642  constructor({
18643    closedByChildren,
18644    implicitNamespacePrefix,
18645    contentType = TagContentType.PARSABLE_DATA,
18646    closedByParent = false,
18647    isVoid = false,
18648    ignoreFirstLf = false,
18649    preventNamespaceInheritance = false,
18650    canSelfClose = false
18651  } = {}) {
18652    this.closedByChildren = {};
18653    this.closedByParent = false;
18654    if (closedByChildren && closedByChildren.length > 0) {
18655      closedByChildren.forEach(tagName => this.closedByChildren[tagName] = true);
18656    }
18657    this.isVoid = isVoid;
18658    this.closedByParent = closedByParent || isVoid;
18659    this.implicitNamespacePrefix = implicitNamespacePrefix || null;
18660    this.contentType = contentType;
18661    this.ignoreFirstLf = ignoreFirstLf;
18662    this.preventNamespaceInheritance = preventNamespaceInheritance;
18663    this.canSelfClose = canSelfClose ?? isVoid;
18664  }
18665  isClosedByChild(name) {
18666    return this.isVoid || name.toLowerCase() in this.closedByChildren;
18667  }
18668  getContentType(prefix) {
18669    if (typeof this.contentType === 'object') {
18670      const overrideType = prefix === undefined ? undefined : this.contentType[prefix];
18671      return overrideType ?? this.contentType.default;
18672    }
18673    return this.contentType;
18674  }
18675}
18676let DEFAULT_TAG_DEFINITION;
18677// see https://www.w3.org/TR/html51/syntax.html#optional-tags
18678// This implementation does not fully conform to the HTML5 spec.
18679let TAG_DEFINITIONS;
18680function getHtmlTagDefinition(tagName) {
18681  if (!TAG_DEFINITIONS) {
18682    DEFAULT_TAG_DEFINITION = new HtmlTagDefinition({
18683      canSelfClose: true
18684    });
18685    TAG_DEFINITIONS = Object.assign(Object.create(null), {
18686      'base': new HtmlTagDefinition({
18687        isVoid: true
18688      }),
18689      'meta': new HtmlTagDefinition({
18690        isVoid: true
18691      }),
18692      'area': new HtmlTagDefinition({
18693        isVoid: true
18694      }),
18695      'embed': new HtmlTagDefinition({
18696        isVoid: true
18697      }),
18698      'link': new HtmlTagDefinition({
18699        isVoid: true
18700      }),
18701      'img': new HtmlTagDefinition({
18702        isVoid: true
18703      }),
18704      'input': new HtmlTagDefinition({
18705        isVoid: true
18706      }),
18707      'param': new HtmlTagDefinition({
18708        isVoid: true
18709      }),
18710      'hr': new HtmlTagDefinition({
18711        isVoid: true
18712      }),
18713      'br': new HtmlTagDefinition({
18714        isVoid: true
18715      }),
18716      'source': new HtmlTagDefinition({
18717        isVoid: true
18718      }),
18719      'track': new HtmlTagDefinition({
18720        isVoid: true
18721      }),
18722      'wbr': new HtmlTagDefinition({
18723        isVoid: true
18724      }),
18725      'p': new HtmlTagDefinition({
18726        closedByChildren: ['address', 'article', 'aside', 'blockquote', 'div', 'dl', 'fieldset', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'header', 'hgroup', 'hr', 'main', 'nav', 'ol', 'p', 'pre', 'section', 'table', 'ul'],
18727        closedByParent: true
18728      }),
18729      'thead': new HtmlTagDefinition({
18730        closedByChildren: ['tbody', 'tfoot']
18731      }),
18732      'tbody': new HtmlTagDefinition({
18733        closedByChildren: ['tbody', 'tfoot'],
18734        closedByParent: true
18735      }),
18736      'tfoot': new HtmlTagDefinition({
18737        closedByChildren: ['tbody'],
18738        closedByParent: true
18739      }),
18740      'tr': new HtmlTagDefinition({
18741        closedByChildren: ['tr'],
18742        closedByParent: true
18743      }),
18744      'td': new HtmlTagDefinition({
18745        closedByChildren: ['td', 'th'],
18746        closedByParent: true
18747      }),
18748      'th': new HtmlTagDefinition({
18749        closedByChildren: ['td', 'th'],
18750        closedByParent: true
18751      }),
18752      'col': new HtmlTagDefinition({
18753        isVoid: true
18754      }),
18755      'svg': new HtmlTagDefinition({
18756        implicitNamespacePrefix: 'svg'
18757      }),
18758      'foreignObject': new HtmlTagDefinition({
18759        // Usually the implicit namespace here would be redundant since it will be inherited from
18760        // the parent `svg`, but we have to do it for `foreignObject`, because the way the parser
18761        // works is that the parent node of an end tag is its own start tag which means that
18762        // the `preventNamespaceInheritance` on `foreignObject` would have it default to the
18763        // implicit namespace which is `html`, unless specified otherwise.
18764        implicitNamespacePrefix: 'svg',
18765        // We want to prevent children of foreignObject from inheriting its namespace, because
18766        // the point of the element is to allow nodes from other namespaces to be inserted.
18767        preventNamespaceInheritance: true
18768      }),
18769      'math': new HtmlTagDefinition({
18770        implicitNamespacePrefix: 'math'
18771      }),
18772      'li': new HtmlTagDefinition({
18773        closedByChildren: ['li'],
18774        closedByParent: true
18775      }),
18776      'dt': new HtmlTagDefinition({
18777        closedByChildren: ['dt', 'dd']
18778      }),
18779      'dd': new HtmlTagDefinition({
18780        closedByChildren: ['dt', 'dd'],
18781        closedByParent: true
18782      }),
18783      'rb': new HtmlTagDefinition({
18784        closedByChildren: ['rb', 'rt', 'rtc', 'rp'],
18785        closedByParent: true
18786      }),
18787      'rt': new HtmlTagDefinition({
18788        closedByChildren: ['rb', 'rt', 'rtc', 'rp'],
18789        closedByParent: true
18790      }),
18791      'rtc': new HtmlTagDefinition({
18792        closedByChildren: ['rb', 'rtc', 'rp'],
18793        closedByParent: true
18794      }),
18795      'rp': new HtmlTagDefinition({
18796        closedByChildren: ['rb', 'rt', 'rtc', 'rp'],
18797        closedByParent: true
18798      }),
18799      'optgroup': new HtmlTagDefinition({
18800        closedByChildren: ['optgroup'],
18801        closedByParent: true
18802      }),
18803      'option': new HtmlTagDefinition({
18804        closedByChildren: ['option', 'optgroup'],
18805        closedByParent: true
18806      }),
18807      'pre': new HtmlTagDefinition({
18808        ignoreFirstLf: true
18809      }),
18810      'listing': new HtmlTagDefinition({
18811        ignoreFirstLf: true
18812      }),
18813      'style': new HtmlTagDefinition({
18814        contentType: TagContentType.RAW_TEXT
18815      }),
18816      'script': new HtmlTagDefinition({
18817        contentType: TagContentType.RAW_TEXT
18818      }),
18819      'title': new HtmlTagDefinition({
18820        // The browser supports two separate `title` tags which have to use
18821        // a different content type: `HTMLTitleElement` and `SVGTitleElement`
18822        contentType: {
18823          default: TagContentType.ESCAPABLE_RAW_TEXT,
18824          svg: TagContentType.PARSABLE_DATA
18825        }
18826      }),
18827      'textarea': new HtmlTagDefinition({
18828        contentType: TagContentType.ESCAPABLE_RAW_TEXT,
18829        ignoreFirstLf: true
18830      })
18831    });
18832    new DomElementSchemaRegistry().allKnownElementNames().forEach(knownTagName => {
18833      if (!TAG_DEFINITIONS[knownTagName] && getNsPrefix(knownTagName) === null) {
18834        TAG_DEFINITIONS[knownTagName] = new HtmlTagDefinition({
18835          canSelfClose: false
18836        });
18837      }
18838    });
18839  }
18840  // We have to make both a case-sensitive and a case-insensitive lookup, because
18841  // HTML tag names are case insensitive, whereas some SVG tags are case sensitive.
18842  return TAG_DEFINITIONS[tagName] ?? TAG_DEFINITIONS[tagName.toLowerCase()] ?? DEFAULT_TAG_DEFINITION;
18843}
18844const TAG_TO_PLACEHOLDER_NAMES = {
18845  'A': 'LINK',
18846  'B': 'BOLD_TEXT',
18847  'BR': 'LINE_BREAK',
18848  'EM': 'EMPHASISED_TEXT',
18849  'H1': 'HEADING_LEVEL1',
18850  'H2': 'HEADING_LEVEL2',
18851  'H3': 'HEADING_LEVEL3',
18852  'H4': 'HEADING_LEVEL4',
18853  'H5': 'HEADING_LEVEL5',
18854  'H6': 'HEADING_LEVEL6',
18855  'HR': 'HORIZONTAL_RULE',
18856  'I': 'ITALIC_TEXT',
18857  'LI': 'LIST_ITEM',
18858  'LINK': 'MEDIA_LINK',
18859  'OL': 'ORDERED_LIST',
18860  'P': 'PARAGRAPH',
18861  'Q': 'QUOTATION',
18862  'S': 'STRIKETHROUGH_TEXT',
18863  'SMALL': 'SMALL_TEXT',
18864  'SUB': 'SUBSTRIPT',
18865  'SUP': 'SUPERSCRIPT',
18866  'TBODY': 'TABLE_BODY',
18867  'TD': 'TABLE_CELL',
18868  'TFOOT': 'TABLE_FOOTER',
18869  'TH': 'TABLE_HEADER_CELL',
18870  'THEAD': 'TABLE_HEADER',
18871  'TR': 'TABLE_ROW',
18872  'TT': 'MONOSPACED_TEXT',
18873  'U': 'UNDERLINED_TEXT',
18874  'UL': 'UNORDERED_LIST'
18875};
18876/**
18877 * Creates unique names for placeholder with different content.
18878 *
18879 * Returns the same placeholder name when the content is identical.
18880 */
18881class PlaceholderRegistry {
18882  constructor() {
18883    // Count the occurrence of the base name top generate a unique name
18884    this._placeHolderNameCounts = {};
18885    // Maps signature to placeholder names
18886    this._signatureToName = {};
18887  }
18888  getStartTagPlaceholderName(tag, attrs, isVoid) {
18889    const signature = this._hashTag(tag, attrs, isVoid);
18890    if (this._signatureToName[signature]) {
18891      return this._signatureToName[signature];
18892    }
18893    const upperTag = tag.toUpperCase();
18894    const baseName = TAG_TO_PLACEHOLDER_NAMES[upperTag] || `TAG_${upperTag}`;
18895    const name = this._generateUniqueName(isVoid ? baseName : `START_${baseName}`);
18896    this._signatureToName[signature] = name;
18897    return name;
18898  }
18899  getCloseTagPlaceholderName(tag) {
18900    const signature = this._hashClosingTag(tag);
18901    if (this._signatureToName[signature]) {
18902      return this._signatureToName[signature];
18903    }
18904    const upperTag = tag.toUpperCase();
18905    const baseName = TAG_TO_PLACEHOLDER_NAMES[upperTag] || `TAG_${upperTag}`;
18906    const name = this._generateUniqueName(`CLOSE_${baseName}`);
18907    this._signatureToName[signature] = name;
18908    return name;
18909  }
18910  getPlaceholderName(name, content) {
18911    const upperName = name.toUpperCase();
18912    const signature = `PH: ${upperName}=${content}`;
18913    if (this._signatureToName[signature]) {
18914      return this._signatureToName[signature];
18915    }
18916    const uniqueName = this._generateUniqueName(upperName);
18917    this._signatureToName[signature] = uniqueName;
18918    return uniqueName;
18919  }
18920  getUniquePlaceholder(name) {
18921    return this._generateUniqueName(name.toUpperCase());
18922  }
18923  getStartBlockPlaceholderName(name, parameters) {
18924    const signature = this._hashBlock(name, parameters);
18925    if (this._signatureToName[signature]) {
18926      return this._signatureToName[signature];
18927    }
18928    const placeholder = this._generateUniqueName(`START_BLOCK_${this._toSnakeCase(name)}`);
18929    this._signatureToName[signature] = placeholder;
18930    return placeholder;
18931  }
18932  getCloseBlockPlaceholderName(name) {
18933    const signature = this._hashClosingBlock(name);
18934    if (this._signatureToName[signature]) {
18935      return this._signatureToName[signature];
18936    }
18937    const placeholder = this._generateUniqueName(`CLOSE_BLOCK_${this._toSnakeCase(name)}`);
18938    this._signatureToName[signature] = placeholder;
18939    return placeholder;
18940  }
18941  // Generate a hash for a tag - does not take attribute order into account
18942  _hashTag(tag, attrs, isVoid) {
18943    const start = `<${tag}`;
18944    const strAttrs = Object.keys(attrs).sort().map(name => ` ${name}=${attrs[name]}`).join('');
18945    const end = isVoid ? '/>' : `></${tag}>`;
18946    return start + strAttrs + end;
18947  }
18948  _hashClosingTag(tag) {
18949    return this._hashTag(`/${tag}`, {}, false);
18950  }
18951  _hashBlock(name, parameters) {
18952    const params = parameters.length === 0 ? '' : ` (${parameters.sort().join('; ')})`;
18953    return `@${name}${params} {}`;
18954  }
18955  _hashClosingBlock(name) {
18956    return this._hashBlock(`close_${name}`, []);
18957  }
18958  _toSnakeCase(name) {
18959    return name.toUpperCase().replace(/[^A-Z0-9]/g, '_');
18960  }
18961  _generateUniqueName(base) {
18962    const seen = this._placeHolderNameCounts.hasOwnProperty(base);
18963    if (!seen) {
18964      this._placeHolderNameCounts[base] = 1;
18965      return base;
18966    }
18967    const id = this._placeHolderNameCounts[base];
18968    this._placeHolderNameCounts[base] = id + 1;
18969    return `${base}_${id}`;
18970  }
18971}
18972const _expParser = new Parser$1(new Lexer());
18973/**
18974 * Returns a function converting html nodes to an i18n Message given an interpolationConfig
18975 */
18976function createI18nMessageFactory(interpolationConfig, containerBlocks) {
18977  const visitor = new _I18nVisitor(_expParser, interpolationConfig, containerBlocks);
18978  return (nodes, meaning, description, customId, visitNodeFn) => visitor.toI18nMessage(nodes, meaning, description, customId, visitNodeFn);
18979}
18980function noopVisitNodeFn(_html, i18n) {
18981  return i18n;
18982}
18983class _I18nVisitor {
18984  constructor(_expressionParser, _interpolationConfig, _containerBlocks) {
18985    this._expressionParser = _expressionParser;
18986    this._interpolationConfig = _interpolationConfig;
18987    this._containerBlocks = _containerBlocks;
18988  }
18989  toI18nMessage(nodes, meaning = '', description = '', customId = '', visitNodeFn) {
18990    const context = {
18991      isIcu: nodes.length == 1 && nodes[0] instanceof Expansion,
18992      icuDepth: 0,
18993      placeholderRegistry: new PlaceholderRegistry(),
18994      placeholderToContent: {},
18995      placeholderToMessage: {},
18996      visitNodeFn: visitNodeFn || noopVisitNodeFn
18997    };
18998    const i18nodes = visitAll(this, nodes, context);
18999    return new Message(i18nodes, context.placeholderToContent, context.placeholderToMessage, meaning, description, customId);
19000  }
19001  visitElement(el, context) {
19002    const children = visitAll(this, el.children, context);
19003    const attrs = {};
19004    el.attrs.forEach(attr => {
19005      // Do not visit the attributes, translatable ones are top-level ASTs
19006      attrs[attr.name] = attr.value;
19007    });
19008    const isVoid = getHtmlTagDefinition(el.name).isVoid;
19009    const startPhName = context.placeholderRegistry.getStartTagPlaceholderName(el.name, attrs, isVoid);
19010    context.placeholderToContent[startPhName] = {
19011      text: el.startSourceSpan.toString(),
19012      sourceSpan: el.startSourceSpan
19013    };
19014    let closePhName = '';
19015    if (!isVoid) {
19016      closePhName = context.placeholderRegistry.getCloseTagPlaceholderName(el.name);
19017      context.placeholderToContent[closePhName] = {
19018        text: `</${el.name}>`,
19019        sourceSpan: el.endSourceSpan ?? el.sourceSpan
19020      };
19021    }
19022    const node = new TagPlaceholder(el.name, attrs, startPhName, closePhName, children, isVoid, el.sourceSpan, el.startSourceSpan, el.endSourceSpan);
19023    return context.visitNodeFn(el, node);
19024  }
19025  visitAttribute(attribute, context) {
19026    const node = attribute.valueTokens === undefined || attribute.valueTokens.length === 1 ? new Text$2(attribute.value, attribute.valueSpan || attribute.sourceSpan) : this._visitTextWithInterpolation(attribute.valueTokens, attribute.valueSpan || attribute.sourceSpan, context, attribute.i18n);
19027    return context.visitNodeFn(attribute, node);
19028  }
19029  visitText(text, context) {
19030    const node = text.tokens.length === 1 ? new Text$2(text.value, text.sourceSpan) : this._visitTextWithInterpolation(text.tokens, text.sourceSpan, context, text.i18n);
19031    return context.visitNodeFn(text, node);
19032  }
19033  visitComment(comment, context) {
19034    return null;
19035  }
19036  visitExpansion(icu, context) {
19037    context.icuDepth++;
19038    const i18nIcuCases = {};
19039    const i18nIcu = new Icu(icu.switchValue, icu.type, i18nIcuCases, icu.sourceSpan);
19040    icu.cases.forEach(caze => {
19041      i18nIcuCases[caze.value] = new Container(caze.expression.map(node => node.visit(this, context)), caze.expSourceSpan);
19042    });
19043    context.icuDepth--;
19044    if (context.isIcu || context.icuDepth > 0) {
19045      // Returns an ICU node when:
19046      // - the message (vs a part of the message) is an ICU message, or
19047      // - the ICU message is nested.
19048      const expPh = context.placeholderRegistry.getUniquePlaceholder(`VAR_${icu.type}`);
19049      i18nIcu.expressionPlaceholder = expPh;
19050      context.placeholderToContent[expPh] = {
19051        text: icu.switchValue,
19052        sourceSpan: icu.switchValueSourceSpan
19053      };
19054      return context.visitNodeFn(icu, i18nIcu);
19055    }
19056    // Else returns a placeholder
19057    // ICU placeholders should not be replaced with their original content but with the their
19058    // translations.
19059    // TODO(vicb): add a html.Node -> i18n.Message cache to avoid having to re-create the msg
19060    const phName = context.placeholderRegistry.getPlaceholderName('ICU', icu.sourceSpan.toString());
19061    context.placeholderToMessage[phName] = this.toI18nMessage([icu], '', '', '', undefined);
19062    const node = new IcuPlaceholder(i18nIcu, phName, icu.sourceSpan);
19063    return context.visitNodeFn(icu, node);
19064  }
19065  visitExpansionCase(_icuCase, _context) {
19066    throw new Error('Unreachable code');
19067  }
19068  visitBlock(block, context) {
19069    const children = visitAll(this, block.children, context);
19070    if (this._containerBlocks.has(block.name)) {
19071      return new Container(children, block.sourceSpan);
19072    }
19073    const parameters = block.parameters.map(param => param.expression);
19074    const startPhName = context.placeholderRegistry.getStartBlockPlaceholderName(block.name, parameters);
19075    const closePhName = context.placeholderRegistry.getCloseBlockPlaceholderName(block.name);
19076    context.placeholderToContent[startPhName] = {
19077      text: block.startSourceSpan.toString(),
19078      sourceSpan: block.startSourceSpan
19079    };
19080    context.placeholderToContent[closePhName] = {
19081      text: block.endSourceSpan ? block.endSourceSpan.toString() : '}',
19082      sourceSpan: block.endSourceSpan ?? block.sourceSpan
19083    };
19084    const node = new BlockPlaceholder(block.name, parameters, startPhName, closePhName, children, block.sourceSpan, block.startSourceSpan, block.endSourceSpan);
19085    return context.visitNodeFn(block, node);
19086  }
19087  visitBlockParameter(_parameter, _context) {
19088    throw new Error('Unreachable code');
19089  }
19090  /**
19091   * Convert, text and interpolated tokens up into text and placeholder pieces.
19092   *
19093   * @param tokens The text and interpolated tokens.
19094   * @param sourceSpan The span of the whole of the `text` string.
19095   * @param context The current context of the visitor, used to compute and store placeholders.
19096   * @param previousI18n Any i18n metadata associated with this `text` from a previous pass.
19097   */
19098  _visitTextWithInterpolation(tokens, sourceSpan, context, previousI18n) {
19099    // Return a sequence of `Text` and `Placeholder` nodes grouped in a `C
19099ontainer`.
19100    const nodes = [];
19101    // We will only create a container if there are actually interpolations,
19102    // so this flag tracks that.
19103    let hasInterpolation = false;
19104    for (const token of tokens) {
19105      switch (token.type) {
19106        case 8 /* TokenType.INTERPOLATION */:
19107        case 17 /* TokenType.ATTR_VALUE_INTERPOLATION */:
19108          hasInterpolation = true;
19109          const expression = token.parts[1];
19110          const baseName = extractPlaceholderName(expression) || 'INTERPOLATION';
19111          const phName = context.placeholderRegistry.getPlaceholderName(baseName, expression);
19112          context.placeholderToContent[phName] = {
19113            text: token.parts.join(''),
19114            sourceSpan: token.sourceSpan
19115          };
19116          nodes.push(new Placeholder(expression, phName, token.sourceSpan));
19117          break;
19118        default:
19119          if (token.parts[0].length > 0) {
19120            // This token is text or an encoded entity.
19121            // If it is following on from a previous text node then merge it into that node
19122            // Otherwise, if it is following an interpolation, then add a new node.
19123            const previous = nodes[nodes.length - 1];
19124            if (previous instanceof Text$2) {
19125              previous.value += token.parts[0];
19126              previous.sourceSpan = new ParseSourceSpan(previous.sourceSpan.start, token.sourceSpan.end, previous.sourceSpan.fullStart, previous.sourceSpan.details);
19127            } else {
19128              nodes.push(new Text$2(token.parts[0], token.sourceSpan));
19129            }
19130          }
19131          break;
19132      }
19133    }
19134    if (hasInterpolation) {
19135      // Whitespace removal may have invalidated the interpolation source-spans.
19136      reusePreviousSourceSpans(nodes, previousI18n);
19137      return new Container(nodes, sourceSpan);
19138    } else {
19139      return nodes[0];
19140    }
19141  }
19142}
19143/**
19144 * Re-use the source-spans from `previousI18n` metadata for the `nodes`.
19145 *
19146 * Whitespace removal can invalidate the source-spans of interpolation nodes, so we
19147 * reuse the source-span stored from a previous pass before the whitespace was removed.
19148 *
19149 * @param nodes The `Text` and `Placeholder` nodes to be processed.
19150 * @param previousI18n Any i18n metadata for these `nodes` stored from a previous pass.
19151 */
19152function reusePreviousSourceSpans(nodes, previousI18n) {
19153  if (previousI18n instanceof Message) {
19154    // The `previousI18n` is an i18n `Message`, so we are processing an `Attribute` with i18n
19155    // metadata. The `Message` should consist only of a single `Container` that contains the
19156    // parts (`Text` and `Placeholder`) to process.
19157    assertSingleContainerMessage(previousI18n);
19158    previousI18n = previousI18n.nodes[0];
19159  }
19160  if (previousI18n instanceof Container) {
19161    // The `previousI18n` is a `Container`, which means that this is a second i18n extraction pass
19162    // after whitespace has been removed from the AST nodes.
19163    assertEquivalentNodes(previousI18n.children, nodes);
19164    // Reuse the source-spans from the first pass.
19165    for (let i = 0; i < nodes.length; i++) {
19166      nodes[i].sourceSpan = previousI18n.children[i].sourceSpan;
19167    }
19168  }
19169}
19170/**
19171 * Asserts that the `message` contains exactly one `Container` node.
19172 */
19173function assertSingleContainerMessage(message) {
19174  const nodes = message.nodes;
19175  if (nodes.length !== 1 || !(nodes[0] instanceof Container)) {
19176    throw new Error('Unexpected previous i18n message - expected it to consist of only a single `Container` node.');
19177  }
19178}
19179/**
19180 * Asserts that the `previousNodes` and `node` collections have the same number of elements and
19181 * corresponding elements have the same node type.
19182 */
19183function assertEquivalentNodes(previousNodes, nodes) {
19184  if (previousNodes.length !== nodes.length) {
19185    throw new Error('The number of i18n message children changed between first and second pass.');
19186  }
19187  if (previousNodes.some((node, i) => nodes[i].constructor !== node.constructor)) {
19188    throw new Error('The types of the i18n message children changed between first and second pass.');
19189  }
19190}
19191const _CUSTOM_PH_EXP = /\/\/[\s\S]*i18n[\s\S]*\([\s\S]*ph[\s\S]*=[\s\S]*("|')([\s\S]*?)\1[\s\S]*\)/g;
19192function extractPlaceholderName(input) {
19193  return input.split(_CUSTOM_PH_EXP)[2];
19194}
19195
19196/**
19197 * An i18n error.
19198 */
19199class I18nError extends ParseError {
19200  constructor(span, msg) {
19201    super(span, msg);
19202  }
19203}
19204
19205// Mapping between all HTML entity names and their unicode representation.
19206// Generated from https://html.spec.whatwg.org/multipage/entities.json by stripping
19207// the `&` and `;` from the keys and removing the duplicates.
19208// see https://www.w3.org/TR/html51/syntax.html#named-character-references
19209const NAMED_ENTITIES = {
19210  'AElig': '\u00C6',
19211  'AMP': '\u0026',
19212  'amp': '\u0026',
19213  'Aacute': '\u00C1',
19214  'Abreve': '\u0102',
19215  'Acirc': '\u00C2',
19216  'Acy': '\u0410',
19217  'Afr': '\uD835\uDD04',
19218  'Agrave': '\u00C0',
19219  'Alpha': '\u0391',
19220  'Amacr': '\u0100',
19221  'And': '\u2A53',
19222  'Aogon': '\u0104',
19223  'Aopf': '\uD835\uDD38',
19224  'ApplyFunction': '\u2061',
19225  'af': '\u2061',
19226  'Aring': '\u00C5',
19227  'angst': '\u00C5',
19228  'Ascr': '\uD835\uDC9C',
19229  'Assign': '\u2254',
19230  'colone': '\u2254',
19231  'coloneq': '\u2254',
19232  'Atilde': '\u00C3',
19233  'Auml': '\u00C4',
19234  'Backslash': '\u2216',
19235  'setminus': '\u2216',
19236  'setmn': '\u2216',
19237  'smallsetminus': '\u2216',
19238  'ssetmn': '\u2216',
19239  'Barv': '\u2AE7',
19240  'Barwed': '\u2306',
19241  'doublebarwedge': '\u2306',
19242  'Bcy': '\u0411',
19243  'Because': '\u2235',
19244  'becaus': '\u2235',
19245  'because': '\u2235',
19246  'Bernoullis': '\u212C',
19247  'Bscr': '\u212C',
19248  'bernou': '\u212C',
19249  'Beta': '\u0392',
19250  'Bfr': '\uD835\uDD05',
19251  'Bopf': '\uD835\uDD39',
19252  'Breve': '\u02D8',
19253  'breve': '\u02D8',
19254  'Bumpeq': '\u224E',
19255  'HumpDownHump': '\u224E',
19256  'bump': '\u224E',
19257  'CHcy': '\u0427',
19258  'COPY': '\u00A9',
19259  'copy': '\u00A9',
19260  'Cacute': '\u0106',
19261  'Cap': '\u22D2',
19262  'CapitalDifferentialD': '\u2145',
19263  'DD': '\u2145',
19264  'Cayleys': '\u212D',
19265  'Cfr': '\u212D',
19266  'Ccaron': '\u010C',
19267  'Ccedil': '\u00C7',
19268  'Ccirc': '\u0108',
19269  'Cconint': '\u2230',
19270  'Cdot': '\u010A',
19271  'Cedilla': '\u00B8',
19272  'cedil': '\u00B8',
19273  'CenterDot': '\u00B7',
19274  'centerdot': '\u00B7',
19275  'middot': '\u00B7',
19276  'Chi': '\u03A7',
19277  'CircleDot': '\u2299',
19278  'odot': '\u2299',
19279  'CircleMinus': '\u2296',
19280  'ominus': '\u2296',
19281  'CirclePlus': '\u2295',
19282  'oplus': '\u2295',
19283  'CircleTimes': '\u2297',
19284  'otimes': '\u2297',
19285  'ClockwiseContourIntegral': '\u2232',
19286  'cwconint': '\u2232',
19287  'CloseCurlyDoubleQuote': '\u201D',
19288  'rdquo': '\u201D',
19289  'rdquor': '\u201D',
19290  'CloseCurlyQuote': '\u2019',
19291  'rsquo': '\u2019',
19292  'rsquor': '\u2019',
19293  'Colon': '\u2237',
19294  'Proportion': '\u2237',
19295  'Colone': '\u2A74',
19296  'Congruent': '\u2261',
19297  'equiv': '\u2261',
19298  'Conint': '\u222F',
19299  'DoubleContourIntegral': '\u222F',
19300  'ContourIntegral': '\u222E',
19301  'conint': '\u222E',
19302  'oint': '\u222E',
19303  'Copf': '\u2102',
19304  'complexes': '\u2102',
19305  'Coproduct': '\u2210',
19306  'coprod': '\u2210',
19307  'CounterClockwiseContourIntegral': '\u2233',
19308  'awconint': '\u2233',
19309  'Cross': '\u2A2F',
19310  'Cscr': '\uD835\uDC9E',
19311  'Cup': '\u22D3',
19312  'CupCap': '\u224D',
19313  'asympeq': '\u224D',
19314  'DDotrahd': '\u2911',
19315  'DJcy': '\u0402',
19316  'DScy': '\u0405',
19317  'DZcy': '\u040F',
19318  'Dagger': '\u2021',
19319  'ddagger': '\u2021',
19320  'Darr': '\u21A1',
19321  'Dashv': '\u2AE4',
19322  'DoubleLeftTee': '\u2AE4',
19323  'Dcaron': '\u010E',
19324  'Dcy': '\u0414',
19325  'Del': '\u2207',
19326  'nabla': '\u2207',
19327  'Delta': '\u0394',
19328  'Dfr': '\uD835\uDD07',
19329  'DiacriticalAcute': '\u00B4',
19330  'acute': '\u00B4',
19331  'DiacriticalDot': '\u02D9',
19332  'dot': '\u02D9',
19333  'DiacriticalDoubleAcute': '\u02DD',
19334  'dblac': '\u02DD',
19335  'DiacriticalGrave': '\u0060',
19336  'grave': '\u0060',
19337  'DiacriticalTilde': '\u02DC',
19338  'tilde': '\u02DC',
19339  'Diamond': '\u22C4',
19340  'diam': '\u22C4',
19341  'diamond': '\u22C4',
19342  'DifferentialD': '\u2146',
19343  'dd': '\u2146',
19344  'Dopf': '\uD835\uDD3B',
19345  'Dot': '\u00A8',
19346  'DoubleDot': '\u00A8',
19347  'die': '\u00A8',
19348  'uml': '\u00A8',
19349  'DotDot': '\u20DC',
19350  'DotEqual': '\u2250',
19351  'doteq': '\u2250',
19352  'esdot': '\u2250',
19353  'DoubleDownArrow': '\u21D3',
19354  'Downarrow': '\u21D3',
19355  'dArr': '\u21D3',
19356  'DoubleLeftArrow': '\u21D0',
19357  'Leftarrow': '\u21D0',
19358  'lArr': '\u21D0',
19359  'DoubleLeftRightArrow': '\u21D4',
19360  'Leftrightarrow': '\u21D4',
19361  'hArr': '\u21D4',
19362  'iff': '\u21D4',
19363  'DoubleLongLeftArrow': '\u27F8',
19364  'Longleftarrow': '\u27F8',
19365  'xlArr': '\u27F8',
19366  'DoubleLongLeftRightArrow': '\u27FA',
19367  'Longleftrightarrow': '\u27FA',
19368  'xhArr': '\u27FA',
19369  'DoubleLongRightArrow': '\u27F9',
19370  'Longrightarrow': '\u27F9',
19371  'xrArr': '\u27F9',
19372  'DoubleRightArrow': '\u21D2',
19373  'Implies': '\u21D2',
19374  'Rightarrow': '\u21D2',
19375  'rArr': '\u21D2',
19376  'DoubleRightTee': '\u22A8',
19377  'vDash': '\u22A8',
19378  'DoubleUpArrow': '\u21D1',
19379  'Uparrow': '\u21D1',
19380  'uArr': '\u21D1',
19381  'DoubleUpDownArrow': '\u21D5',
19382  'Updownarrow': '\u21D5',
19383  'vArr': '\u21D5',
19384  'DoubleVerticalBar': '\u2225',
19385  'par': '\u2225',
19386  'parallel': '\u2225',
19387  'shortparallel': '\u2225',
19388  'spar': '\u2225',
19389  'DownArrow': '\u2193',
19390  'ShortDownArrow': '\u2193',
19391  'darr': '\u2193',
19392  'downarrow': '\u2193',
19393  'DownArrowBar': '\u2913',
19394  'DownArrowUpArrow': '\u21F5',
19395  'duarr': '\u21F5',
19396  'DownBreve': '\u0311',
19397  'DownLeftRightVector': '\u2950',
19398  'DownLeftTeeVector': '\u295E',
19399  'DownLeftVector': '\u21BD',
19400  'leftharpoondown': '\u21BD',
19401  'lhard': '\u21BD',
19402  'DownLeftVectorBar': '\u2956',
19403  'DownRightTeeVector': '\u295F',
19404  'DownRightVector': '\u21C1',
19405  'rhard': '\u21C1',
19406  'rightharpoondown': '\u21C1',
19407  'DownRightVectorBar': '\u2957',
19408  'DownTee': '\u22A4',
19409  'top': '\u22A4',
19410  'DownTeeArrow': '\u21A7',
19411  'mapstodown': '\u21A7',
19412  'Dscr': '\uD835\uDC9F',
19413  'Dstrok': '\u0110',
19414  'ENG': '\u014A',
19415  'ETH': '\u00D0',
19416  'Eacute': '\u00C9',
19417  'Ecaron': '\u011A',
19418  'Ecirc': '\u00CA',
19419  'Ecy': '\u042D',
19420  'Edot': '\u0116',
19421  'Efr': '\uD835\uDD08',
19422  'Egrave': '\u00C8',
19423  'Element': '\u2208',
19424  'in': '\u2208',
19425  'isin': '\u2208',
19426  'isinv': '\u2208',
19427  'Emacr': '\u0112',
19428  'EmptySmallSquare': '\u25FB',
19429  'EmptyVerySmallSquare': '\u25AB',
19430  'Eogon': '\u0118',
19431  'Eopf': '\uD835\uDD3C',
19432  'Epsilon': '\u0395',
19433  'Equal': '\u2A75',
19434  'EqualTilde': '\u2242',
19435  'eqsim': '\u2242',
19436  'esim': '\u2242',
19437  'Equilibrium': '\u21CC',
19438  'rightleftharpoons': '\u21CC',
19439  'rlhar': '\u21CC',
19440  'Escr': '\u2130',
19441  'expectation': '\u2130',
19442  'Esim': '\u2A73',
19443  'Eta': '\u0397',
19444  'Euml': '\u00CB',
19445  'Exists': '\u2203',
19446  'exist': '\u2203',
19447  'ExponentialE': '\u2147',
19448  'ee': '\u2147',
19449  'exponentiale': '\u2147',
19450  'Fcy': '\u0424',
19451  'Ffr': '\uD835\uDD09',
19452  'FilledSmallSquare': '\u25FC',
19453  'FilledVerySmallSquare': '\u25AA',
19454  'blacksquare': '\u25AA',
19455  'squarf': '\u25AA',
19456  'squf': '\u25AA',
19457  'Fopf': '\uD835\uDD3D',
19458  'ForAll': '\u2200',
19459  'forall': '\u2200',
19460  'Fouriertrf': '\u2131',
19461  'Fscr': '\u2131',
19462  'GJcy': '\u0403',
19463  'GT': '\u003E',
19464  'gt': '\u003E',
19465  'Gamma': '\u0393',
19466  'Gammad': '\u03DC',
19467  'Gbreve': '\u011E',
19468  'Gcedil': '\u0122',
19469  'Gcirc': '\u011C',
19470  'Gcy': '\u0413',
19471  'Gdot': '\u0120',
19472  'Gfr': '\uD835\uDD0A',
19473  'Gg': '\u22D9',
19474  'ggg': '\u22D9',
19475  'Gopf': '\uD835\uDD3E',
19476  'GreaterEqual': '\u2265',
19477  'ge': '\u2265',
19478  'geq': '\u2265',
19479  'GreaterEqualLess': '\u22DB',
19480  'gel': '\u22DB',
19481  'gtreqless': '\u22DB',
19482  'GreaterFullEqual': '\u2267',
19483  'gE': '\u2267',
19484  'geqq': '\u2267',
19485  'GreaterGreater': '\u2AA2',
19486  'GreaterLess': '\u2277',
19487  'gl': '\u2277',
19488  'gtrless': '\u2277',
19489  'GreaterSlantEqual': '\u2A7E',
19490  'geqslant': '\u2A7E',
19491  'ges': '\u2A7E',
19492  'GreaterTilde': '\u2273',
19493  'gsim': '\u2273',
19494  'gtrsim': '\u2273',
19495  'Gscr': '\uD835\uDCA2',
19496  'Gt': '\u226B',
19497  'NestedGreaterGreater': '\u226B',
19498  'gg': '\u226B',
19499  'HARDcy': '\u042A',
19500  'Hacek': '\u02C7',
19501  'caron': '\u02C7',
19502  'Hat': '\u005E',
19503  'Hcirc': '\u0124',
19504  'Hfr': '\u210C',
19505  'Poincareplane': '\u210C',
19506  'HilbertSpace': '\u210B',
19507  'Hscr': '\u210B',
19508  'hamilt': '\u210B',
19509  'Hopf': '\u210D',
19510  'quaternions': '\u210D',
19511  'HorizontalLine': '\u2500',
19512  'boxh': '\u2500',
19513  'Hstrok': '\u0126',
19514  'HumpEqual': '\u224F',
19515  'bumpe': '\u224F',
19516  'bumpeq': '\u224F',
19517  'IEcy': '\u0415',
19518  'IJlig': '\u0132',
19519  'IOcy': '\u0401',
19520  'Iacute': '\u00CD',
19521  'Icirc': '\u00CE',
19522  'Icy': '\u0418',
19523  'Idot': '\u0130',
19524  'Ifr': '\u2111',
19525  'Im': '\u2111',
19526  'image': '\u2111',
19527  'imagpart': '\u2111',
19528  'Igrave': '\u00CC',
19529  'Imacr': '\u012A',
19530  'ImaginaryI': '\u2148',
19531  'ii': '\u2148',
19532  'Int': '\u222C',
19533  'Integral': '\u222B',
19534  'int': '\u222B',
19535  'Intersection': '\u22C2',
19536  'bigcap': '\u22C2',
19537  'xcap': '\u22C2',
19538  'InvisibleComma': '\u2063',
19539  'ic': '\u2063',
19540  'InvisibleTimes': '\u2062',
19541  'it': '\u2062',
19542  'Iogon': '\u012E',
19543  'Iopf': '\uD835\uDD40',
19544  'Iota': '\u0399',
19545  'Iscr': '\u2110',
19546  'imagline': '\u2110',
19547  'Itilde': '\u0128',
19548  'Iukcy': '\u0406',
19549  'Iuml': '\u00CF',
19550  'Jcirc': '\u0134',
19551  'Jcy': '\u0419',
19552  'Jfr': '\uD835\uDD0D',
19553  'Jopf': '\uD835\uDD41',
19554  'Jscr': '\uD835\uDCA5',
19555  'Jsercy': '\u0408',
19556  'Jukcy': '\u0404',
19557  'KHcy': '\u0425',
19558  'KJcy': '\u040C',
19559  'Kappa': '\u039A',
19560  'Kcedil': '\u0136',
19561  'Kcy': '\u041A',
19562  'Kfr': '\uD835\uDD0E',
19563  'Kopf': '\uD835\uDD42',
19564  'Kscr': '\uD835\uDCA6',
19565  'LJcy': '\u0409',
19566  'LT': '\u003C',
19567  'lt': '\u003C',
19568  'Lacute': '\u0139',
19569  'Lambda': '\u039B',
19570  'Lang': '\u27EA',
19571  'Laplacetrf': '\u2112',
19572  'Lscr': '\u2112',
19573  'lagran': '\u2112',
19574  'Larr': '\u219E',
19575  'twoheadleftarrow': '\u219E',
19576  'Lcaron': '\u013D',
19577  'Lcedil': '\u013B',
19578  'Lcy': '\u041B',
19579  'LeftAngleBracket': '\u27E8',
19580  'lang': '\u27E8',
19581  'langle': '\u27E8',
19582  'LeftArrow': '\u2190',
19583  'ShortLeftArrow': '\u2190',
19584  'larr': '\u2190',
19585  'leftarrow': '\u2190',
19586  'slarr': '\u2190',
19587  'LeftArrowBar': '\u21E4',
19588  'larrb': '\u21E4',
19589  'LeftArrowRightArrow': '\u21C6',
19590  'leftrightarrows': '\u21C6',
19591  'lrarr': '\u21C6',
19592  'LeftCeiling': '\u2308',
19593  'lceil': '\u2308',
19594  'LeftDoubleBracket': '\u27E6',
19595  'lobrk': '\u27E6',
19596  'LeftDownTeeVector': '\u2961',
19597  'LeftDownVector': '\u21C3',
19598  'dharl': '\u21C3',
19599  'downharpoonleft': '\u21C3',
19600  'LeftDownVectorBar': '\u2959',
19601  'LeftFloor': '\u230A',
19602  'lfloor': '\u230A',
19603  'LeftRightArrow': '\u2194',
19604  'harr': '\u2194',
19605  'leftrightarrow': '\u2194',
19606  'LeftRightVector': '\u294E',
19607  'LeftTee': '\u22A3',
19608  'dashv': '\u22A3',
19609  'LeftTeeArrow': '\u21A4',
19610  'mapstoleft': '\u21A4',
19611  'LeftTeeVector': '\u295A',
19612  'LeftTriangle': '\u22B2',
19613  'vartriangleleft': '\u22B2',
19614  'vltri': '\u22B2',
19615  'LeftTriangleBar': '\u29CF',
19616  'LeftTriangleEqual': '\u22B4',
19617  'ltrie': '\u22B4',
19618  'trianglelefteq': '\u22B4',
19619  'LeftUpDownVector': '\u2951',
19620  'LeftUpTeeVector': '\u2960',
19621  'LeftUpVector': '\u21BF',
19622  'uharl': '\u21BF',
19623  'upharpoonleft': '\u21BF',
19624  'LeftUpVectorBar': '\u2958',
19625  'LeftVector': '\u21BC',
19626  'leftharpoonup': '\u21BC',
19627  'lharu': '\u21BC',
19628  'LeftVectorBar': '\u2952',
19629  'LessEqualGreater': '\u22DA',
19630  'leg': '\u22DA',
19631  'lesseqgtr': '\u22DA',
19632  'LessFullEqual': '\u2266',
19633  'lE': '\u2266',
19634  'leqq': '\u2266',
19635  'LessGreater': '\u2276',
19636  'lessgtr': '\u2276',
19637  'lg': '\u2276',
19638  'LessLess': '\u2AA1',
19639  'LessSlantEqual': '\u2A7D',
19640  'leqslant': '\u2A7D',
19641  'les': '\u2A7D',
19642  'LessTilde': '\u2272',
19643  'lesssim': '\u2272',
19644  'lsim': '\u2272',
19645  'Lfr': '\uD835\uDD0F',
19646  'Ll': '\u22D8',
19647  'Lleftarrow': '\u21DA',
19648  'lAarr': '\u21DA',
19649  'Lmidot': '\u013F',
19650  'LongLeftArrow': '\u27F5',
19651  'longleftarrow': '\u27F5',
19652  'xlarr': '\u27F5',
19653  'LongLeftRightArrow': '\u27F7',
19654  'longleftrightarrow': '\u27F7',
19655  'xharr': '\u27F7',
19656  'LongRightArrow': '\u27F6',
19657  'longrightarrow': '\u27F6',
19658  'xrarr': '\u27F6',
19659  'Lopf': '\uD835\uDD43',
19660  'LowerLeftArrow': '\u2199',
19661  'swarr': '\u2199',
19662  'swarrow': '\u2199',
19663  'LowerRightArrow': '\u2198',
19664  'searr': '\u2198',
19665  'searrow': '\u2198',
19666  'Lsh': '\u21B0',
19667  'lsh': '\u21B0',
19668  'Lstrok': '\u0141',
19669  'Lt': '\u226A',
19670  'NestedLessLess': '\u226A',
19671  'll': '\u226A',
19672  'Map': '\u2905',
19673  'Mcy': '\u041C',
19674  'MediumSpace': '\u205F',
19675  'Mellintrf': '\u2133',
19676  'Mscr': '\u2133',
19677  'phmmat': '\u2133',
19678  'Mfr': '\uD835\uDD10',
19679  'MinusPlus': '\u2213',
19680  'mnplus': '\u2213',
19681  'mp': '\u2213',
19682  'Mopf': '\uD835\uDD44',
19683  'Mu': '\u039C',
19684  'NJcy': '\u040A',
19685  'Nacute': '\u0143',
19686  'Ncaron': '\u0147',
19687  'Ncedil': '\u0145',
19688  'Ncy': '\u041D',
19689  'NegativeMediumSpace': '\u200B',
19690  'NegativeThickSpace': '\u200B',
19691  'NegativeThinSpace': '\u200B',
19692  'NegativeVeryThinSpace': '\u200B',
19693  'ZeroWidthSpace': '\u200B',
19694  'NewLine': '\u000A',
19695  'Nfr': '\uD835\uDD11',
19696  'NoBreak': '\u2060',
19697  'NonBreakingSpace': '\u00A0',
19698  'nbsp': '\u00A0',
19698
19699  'Nopf': '\u2115',
19700  'naturals': '\u2115',
19701  'Not': '\u2AEC',
19702  'NotCongruent': '\u2262',
19703  'nequiv': '\u2262',
19704  'NotCupCap': '\u226D',
19705  'NotDoubleVerticalBar': '\u2226',
19706  'npar': '\u2226',
19707  'nparallel': '\u2226',
19708  'nshortparallel': '\u2226',
19709  'nspar': '\u2226',
19710  'NotElement': '\u2209',
19711  'notin': '\u2209',
19712  'notinva': '\u2209',
19713  'NotEqual': '\u2260',
19714  'ne': '\u2260',
19715  'NotEqualTilde': '\u2242\u0338',
19716  'nesim': '\u2242\u0338',
19717  'NotExists': '\u2204',
19718  'nexist': '\u2204',
19719  'nexists': '\u2204',
19720  'NotGreater': '\u226F',
19721  'ngt': '\u226F',
19722  'ngtr': '\u226F',
19723  'NotGreaterEqual': '\u2271',
19724  'nge': '\u2271',
19725  'ngeq': '\u2271',
19726  'NotGreaterFullEqual': '\u2267\u0338',
19727  'ngE': '\u2267\u0338',
19728  'ngeqq': '\u2267\u0338',
19729  'NotGreaterGreater': '\u226B\u0338',
19730  'nGtv': '\u226B\u0338',
19731  'NotGreaterLess': '\u2279',
19732  'ntgl': '\u2279',
19733  'NotGreaterSlantEqual': '\u2A7E\u0338',
19734  'ngeqslant': '\u2A7E\u0338',
19735  'nges': '\u2A7E\u0338',
19736  'NotGreaterTilde': '\u2275',
19737  'ngsim': '\u2275',
19738  'NotHumpDownHump': '\u224E\u0338',
19739  'nbump': '\u224E\u0338',
19740  'NotHumpEqual': '\u224F\u0338',
19741  'nbumpe': '\u224F\u0338',
19742  'NotLeftTriangle': '\u22EA',
19743  'nltri': '\u22EA',
19744  'ntriangleleft': '\u22EA',
19745  'NotLeftTriangleBar': '\u29CF\u0338',
19746  'NotLeftTriangleEqual': '\u22EC',
19747  'nltrie': '\u22EC',
19748  'ntrianglelefteq': '\u22EC',
19749  'NotLess': '\u226E',
19750  'nless': '\u226E',
19751  'nlt': '\u226E',
19752  'NotLessEqual': '\u2270',
19753  'nle': '\u2270',
19754  'nleq': '\u2270',
19755  'NotLessGreater': '\u2278',
19756  'ntlg': '\u2278',
19757  'NotLessLess': '\u226A\u0338',
19758  'nLtv': '\u226A\u0338',
19759  'NotLessSlantEqual': '\u2A7D\u0338',
19760  'nleqslant': '\u2A7D\u0338',
19761  'nles': '\u2A7D\u0338',
19762  'NotLessTilde': '\u2274',
19763  'nlsim': '\u2274',
19764  'NotNestedGreaterGreater': '\u2AA2\u0338',
19765  'NotNestedLessLess': '\u2AA1\u0338',
19766  'NotPrecedes': '\u2280',
19767  'npr': '\u2280',
19768  'nprec': '\u2280',
19769  'NotPrecedesEqual': '\u2AAF\u0338',
19770  'npre': '\u2AAF\u0338',
19771  'npreceq': '\u2AAF\u0338',
19772  'NotPrecedesSlantEqual': '\u22E0',
19773  'nprcue': '\u22E0',
19774  'NotReverseElement': '\u220C',
19775  'notni': '\u220C',
19776  'notniva': '\u220C',
19777  'NotRightTriangle': '\u22EB',
19778  'nrtri': '\u22EB',
19779  'ntriangleright': '\u22EB',
19780  'NotRightTriangleBar': '\u29D0\u0338',
19781  'NotRightTriangleEqual': '\u22ED',
19782  'nrtrie': '\u22ED',
19783  'ntrianglerighteq': '\u22ED',
19784  'NotSquareSubset': '\u228F\u0338',
19785  'NotSquareSubsetEqual': '\u22E2',
19786  'nsqsube': '\u22E2',
19787  'NotSquareSuperset': '\u2290\u0338',
19788  'NotSquareSupersetEqual': '\u22E3',
19789  'nsqsupe': '\u22E3',
19790  'NotSubset': '\u2282\u20D2',
19791  'nsubset': '\u2282\u20D2',
19792  'vnsub': '\u2282\u20D2',
19793  'NotSubsetEqual': '\u2288',
19794  'nsube': '\u2288',
19795  'nsubseteq': '\u2288',
19796  'NotSucceeds': '\u2281',
19797  'nsc': '\u2281',
19798  'nsucc': '\u2281',
19799  'NotSucceedsEqual': '\u2AB0\u0338',
19800  'nsce': '\u2AB0\u0338',
19801  'nsucceq': '\u2AB0\u0338',
19802  'NotSucceedsSlantEqual': '\u22E1',
19803  'nsccue': '\u22E1',
19804  'NotSucceedsTilde': '\u227F\u0338',
19805  'NotSuperset': '\u2283\u20D2',
19806  'nsupset': '\u2283\u20D2',
19807  'vnsup': '\u2283\u20D2',
19808  'NotSupersetEqual': '\u2289',
19809  'nsupe': '\u2289',
19810  'nsupseteq': '\u2289',
19811  'NotTilde': '\u2241',
19812  'nsim': '\u2241',
19813  'NotTildeEqual': '\u2244',
19814  'nsime': '\u2244',
19815  'nsimeq': '\u2244',
19816  'NotTildeFullEqual': '\u2247',
19817  'ncong': '\u2247',
19818  'NotTildeTilde': '\u2249',
19819  'nap': '\u2249',
19820  'napprox': '\u2249',
19821  'NotVerticalBar': '\u2224',
19822  'nmid': '\u2224',
19823  'nshortmid': '\u2224',
19824  'nsmid': '\u2224',
19825  'Nscr': '\uD835\uDCA9',
19826  'Ntilde': '\u00D1',
19827  'Nu': '\u039D',
19828  'OElig': '\u0152',
19829  'Oacute': '\u00D3',
19830  'Ocirc': '\u00D4',
19831  'Ocy': '\u041E',
19832  'Odblac': '\u0150',
19833  'Ofr': '\uD835\uDD12',
19834  'Ograve': '\u00D2',
19835  'Omacr': '\u014C',
19836  'Omega': '\u03A9',
19837  'ohm': '\u03A9',
19838  'Omicron': '\u039F',
19839  'Oopf': '\uD835\uDD46',
19840  'OpenCurlyDoubleQuote': '\u201C',
19841  'ldquo': '\u201C',
19842  'OpenCurlyQuote': '\u2018',
19843  'lsquo': '\u2018',
19844  'Or': '\u2A54',
19845  'Oscr': '\uD835\uDCAA',
19846  'Oslash': '\u00D8',
19847  'Otilde': '\u00D5',
19848  'Otimes': '\u2A37',
19849  'Ouml': '\u00D6',
19850  'OverBar': '\u203E',
19851  'oline': '\u203E',
19852  'OverBrace': '\u23DE',
19853  'OverBracket': '\u23B4',
19854  'tbrk': '\u23B4',
19855  'OverParenthesis': '\u23DC',
19856  'PartialD': '\u2202',
19857  'part': '\u2202',
19858  'Pcy': '\u041F',
19859  'Pfr': '\uD835\uDD13',
19860  'Phi': '\u03A6',
19861  'Pi': '\u03A0',
19862  'PlusMinus': '\u00B1',
19863  'plusmn': '\u00B1',
19864  'pm': '\u00B1',
19865  'Popf': '\u2119',
19866  'primes': '\u2119',
19867  'Pr': '\u2ABB',
19868  'Precedes': '\u227A',
19869  'pr': '\u227A',
19870  'prec': '\u227A',
19871  'PrecedesEqual': '\u2AAF',
19872  'pre': '\u2AAF',
19873  'preceq': '\u2AAF',
19874  'PrecedesSlantEqual': '\u227C',
19875  'prcue': '\u227C',
19876  'preccurlyeq': '\u227C',
19877  'PrecedesTilde': '\u227E',
19878  'precsim': '\u227E',
19879  'prsim': '\u227E',
19880  'Prime': '\u2033',
19881  'Product': '\u220F',
19882  'prod': '\u220F',
19883  'Proportional': '\u221D',
19884  'prop': '\u221D',
19885  'propto': '\u221D',
19886  'varpropto': '\u221D',
19887  'vprop': '\u221D',
19888  'Pscr': '\uD835\uDCAB',
19889  'Psi': '\u03A8',
19890  'QUOT': '\u0022',
19891  'quot': '\u0022',
19892  'Qfr': '\uD835\uDD14',
19893  'Qopf': '\u211A',
19894  'rationals': '\u211A',
19895  'Qscr': '\uD835\uDCAC',
19896  'RBarr': '\u2910',
19897  'drbkarow': '\u2910',
19898  'REG': '\u00AE',
19899  'circledR': '\u00AE',
19900  'reg': '\u00AE',
19901  'Racute': '\u0154',
19902  'Rang': '\u27EB',
19903  'Rarr': '\u21A0',
19904  'twoheadrightarrow': '\u21A0',
19905  'Rarrtl': '\u2916',
19906  'Rcaron': '\u0158',
19907  'Rcedil': '\u0156',
19908  'Rcy': '\u0420',
19909  'Re': '\u211C',
19910  'Rfr': '\u211C',
19911  'real': '\u211C',
19912  'realpart': '\u211C',
19913  'ReverseElement': '\u220B',
19914  'SuchThat': '\u220B',
19915  'ni': '\u220B',
19916  'niv': '\u220B',
19917  'ReverseEquilibrium': '\u21CB',
19918  'leftrightharpoons': '\u21CB',
19919  'lrhar': '\u21CB',
19920  'ReverseUpEquilibrium': '\u296F',
19921  'duhar': '\u296F',
19922  'Rho': '\u03A1',
19923  'RightAngleBracket': '\u27E9',
19924  'rang': '\u27E9',
19925  'rangle': '\u27E9',
19926  'RightArrow': '\u2192',
19927  'ShortRightArrow': '\u2192',
19928  'rarr': '\u2192',
19929  'rightarrow': '\u2192',
19930  'srarr': '\u2192',
19931  'RightArrowBar': '\u21E5',
19932  'rarrb': '\u21E5',
19933  'RightArrowLeftArrow': '\u21C4',
19934  'rightleftarrows': '\u21C4',
19935  'rlarr': '\u21C4',
19936  'RightCeiling': '\u2309',
19937  'rceil': '\u2309',
19938  'RightDoubleBracket': '\u27E7',
19939  'robrk': '\u27E7',
19940  'RightDownTeeVector': '\u295D',
19941  'RightDownVector': '\u21C2',
19942  'dharr': '\u21C2',
19943  'downharpoonright': '\u21C2',
19944  'RightDownVectorBar': '\u2955',
19945  'RightFloor': '\u230B',
19946  'rfloor': '\u230B',
19947  'RightTee': '\u22A2',
19948  'vdash': '\u22A2',
19949  'RightTeeArrow': '\u21A6',
19950  'map': '\u21A6',
19951  'mapsto': '\u21A6',
19952  'RightTeeVector': '\u295B',
19953  'RightTriangle': '\u22B3',
19954  'vartriangleright': '\u22B3',
19955  'vrtri': '\u22B3',
19956  'RightTriangleBar': '\u29D0',
19957  'RightTriangleEqual': '\u22B5',
19958  'rtrie': '\u22B5',
19959  'trianglerighteq': '\u22B5',
19960  'RightUpDownVector': '\u294F',
19961  'RightUpTeeVector': '\u295C',
19962  'RightUpVector': '\u21BE',
19963  'uharr': '\u21BE',
19964  'upharpoonright': '\u21BE',
19965  'RightUpVectorBar': '\u2954',
19966  'RightVector': '\u21C0',
19967  'rharu': '\u21C0',
19968  'rightharpoonup': '\u21C0',
19969  'RightVectorBar': '\u2953',
19970  'Ropf': '\u211D',
19971  'reals': '\u211D',
19972  'RoundImplies': '\u2970',
19973  'Rrightarrow': '\u21DB',
19974  'rAarr': '\u21DB',
19975  'Rscr': '\u211B',
19976  'realine': '\u211B',
19977  'Rsh': '\u21B1',
19978  'rsh': '\u21B1',
19979  'RuleDelayed': '\u29F4',
19980  'SHCHcy': '\u0429',
19981  'SHcy': '\u0428',
19982  'SOFTcy': '\u042C',
19983  'Sacute': '\u015A',
19984  'Sc': '\u2ABC',
19985  'Scaron': '\u0160',
19986  'Scedil': '\u015E',
19987  'Scirc': '\u015C',
19988  'Scy': '\u0421',
19989  'Sfr': '\uD835\uDD16',
19990  'ShortUpArrow': '\u2191',
19991  'UpArrow': '\u2191',
19992  'uarr': '\u2191',
19993  'uparrow': '\u2191',
19994  'Sigma': '\u03A3',
19995  'SmallCircle': '\u2218',
19996  'compfn': '\u2218',
19997  'Sopf': '\uD835\uDD4A',
19998  'Sqrt': '\u221A',
19999  'radic': '\u221A',
20000  'Square': '\u25A1',
20001  'squ': '\u25A1',
20002  'square': '\u25A1',
20003  'SquareIntersection': '\u2293',
20004  'sqcap': '\u2293',
20005  'SquareSubset': '\u228F',
20006  'sqsub': '\u228F',
20007  'sqsubset': '\u228F',
20008  'SquareSubsetEqual': '\u2291',
20009  'sqsube': '\u2291',
20010  'sqsubseteq': '\u2291',
20011  'SquareSuperset': '\u2290',
20012  'sqsup': '\u2290',
20013  'sqsupset': '\u2290',
20014  'SquareSupersetEqual': '\u2292',
20015  'sqsupe': '\u2292',
20016  'sqsupseteq': '\u2292',
20017  'SquareUnion': '\u2294',
20018  'sqcup': '\u2294',
20019  'Sscr': '\uD835\uDCAE',
20020  'Star': '\u22C6',
20021  'sstarf': '\u22C6',
20022  'Sub': '\u22D0',
20023  'Subset': '\u22D0',
20024  'SubsetEqual': '\u2286',
20025  'sube': '\u2286',
20026  'subseteq': '\u2286',
20027  'Succeeds': '\u227B',
20028  'sc': '\u227B',
20029  'succ': '\u227B',
20030  'SucceedsEqual': '\u2AB0',
20031  'sce': '\u2AB0',
20032  'succeq': '\u2AB0',
20033  'SucceedsSlantEqual': '\u227D',
20034  'sccue': '\u227D',
20035  'succcurlyeq': '\u227D',
20036  'SucceedsTilde': '\u227F',
20037  'scsim': '\u227F',
20038  'succsim': '\u227F',
20039  'Sum': '\u2211',
20040  'sum': '\u2211',
20041  'Sup': '\u22D1',
20042  'Supset': '\u22D1',
20043  'Superset': '\u2283',
20044  'sup': '\u2283',
20045  'supset': '\u2283',
20046  'SupersetEqual': '\u2287',
20047  'supe': '\u2287',
20048  'supseteq': '\u2287',
20049  'THORN': '\u00DE',
20050  'TRADE': '\u2122',
20051  'trade': '\u2122',
20052  'TSHcy': '\u040B',
20053  'TScy': '\u0426',
20054  'Tab': '\u0009',
20055  'Tau': '\u03A4',
20056  'Tcaron': '\u0164',
20057  'Tcedil': '\u0162',
20058  'Tcy': '\u0422',
20059  'Tfr': '\uD835\uDD17',
20060  'Therefore': '\u2234',
20061  'there4': '\u2234',
20062  'therefore': '\u2234',
20063  'Theta': '\u0398',
20064  'ThickSpace': '\u205F\u200A',
20065  'ThinSpace': '\u2009',
20066  'thinsp': '\u2009',
20067  'Tilde': '\u223C',
20068  'sim': '\u223C',
20069  'thicksim': '\u223C',
20070  'thksim': '\u223C',
20071  'TildeEqual': '\u2243',
20072  'sime': '\u2243',
20073  'simeq': '\u2243',
20074  'TildeFullEqual': '\u2245',
20075  'cong': '\u2245',
20076  'TildeTilde': '\u2248',
20077  'ap': '\u2248',
20078  'approx': '\u2248',
20079  'asymp': '\u2248',
20080  'thickapprox': '\u2248',
20081  'thkap': '\u2248',
20082  'Topf': '\uD835\uDD4B',
20083  'TripleDot': '\u20DB',
20084  'tdot': '\u20DB',
20085  'Tscr': '\uD835\uDCAF',
20086  'Tstrok': '\u0166',
20087  'Uacute': '\u00DA',
20088  'Uarr': '\u219F',
20089  'Uarrocir': '\u2949',
20090  'Ubrcy': '\u040E',
20091  'Ubreve': '\u016C',
20092  'Ucirc': '\u00DB',
20093  'Ucy': '\u0423',
20094  'Udblac': '\u0170',
20095  'Ufr': '\uD835\uDD18',
20096  'Ugrave': '\u00D9',
20097  'Umacr': '\u016A',
20098  'UnderBar': '\u005F',
20099  'lowbar': '\u005F',
20100  'UnderBrace': '\u23DF',
20101  'UnderBracket': '\u23B5',
20102  'bbrk': '\u23B5',
20103  'UnderParenthesis': '\u23DD',
20104  'Union': '\u22C3',
20105  'bigcup': '\u22C3',
20106  'xcup': '\u22C3',
20107  'UnionPlus': '\u228E',
20108  'uplus': '\u228E',
20109  'Uogon': '\u0172',
20110  'Uopf': '\uD835\uDD4C',
20111  'UpArrowBar': '\u2912',
20112  'UpArrowDownArrow': '\u21C5',
20113  'udarr': '\u21C5',
20114  'UpDownArrow': '\u2195',
20115  'updownarrow': '\u2195',
20116  'varr': '\u2195',
20117  'UpEquilibrium': '\u296E',
20118  'udhar': '\u296E',
20119  'UpTee': '\u22A5',
20120  'bot': '\u22A5',
20121  'bottom': '\u22A5',
20122  'perp': '\u22A5',
20123  'UpTeeArrow': '\u21A5',
20124  'mapstoup': '\u21A5',
20125  'UpperLeftArrow': '\u2196',
20126  'nwarr': '\u2196',
20127  'nwarrow': '\u2196',
20128  'UpperRightArrow': '\u2197',
20129  'nearr': '\u2197',
20130  'nearrow': '\u2197',
20131  'Upsi': '\u03D2',
20132  'upsih': '\u03D2',
20133  'Upsilon': '\u03A5',
20134  'Uring': '\u016E',
20135  'Uscr': '\uD835\uDCB0',
20136  'Utilde': '\u0168',
20137  'Uuml': '\u00DC',
20138  'VDash': '\u22AB',
20139  'Vbar': '\u2AEB',
20140  'Vcy': '\u0412',
20141  'Vdash': '\u22A9',
20142  'Vdashl': '\u2AE6',
20143  'Vee': '\u22C1',
20144  'bigvee': '\u22C1',
20145  'xvee': '\u22C1',
20146  'Verbar': '\u2016',
20147  'Vert': '\u2016',
20148  'VerticalBar': '\u2223',
20149  'mid': '\u2223',
20150  'shortmid': '\u2223',
20151  'smid': '\u2223',
20152  'VerticalLine': '\u007C',
20153  'verbar': '\u007C',
20154  'vert': '\u007C',
20155  'VerticalSeparator': '\u2758',
20156  'VerticalTilde': '\u2240',
20157  'wr': '\u2240',
20158  'wreath': '\u2240',
20159  'VeryThinSpace': '\u200A',
20160  'hairsp': '\u200A',
20161  'Vfr': '\uD835\uDD19',
20162  'Vopf': '\uD835\uDD4D',
20163  'Vscr': '\uD835\uDCB1',
20164  'Vvdash': '\u22AA',
20165  'Wcirc': '\u0174',
20166  'Wedge': '\u22C0',
20167  'bigwedge': '\u22C0',
20168  'xwedge': '\u22C0',
20169  'Wfr': '\uD835\uDD1A',
20170  'Wopf': '\uD835\uDD4E',
20171  'Wscr': '\uD835\uDCB2',
20172  'Xfr': '\uD835\uDD1B',
20173  'Xi': '\u039E',
20174  'Xopf': '\uD835\uDD4F',
20175  'Xscr': '\uD835\uDCB3',
20176  'YAcy': '\u042F',
20177  'YIcy': '\u0407',
20178  'YUcy': '\u042E',
20179  'Yacute': '\u00DD',
20180  'Ycirc': '\u0176',
20181  'Ycy': '\u042B',
20182  'Yfr': '\uD835\uDD1C',
20183  'Yopf': '\uD835\uDD50',
20184  'Yscr': '\uD835\uDCB4',
20185  'Yuml': '\u0178',
20186  'ZHcy': '\u0416',
20187  'Zacute': '\u0179',
20188  'Zcaron': '\u017D',
20189  'Zcy': '\u0417',
20190  'Zdot': '\u017B',
20191  'Zeta': '\u0396',
20192  'Zfr': '\u2128',
20193  'zeetrf': '\u2128',
20194  'Zopf': '\u2124',
20195  'integers': '\u2124',
20196  'Zscr': '\uD835\uDCB5',
20197  'aacute': '\u00E1',
20198  'abreve': '\u0103',
20199  'ac': '\u223E',
20200  'mstpos': '\u223E',
20201  'acE': '\u223E\u0333',
20202  'acd': '\u223F',
20203  'acirc': '\u00E2',
20204  'acy': '\u0430',
20205  'aelig': '\u00E6',
20206  'afr': '\uD835\uDD1E',
20207  'agrave': '\u00E0',
20208  'alefsym': '\u2135',
20209  'aleph': '\u2135',
20210  'alpha': '\u03B1',
20211  'amacr': '\u0101',
20212  'amalg': '\u2A3F',
20213  'and': '\u2227',
20214  'wedge': '\u2227',
20215  'andand': '\u2A55',
20216  'andd': '\u2A5C',
20217  'andslope': '\u2A58',
20218  'andv': '\u2A5A',
20219  'ang': '\u2220',
20220  'angle': '\u2220',
20221  'ange': '\u29A4',
20222  'angmsd': '\u2221',
20223  'measuredangle': '\u2221',
20224  'angmsdaa': '\u29A8',
20225  'angmsdab': '\u29A9',
20226  'angmsdac': '\u29AA',
20227  'angmsdad': '\u29AB',
20228  'angmsdae': '\u29AC',
20229  'angmsdaf': '\u29AD',
20230  'angmsdag': '\u29AE',
20231  'angmsdah': '\u29AF',
20232  'angrt': '\u221F',
20233  'angrtvb': '\u22BE',
20234  'angrtvbd': '\u299D',
20235  'angsph': '\u2222',
20236  'angzarr': '\u237C',
20237  'aogon': '\u0105',
20238  'aopf': '\uD835\uDD52',
20239  'apE': '\u2A70',
20240  'apacir': '\u2A6F',
20241  'ape': '\u224A',
20242  'approxeq': '\u224A',
20243  'apid': '\u224B',
20244  'apos': '\u0027',
20245  'aring': '\u00E5',
20246  'ascr': '\uD835\uDCB6',
20247  'ast': '\u002A',
20248  'midast': '\u002A',
20249  'atilde': '\u00E3',
20250  'auml': '\u00E4',
20251  'awint': '\u2A11',
20252  'bNot': '\u2AED',
20253  'backcong': '\u224C',
20254  'bcong': '\u224C',
20255  'backepsilon': '\u03F6',
20256  'bepsi': '\u03F6',
20257  'backprime': '\u2035',
20258  'bprime': '\u2035',
20259  'backsim': '\u223D',
20260  'bsim': '\u223D',
20261  'backsimeq': '\u22CD',
20262  'bsime': '\u22CD',
20263  'barvee': '\u22BD',
20264  'barwed': '\u2305',
20265  'barwedge': '\u2305',
20266  'bbrktbrk': '\u23B6',
20267  'bcy': '\u0431',
20268  'bdquo': '\u201E',
20269  'ldquor': '\u201E',
20270  'bemptyv': '\u29B0',
20271  'beta': '\u03B2',
20272  'beth': '\u2136',
20273  'between': '\u226C',
20274  'twixt': '\u226C',
20275  'bfr': '\uD835\uDD1F',
20276  'bigcirc': '\u25EF',
20277  'xcirc': '\u25EF',
20278  'bigodot': '\u2A00',
20279  'xodot': '\u2A00',
20280  'bigoplus': '\u2A01',
20281  'xoplus': '\u2A01',
20282  'bigotimes': '\u2A02',
20283  'xotime': '\u2A02',
20284  'bigsqcup': '\u2A06',
20285  'xsqcup': '\u2A06',
20286  'bigstar': '\u2605',
20287  'starf': '\u2605',
20288  'bigtriangledown': '\u25BD',
20289  'xdtri': '\u25BD',
20290  'bigtriangleup': '\u25B3',
20291  'xutri': '\u25B3',
20292  'biguplus': '\u2A04',
20293  'xuplus': '\u2A04',
20294  'bkarow': '\u290D',
20295  'rbarr': '\u290D',
20296  'blacklozenge': '\u29EB',
20297  'lozf': '\u29EB',
20298  'blacktriangle': '\u25B4',
20299  'utrif': '\u25B4',
20300  'blacktriangledown': '\u25BE',
20301  'dtrif': '\u25BE',
20302  'blacktriangleleft': '\u25C2',
20303  'ltrif': '\u25C2',
20304  'blacktriangleright': '\u25B8',
20305  'rtrif': '\u25B8',
20306  'blank': '\u2423',
20307  'blk12': '\u2592',
20308  'blk14': '\u2591',
20309  'blk34': '\u2593',
20310  'block': '\u2588',
20311  'bne': '\u003D\u20E5',
20312  'bnequiv': '\u2261\u20E5',
20313  'bnot': '\u2310',
20314  'bopf': '\uD835\uDD53',
20315  'bowtie': '\u22C8',
20316  'boxDL': '\u2557',
20317  'boxDR': '\u2554',
20318  'boxDl': '\u2556',
20319  'boxDr': '\u2553',
20320  'boxH': '\u2550',
20321  'boxHD': '\u2566',
20322  'boxHU': '\u2569',
20323  'boxHd': '\u2564',
20324  'boxHu': '\u2567',
20325  'boxUL': '\u255D',
20326  'boxUR': '\u255A',
20327  'boxUl': '\u255C',
20328  'boxUr': '\u2559',
20329  'boxV': '\u2551',
20330  'boxVH': '\u256C',
20331  'boxVL': '\u2563',
20332  'boxVR': '\u2560',
20333  'boxVh': '\u256B',
20334  'boxVl': '\u2562',
20335  'boxVr': '\u255F',
20336  'boxbox': '\u29C9',
20337  'boxdL': '\u2555',
20338  'boxdR': '\u2552',
20339  'boxdl': '\u2510',
20340  'boxdr': '\u250C',
20341  'boxhD': '\u2565',
20342  'boxhU': '\u2568',
20343  'boxhd': '\u252C',
20344  'boxhu': '\u2534',
20345  'boxminus': '\u229F',
20346  'minusb': '\u229F',
20347  'boxplus': '\u229E',
20348  'plusb': '\u229E',
20349  'boxtimes': '\u22A0',
20350  'timesb': '\u22A0',
20351  'boxuL': '\u255B',
20352  'boxuR': '\u2558',
20353  'boxul': '\u2518',
20354  'boxur': '\u2514',
20355  'boxv': '\u2502',
20356  'boxvH': '\u256A',
20357  'boxvL': '\u2561',
20358  'boxvR': '\u255E',
20359  'boxvh': '\u253C',
20360  'boxvl': '\u2524',
20361  'boxvr': '\u251C',
20362  'brvbar': '\u00A6',
20363  'bscr': '\uD835\uDCB7',
20364  'bsemi': '\u204F',
20365  'bsol': '\u005C',
20366  'bsolb': '\u29C5',
20367  'bsolhsub': '\u27C8',
20368  'bull': '\u2022',
20369  'bullet': '\u2022',
20370  'bumpE': '\u2AAE',
20371  'cacute': '\u0107',
20372  'cap': '\u2229',
20373  'capand': '\u2A44',
20374  'capbrcup': '\u2A49',
20375  'capcap': '\u2A4B',
20376  'capcup': '\u2A47',
20377  'capdot': '\u2A40',
20378  'caps': '\u2229\uFE00',
20379  'caret': '\u2041',
20380  'ccaps': '\u2A4D',
20381  'ccaron': '\u010D',
20382  'ccedil': '\u00E7',
20383  'ccirc': '\u0109',
20384  'ccups': '\u2A4C',
20385  'ccupssm': '\u2A50',
20386  'cdot': '\u010B',
20387  'cemptyv': '\u29B2',
20388  'cent': '\u00A2',
20389  'cfr': '\uD835\uDD20',
20390  'chcy': '\u0447',
20391  'check': '\u2713',
20392  'checkmark': '\u2713',
20393  'chi': '\u03C7',
20394  'cir': '\u25CB',
20395  'cirE': '\u29C3',
20396  'circ': '\u02C6',
20397  'circeq': '\u2257',
20398  'cire': '\u2257',
20399  'circlearrowleft': '\u21BA',
20400  'olarr': '\u21BA',
20401  'circlearrowright': '\u21BB',
20402  'orarr': '\u21BB',
20403  'circledS': '\u24C8',
20404  'oS': '\u24C8',
20405  'circledast': '\u229B',
20406  'oast': '\u229B',
20407  'circledcirc': '\u229A',
20408  'ocir': '\u229A',
20409  'circleddash': '\u229D',
20410  'odash': '\u229D',
20411  'cirfnint': '\u2A10',
20412  'cirmid': '\u2AEF',
20413  'cirscir': '\u29C2',
20414  'clubs': '\u2663',
20415  'clubsuit': '\u2663',
20416  'colon': '\u003A',
20417  'comma': '\u002C',
20418  'commat': '\u0040',
20419  'comp': '\u2201',
20420  'complement': '\u2201',
20421  'congdot': '\u2A6D',
20422  'copf': '\uD835\uDD54',
20423  'copysr': '\u2117',
20424  'crarr': '\u21B5',
20425  'cross': '\u2717',
20426  'cscr': '\uD835\uDCB8',
20427  'csub': '\u2ACF',
20428  'csube': '\u2AD1',
20429  'csup': '\u2AD0',
20430  'csupe': '\u2AD2',
20431  'ctdot': '\u22EF',
20432  'cudarrl': '\u2938',
20433  'cudarrr': '\u2935',
20434  'cuepr': '\u22DE',
20435  'curlyeqprec': '\u22DE',
20436  'cuesc': '\u22DF',
20437  'curlyeqsucc': '\u22DF',
20438  'cularr': '\u21B6',
20439  'curvearrowleft': '\u21B6',
20440  'cularrp': '\u293D',
20441  'cup': '\u222A',
20442  'cupbrcap': '\u2A48',
20443  'cupcap': '\u2A46',
20444  'cupcup': '\u2A4A',
20445  'cupdot': '\u228D',
20446  'cupor': '\u2A45',
20447  'cups': '\u222A\uFE00',
20448  'curarr': '\u21B7',
20449  'curvearrowright': '\u21B7',
20450  'curarrm': '\u293C',
20451  'curlyvee': '\u22CE',
20452  'cuvee': '\u22CE',
20453  'curlywedge': '\u22CF',
20454  'cuwed': '\u22CF',
20455  'curren': '\u00A4',
20456  'cwint': '\u2231',
20457  'cylcty': '\u232D',
20458  'dHar': '\u2965',
20459  'dagger': '\u2020',
20460  'daleth': '\u2138',
20461  'dash': '\u2010',
20462  'hyphen': '\u2010',
20463  'dbkarow': '\u290F',
20464  'rBarr': '\u290F',
20465  'dcaron': '\u010F',
20466  'dcy': '\u0434',
20467  'ddarr': '\u21CA',
20468  'downdownarrows': '\u21CA',
20469  'ddotseq': '\u2A77',
20470  'eDDot': '\u2A77',
20471  'deg': '\u00B0',
20472  'delta': '\u03B4',
20473  'demptyv': '\u29B1',
20474  'dfisht': '\u297F',
20475  'dfr': '\uD835\uDD21',
20476  'diamondsuit': '\u2666',
20477  'diams': '\u2666',
20478  'digamma': '\u03DD',
20479  'gammad': '\u03DD',
20480  'disin': '\u22F2',
20481  'div': '\u00F7',
20482  'divide': '\u00F7',
20483  'divideontimes': '\u22C7',
20484  'divonx': '\u22C7',
20485  'djcy': '\u0452',
20486  'dlcorn': '\u231E',
20487  'llcorner': '\u231E',
20488  'dlcrop': '\u230D',
20489  'dollar': '\u0024',
20490  'dopf': '\uD835\uDD55',
20491  'doteqdot': '\u2251',
20492  'eDot': '\u2251',
20493  'dotminus': '\u2238',
20494  'minusd': '\u2238',
20495  'dotplus': '\u2214',
20496  'plusdo': '\u2214',
20497  'dotsquare': '\u22A1',
20498  'sdotb': '\u22A1',
20499  'drcorn': '\u231F',
20500  'lrcorner': '\u231F',
20501  'drcrop': '\u230C',
20502  'dscr': '\uD835\uDCB9',
20503  'dscy': '\u0455',
20504  'dsol': '\u29F6',
20505  'dstrok': '\u0111',
20506  'dtdot': '\u22F1',
20507  'dtri': '\u25BF',
20508  'triangledown': '\u25BF',
20509  'dwangle': '\u29A6',
20510  'dzcy': '\u045F',
20511  'dzigrarr': '\u27FF',
20512  'eacute': '\u00E9',
20513  'easter': '\u2A6E',
20514  'ecaron': '\u011B',
20515  'ecir': '\u2256',
20516  'eqcirc': '\u2256',
20517  'ecirc': '\u00EA',
20518  'ecolon': '\u2255',
20519  'eqcolon': '\u2255',
20520  'ecy': '\u044D',
20521  'edot': '\u0117',
20522  'efDot': '\u2252',
20523  'fallingdotseq': '\u2252',
20524  'efr': '\uD835\uDD22',
20525  'eg': '\u2A9A',
20526  'egrave': '\u00E8',
20527  'egs': '\u2A96',
20528  'eqslantgtr': '\u2A96',
20529  'egsdot': '\u2A98',
20530  'el': '\u2A99',
20531  'elinters': '\u23E7',
20532  'ell': '\u2113',
20533  'els': '\u2A95',
20534  'eqslantless': '\u2A95',
20535  'elsdot': '\u2A97',
20536  'emacr': '\u0113',
20537  'empty': '\u2205',
20538  'emptyset': '\u2205',
20539  'emptyv': '\u2205',
20540  'varnothing': '\u2205',
20541  'emsp13': '\u2004',
20542  'emsp14': '\u2005',
20543  'emsp': '\u2003',
20544  'eng': '\u014B',
20545  'ensp': '\u2002',
20546  'eogon': '\u0119',
20547  'eopf': '\uD835\uDD56',
20548  'epar': '\u22D5',
20549  'eparsl': '\u29E3',
20550  'eplus': '\u2A71',
20551  'epsi': '\u03B5',
20552  'epsilon': '\u03B5',
20553  'epsiv': '\u03F5',
20554  'straightepsilon': '\u03F5',
20555  'varepsilon': '\u03F5',
20556  'equals': '\u003D',
20557  'equest': '\u225F',
20558  'questeq': '\u225F',
20559  'equivDD': '\u2A78',
20560  'eqvparsl': '\u29E5',
20561  'erDot': '\u2253',
20562  'risingdotseq': '\u2253',
20563  'erarr': '\u2971',
20564  'escr': '\u212F',
20565  'eta': '\u03B7',
20566  'eth': '\u00F0',
20567  'euml': '\u00EB',
20568  'euro': '\u20AC',
20569  'excl': '\u0021',
20570  'fcy': '\u0444',
20571  'female': '\u2640',
20572  'ffilig': '\uFB03',
20573  'fflig': '\uFB00',
20574  'ffllig': '\uFB04',
20575  'ffr': '\uD835\uDD23',
20576  'filig': '\uFB01',
20577  'fjlig': '\u0066\u006A',
20578  'flat': '\u266D',
20579  'fllig': '\uFB02',
20580  'fltns': '\u25B1',
20581  'fnof': '\u0192',
20582  'fopf': '\uD835\uDD57',
20583  'fork': '\u22D4',
20584  'pitchfork': '\u22D4',
20585  'forkv': '\u2AD9',
20586  'fpartint': '\u2A0D',
20587  'frac12': '\u00BD',
20588  'half': '\u00BD',
20589  'frac13': '\u2153',
20590  'frac14': '\u00BC',
20591  'frac15': '\u2155',
20592  'frac16': '\u2159',
20593  'frac18': '\u215B',
20594  'frac23': '\u2154',
20595  'frac25': '\u2156',
20596  'frac34': '\u00BE',
20597  'frac35': '\u2157',
20598  'frac38': '\u215C',
20599  'frac45': '\u2158',
20600  'frac56': '\u215A',
20601  'frac58': '\u215D',
20602  'frac78': '\u215E',
20603  'frasl': '\u2044',
20604  'frown': '\u2322',
20605  'sfrown': '\u2322',
20606  'fscr': '\uD835\uDCBB',
20607  'gEl': '\u2A8C',
20608  'gtreqqless': '\u2A8C',
20609  'gacute': '\u01F5',
20610  'gamma': '\u03B3',
20611  'gap': '\u2A86',
20612  'gtrapprox': '\u2A86',
20613  'gbreve': '\u011F',
20614  'gcirc': '\u011D',
20615  'gcy': '\u0433',
20616  'gdot': '\u0121',
20617  'gescc': '\u2AA9',
20618  'gesdot': '\u2A80',
20619  'gesdoto': '\u2A82',
20620  'gesdotol': '\u2A84',
20621  'gesl': '\u22DB\uFE00',
20622  'gesles': '\u2A94',
20623  'gfr': '\uD835\uDD24',
20624  'gimel': '\u2137',
20625  'gjcy': '\u0453',
20626  'glE': '\u2A92',
20627  'gla': '\u2AA5',
20628  'glj': '\u2AA4',
20629  'gnE': '\u2269',
20630  'gneqq': '\u2269',
20631  'gnap': '\u2A8A',
20632  'gnapprox': '\u2A8A',
20633  'gne': '\u2A88',
20634  'gneq': '\u2A88',
20635  'gnsim': '\u22E7',
20636  'gopf': '\uD835\uDD58',
20637  'gscr': '\u210A',
20638  'gsime': '\u2A8E',
20639  'gsiml': '\u2A90',
20640  'gtcc': '\u2AA7',
20641  'gtcir': '\u2A7A',
20642  'gtdot': '\u22D7',
20643  'gtrdot': '\u22D7',
20644  'gtlPar': '\u2995',
20645  'gtquest': '\u2A7C',
20646  'gtrarr': '\u2978',
20647  'gvertneqq': '\u2269\uFE00',
20648  'gvnE': '\u2269\uFE00',
20649  'hardcy': '\u044A',
20650  'harrcir': '\u2948',
20651  'harrw': '\u21AD',
20652  'leftrightsquigarrow': '\u21AD',
20653  'hbar': '\u210F',
20654  'hslash': '\u210F',
20655  'planck': '\u210F',
20656  'plankv': '\u210F',
20657  'hcirc': '\u0125',
20658  'hearts': '\u2665',
20659  'heartsuit': '\u2665',
20660  'hellip': '\u2026',
20661  'mldr': '\u2026',
20662  'hercon': '\u22B9',
20663  'hfr': '\uD835\uDD25',
20664  'hksearow': '\u2925',
20665  'searhk': '\u2925',
20666  'hkswarow': '\u2926',
20667  'swarhk': '\u2926',
20668  'hoarr': '\u21FF',
20669  'homtht': '\u223B',
20670  'hookleftarrow': '\u21A9',
20671  'larrhk': '\u21A9',
20672  'hookrightarrow': '\u21AA',
20673  'rarrhk': '\u21AA',
20674  'hopf': '\uD835\uDD59',
20675  'horbar': '\u2015',
20676  'hscr': '\uD835\uDCBD',
20677  'hstrok': '\u0127',
20678  'hybull': '\u2043',
20679  'iacute': '\u00ED',
20680  'icirc': '\u00EE',
20681  'icy': '\u0438',
20682  'iecy': '\u0435',
20683  'iexcl': '\u00A1',
20684  'ifr': '\uD835\uDD26',
20685  'igrave': '\u00EC',
20686  'iiiint': '\u2A0C',
20687  'qint': '\u2A0C',
20688  'iiint': '\u222D',
20689  'tint': '\u222D',
20690  'iinfin': '\u29DC',
20691  'iiota': '\u2129',
20692  'ijlig': '\u0133',
20693  'imacr': '\u012B',
20694  'imath': '\u0131',
20695  'inodot': '\u0131',
20696  'imof': '\u22B7',
20697  'imped': '\u01B5',
20698  'incare': '\u2105',
20699  'infin': '\u221E',
20700  'infintie': '\u29DD',
20701  'intcal': '\u22BA',
20702  'intercal': '\u22BA',
20703  'intlarhk': '\u2A17',
20704  'intprod': '\u2A3C',
20705  'iprod': '\u2A3C',
20706  'iocy': '\u0451',
20707  'iogon': '\u012F',
20708  'iopf': '\uD835\uDD5A',
20709  'iota': '\u03B9',
20710  'iquest': '\u00BF',
20711  'iscr': '\uD835\uDCBE',
20712  'isinE': '\u22F9',
20713  'isindot': '\u22F5',
20714  'isins': '\u22F4',
20715  'isinsv': '\u22F3',
20716  'itilde': '\u0129',
20717  'iukcy': '\u0456',
20718  'iuml': '\u00EF',
20719  'jcirc': '\u0135',
20720  'jcy': '\u0439',
20721  'jfr': '\uD835\uDD27',
20722  'jmath': '\u0237',
20723  'jopf': '\uD835\uDD5B',
20724  'jscr': '\uD835\uDCBF',
20725  'jsercy': '\u0458',
20726  'jukcy': '\u0454',
20727  'kappa': '\u03BA',
20728  'kappav': '\u03F0',
20729  'varkappa': '\u03F0',
20730  'kcedil': '\u0137',
20731  'kcy': '\u043A',
20732  'kfr': '\uD835\uDD28',
20733  'kgreen': '\u0138',
20734  'khcy': '\u0445',
20735  'kjcy': '\u045C',
20736  'kopf': '\uD835\uDD5C',
20737  'kscr': '\uD835\uDCC0',
20738  'lAtail': '\u291B',
20739  'lBarr': '\u290E',
20740  'lEg': '\u2A8B',
20741  'lesseqqgtr': '\u2A8B',
20742  'lHar': '\u2962',
20743  'lacute': '\u013A',
20744  'laemptyv': '\u29B4',
20745  'lambda': '\u03BB',
20746  'langd': '\u2991',
20747  'lap': '\u2A85',
20748  'lessapprox': '\u2A85',
20749  'laquo': '\u00AB',
20750  'larrbfs': '\u291F',
20751  'larrfs': '\u291D',
20752  'larrlp': '\u21AB',
20753  'looparrowleft': '\u21AB',
20754  'larrpl': '\u2939',
20755  'larrsim': '\u2973',
20756  'larrtl': '\u21A2',
20757  'leftarrowtail': '\u21A2',
20758  'lat': '\u2AAB',
20759  'latail': '\u2919',
20760  'late': '\u2AAD',
20761  'lates': '\u2AAD\uFE00',
20762  'lbarr': '\u290C',
20763  'lbbrk': '\u2772',
20764  'lbrace': '\u007B',
20765  'lcub': '\u007B',
20766  'lbrack': '\u005B',
20767  'lsqb': '\u005B',
20768  'lbrke': '\u298B',
20769  'lbrksld': '\u298F',
20770  'lbrkslu': '\u298D',
20771  'lcaron': '\u013E',
20772  'lcedil': '\u013C',
20773  'lcy': '\u043B',
20774  'ldca': '\u2936',
20775  'ldrdhar': '\u2967',
20776  'ldrushar': '\u294B',
20777  'ldsh': '\u21B2',
20778  'le': '\u2264',
20779  'leq': '\u2264',
20780  'leftleftarrows': '\u21C7',
20781  'llarr': '\u21C7',
20782  'leftthreetimes': '\u22CB',
20783  'lthree': '\u22CB',
20784  'lescc': '\u2AA8',
20785  'lesdot': '\u2A7F',
20786  'lesdoto': '\u2A81',
20787  'lesdotor': '\u2A83',
20788  'lesg': '\u22DA\uFE00',
20789  'lesges': '\u2A93',
20790  'lessdot': '\u22D6',
20791  'ltdot': '\u22D6',
20792  'lfisht': '\u297C',
20793  'lfr': '\uD835\uDD29',
20794  'lgE': '\u2A91',
20795  'lharul': '\u296A',
20796  'lhblk': '\u2584',
20797  'ljcy': '\u0459',
20798  'llhard': '\u296B',
20799  'lltri': '\u25FA',
20800  'lmidot': '\u0140',
20801  'lmoust': '\u23B0',
20802  'lmoustache': '\u23B0',
20803  'lnE': '\u2268',
20804  'lneqq': '\u2268',
20805  'lnap': '\u2A89',
20806  'lnapprox': '\u2A89',
20807  'lne': '\u2A87',
20808  'lneq': '\u2A87',
20809  'lnsim': '\u22E6',
20810  'loang': '\u27EC',
20811  'loarr': '\u21FD',
20812  'longmapsto': '\u27FC',
20813  'xmap': '\u27FC',
20814  'looparrowright': '\u21AC',
20815  'rarrlp': '\u21AC',
20816  'lopar': '\u2985',
20817  'lopf': '\uD835\uDD5D',
20818  'loplus': '\u2A2D',
20819  'lotimes': '\u2A34',
20820  'lowast': '\u2217',
20821  'loz': '\u25CA',
20822  'lozenge': '\u25CA',
20823  'lpar': '\u0028',
20824  'lparlt': '\u2993',
20825  'lrhard': '\u296D',
20826  'lrm': '\u200E',
20827  'lrtri': '\u22BF',
20828  'lsaquo': '\u2039',
20829  'lscr': '\uD835\uDCC1',
20830  'lsime': '\u2A8D',
20831  'lsimg': '\u2A8F',
20832  'lsquor': '\u201A',
20833  'sbquo': '\u201A',
20834  'lstrok': '\u0142',
20835  'ltcc': '\u2AA6',
20836  'ltcir': '\u2A79',
20837  'ltimes': '\u22C9',
20838  'ltlarr': '\u2976',
20839  'ltquest': '\u2A7B',
20840  'ltrPar': '\u2996',
20841  'ltri': '\u25C3',
20842  'triangleleft': '\u25C3',
20843  'lurdshar': '\u294A',
20844  'luruhar': '\u2966',
20845  'lvertneqq': '\u2268\uFE00',
20846  'lvnE': '\u2268\uFE00',
20847  'mDDot': '\u223A',
20848  'macr': '\u00AF',
20849  'strns': '\u00AF',
20850  'male': '\u2642',
20851  'malt': '\u2720',
20852  'maltese': '\u2720',
20853  'marker': '\u25AE',
20854  'mcomma': '\u2A29',
20855  'mcy': '\u043C',
20856  'mdash': '\u2014',
20857  'mfr': '\uD835\uDD2A',
20858  'mho': '\u2127',
20859  'micro': '\u00B5',
20860  'midcir': '\u2AF0',
20861  'minus': '\u2212',
20862  'minusdu': '\u2A2A',
20863  'mlcp': '\u2ADB',
20864  'models': '\u22A7',
20865  'mopf': '\uD835\uDD5E',
20866  'mscr': '\uD835\uDCC2',
20867  'mu': '\u03BC',
20868  'multimap': '\u22B8',
20869  'mumap': '\u22B8',
20870  'nGg': '\u22D9\u0338',
20871  'nGt': '\u226B\u20D2',
20872  'nLeftarrow': '\u21CD',
20873  'nlArr': '\u21CD',
20874  'nLeftrightarrow': '\u21CE',
20875  'nhArr': '\u21CE',
20876  'nLl': '\u22D8\u0338',
20877  'nLt': '\u226A\u20D2',
20878  'nRightarrow': '\u21CF',
20879  'nrArr': '\u21CF',
20880  'nVDash': '\u22AF',
20881  'nVdash': '\u22AE',
20882  'nacute': '\u0144',
20883  'nang': '\u2220\u20D2',
20884  'napE': '\u2A70\u0338',
20885  'napid': '\u224B\u0338',
20886  'napos': '\u0149',
20887  'natur': '\u266E',
20888  'natural': '\u266E',
20889  'ncap': '\u2A43',
20890  'ncaron': '\u0148',
20891  'ncedil': '\u0146',
20892  'ncongdot': '\u2A6D\u0338',
20893  'ncup': '\u2A42',
20894  'ncy': '\u043D',
20895  'ndash': '\u2013',
20896  'neArr': '\u21D7',
20897  'nearhk': '\u2924',
20898  'nedot': '\u2250\u0338',
20899  'nesear': '\u2928',
20900  'toea': '\u2928',
20901  'nfr': '\uD835\uDD2B',
20902  'nharr': '\u21AE',
20903  'nleftrightarrow': '\u21AE',
20904  'nhpar': '\u2AF2',
20905  'nis': '\u22FC',
20906  'nisd': '\u22FA',
20907  'njcy': '\u045A',
20908  'nlE': '\u2266\u0338',
20909  'nleqq': '\u2266\u0338',
20910  'nlarr': '\u219A',
20911  'nleftarrow': '\u219A',
20912  'nldr': '\u2025',
20913  'nopf': '\uD835\uDD5F',
20914  'not': '\u00AC',
20915  'notinE': '\u22F9\u0338',
20916  'notindot': '\u22F5\u0338',
20917  'notinvb': '\u22F7',
20918  'notinvc': '\u22F6',
20919  'notnivb': '\u22FE',
20920  'notnivc': '\u22FD',
20921  'nparsl': '\u2AFD\u20E5',
20922  'npart': '\u2202\u0338',
20923  'npolint': '\u2A14',
20924  'nrarr': '\u219B',
20925  'nrightarrow': '\u219B',
20926  'nrarrc': '\u2933\u0338',
20927  'nrarrw': '\u219D\u0338',
20928  'nscr': '\uD835\uDCC3',
20929  'nsub': '\u2284',
20930  'nsubE': '\u2AC5\u0338',
20931  'nsubseteqq': '\u2AC5\u0338',
20932  'nsup': '\u2285',
20933  'nsupE': '\u2AC6\u0338',
20934  'nsupseteqq': '\u2AC6\u0338',
20935  'ntilde': '\u00F1',
20936  'nu': '\u03BD',
20937  'num': '\u0023',
20938  'numero': '\u2116',
20939  'numsp': '\u2007',
20940  'nvDash': '\u22AD',
20941  'nvHarr': '\u2904',
20942  'nvap': '\u224D\u20D2',
20943  'nvdash': '\u22AC',
20944  'nvge': '\u2265\u20D2',
20945  'nvgt': '\u003E\u20D2',
20946  'nvinfin': '\u29DE',
20947  'nvlArr': '\u2902',
20948  'nvle': '\u2264\u20D2',
20949  'nvlt': '\u003C\u20D2',
20950  'nvltrie': '\u22B4\u20D2',
20951  'nvrArr': '\u2903',
20952  'nvrtrie': '\u22B5\u20D2',
20953  'nvsim': '\u223C\u20D2',
20954  'nwArr': '\u21D6',
20955  'nwarhk': '\u2923',
20956  'nwnear': '\u2927',
20957  'oacute': '\u00F3',
20958  'ocirc': '\u00F4',
20959  'ocy': '\u043E',
20960  'odblac': '\u0151',
20961  'odiv': '\u2A38',
20962  'odsold': '\u29BC',
20963  'oelig': '\u0153',
20964  'ofcir': '\u29BF',
20965  'ofr': '\uD835\uDD2C',
20966  'ogon': '\u02DB',
20967  'ograve': '\u00F2',
20968  'ogt': '\u29C1',
20969  'ohbar': '\u29B5',
20970  'olcir': '\u29BE',
20971  'olcross': '\u29BB',
20972  'olt': '\u29C0',
20973  'omacr': '\u014D',
20974  'omega': '\u03C9',
20975  'omicron': '\u03BF',
20976  'omid': '\u29B6',
20977  'oopf': '\uD835\uDD60',
20978  'opar': '\u29B7',
20979  'operp': '\u29B9',
20980  'or': '\u2228',
20981  'vee': '\u2228',
20982  'ord': '\u2A5D',
20983  'order': '\u2134',
20984  'orderof': '\u2134',
20985  'oscr': '\u2134',
20986  'ordf': '\u00AA',
20987  'ordm': '\u00BA',
20988  'origof': '\u22B6',
20989  'oror': '\u2A56',
20990  'orslope': '\u2A57',
20991  'orv': '\u2A5B',
20992  'oslash': '\u00F8',
20993  'osol': '\u2298',
20994  'otilde': '\u00F5',
20995  'otimesas': '\u2A36',
20996  'ouml': '\u00F6',
20997  'ovbar': '\u233D',
20998  'para': '\u00B6',
20999  'parsim': '\u2AF3',
21000  'parsl': '\u2AFD',
21001  'pcy': '\u043F',
21002  'percnt': '\u0025',
21003  'period': '\u002E',
21004  'permil': '\u2030',
21005  'pertenk': '\u2031',
21006  'pfr': '\uD835\uDD2D',
21007  'phi': '\u03C6',
21008  'phiv': '\u03D5',
21009  'straightphi': '\u03D5',
21010  'varphi': '\u03D5',
21011  'phone': '\u260E',
21012  'pi': '\u03C0',
21013  'piv': '\u03D6',
21014  'varpi': '\u03D6',
21015  'planckh': '\u210E',
21016  'plus': '\u002B',
21017  'plusacir': '\u2A23',
21018  'pluscir': '\u2A22',
21019  'plusdu': '\u2A25',
21020  'pluse': '\u2A72',
21021  'plussim': '\u2A26',
21022  'plustwo': '\u2A27',
21023  'pointint': '\u2A15',
21024  'popf': '\uD835\uDD61',
21025  'pound': '\u00A3',
21026  'prE': '\u2AB3',
21027  'prap': '\u2AB7',
21028  'precapprox': '\u2AB7',
21029  'precnapprox': '\u2AB9',
21030  'prnap': '\u2AB9',
21031  'precneqq': '\u2AB5',
21032  'prnE': '\u2AB5',
21033  'precnsim': '\u22E8',
21034  'prnsim': '\u22E8',
21035  'prime': '\u2032',
21036  'profalar': '\u232E',
21037  'profline': '\u2312',
21038  'profsurf': '\u2313',
21039  'prurel': '\u22B0',
21040  'pscr': '\uD835\uDCC5',
21041  'psi': '\u03C8',
21042  'puncsp': '\u2008',
21043  'qfr': '\uD835\uDD2E',
21044  'qopf': '\uD835\uDD62',
21045  'qprime': '\u2057',
21046  'qscr': '\uD835\uDCC6',
21047  'quatint': '\u2A16',
21048  'quest': '\u003F',
21049  'rAtail': '\u291C',
21050  'rHar': '\u2964',
21051  'race': '\u223D\u0331',
21052  'racute': '\u0155',
21053  'raemptyv': '\u29B3',
21054  'rangd': '\u2992',
21055  'range': '\u29A5',
21056  'raquo': '\u00BB',
21057  'rarrap': '\u2975',
21058  'rarrbfs': '\u2920',
21059  'rarrc': '\u2933',
21060  'rarrfs': '\u291E',
21061  'rarrpl': '\u2945',
21062  'rarrsim': '\u2974',
21063  'rarrtl': '\u21A3',
21064  'rightarrowtail': '\u21A3',
21065  'rarrw': '\u219D',
21066  'rightsquigarrow': '\u219D',
21067  'ratail': '\u291A',
21068  'ratio': '\u2236',
21069  'rbbrk': '\u2773',
21070  'rbrace': '\u007D',
21071  'rcub': '\u007D',
21072  'rbrack': '\u005D',
21073  'rsqb': '\u005D',
21074  'rbrke': '\u298C',
21075  'rbrksld': '\u298E',
21076  'rbrkslu': '\u2990',
21077  'rcaron': '\u0159',
21078  'rcedil': '\u0157',
21079  'rcy': '\u0440',
21080  'rdca': '\u2937',
21081  'rdldhar': '\u2969',
21082  'rdsh': '\u21B3',
21083  'rect': '\u25AD',
21084  'rfisht': '\u297D',
21085  'rfr': '\uD835\uDD2F',
21086  'rharul': '\u296C',
21087  'rho': '\u03C1',
21088  'rhov': '\u03F1',
21089  'varrho': '\u03F1',
21090  'rightrightarrows': '\u21C9',
21091  'rrarr': '\u21C9',
21092  'rightthreetimes': '\u22CC',
21093  'rthree': '\u22CC',
21094  'ring': '\u02DA',
21095  'rlm': '\u200F',
21096  'rmoust': '\u23B1',
21097  'rmoustache': '\u23B1',
21098  'rnmid': '\u2AEE',
21099  'roang': '\u27ED',
21100  'roarr': '\u21FE',
21101  'ropar': '\u2986',
21102  'ropf': '\uD835\uDD63',
21103  'roplus': '\u2A2E',
21104  'rotimes': '\u2A35',
21105  'rpar': '\u0029',
21106  'rpargt': '\u2994',
21107  'rppolint': '\u2A12',
21108  'rsaquo': '\u203A',
21109  'rscr': '\uD835\uDCC7',
21110  'rtimes': '\u22CA',
21111  'rtri': '\u25B9',
21112  'triangleright': '\u25B9',
21113  'rtriltri': '\u29CE',
21114  'ruluhar': '\u2968',
21115  'rx': '\u211E',
21116  'sacute': '\u015B',
21117  'scE': '\u2AB4',
21118  'scap': '\u2AB8',
21119  'succapprox': '\u2AB8',
21120  'scaron': '\u0161',
21121  'scedil': '\u015F',
21122  'scirc': '\u015D',
21123  'scnE': '\u2AB6',
21124  'succneqq': '\u2AB6',
21125  'scnap': '\u2ABA',
21126  'succnapprox': '\u2ABA',
21127  'scnsim': '\u22E9',
21128  'succnsim': '\u22E9',
21129  'scpolint': '\u2A13',
21130  'scy': '\u0441',
21131  'sdot': '\u22C5',
21132  'sdote': '\u2A66',
21133  'seArr': '\u21D8',
21134  'sect': '\u00A7',
21135  'semi': '\u003B',
21136  'seswar': '\u2929',
21137  'tosa': '\u2929',
21138  'sext': '\u2736',
21139  'sfr': '\uD835\uDD30',
21140  'sharp': '\u266F',
21141  'shchcy': '\u0449',
21142  'shcy': '\u0448',
21143  'shy': '\u00AD',
21144  'sigma': '\u03C3',
21145  'sigmaf': '\u03C2',
21146  'sigmav': '\u03C2',
21147  'varsigma': '\u03C2',
21148  'simdot': '\u2A6A',
21149  'simg': '\u2A9E',
21150  'simgE': '\u2AA0',
21151  'siml': '\u2A9D',
21152  'simlE': '\u2A9F',
21153  'simne': '\u2246',
21154  'simplus': '\u2A24',
21155  'simrarr': '\u2972',
21156  'smashp': '\u2A33',
21157  'smeparsl': '\u29E4',
21158  'smile': '\u2323',
21159  'ssmile': '\u2323',
21160  'smt': '\u2AAA',
21161  'smte': '\u2AAC',
21162  'smtes': '\u2AAC\uFE00',
21163  'softcy': '\u044C',
21164  'sol': '\u002F',
21165  'solb': '\u29C4',
21166  'solbar': '\u233F',
21167  'sopf': '\uD835\uDD64',
21168  'spades': '\u2660',
21169  'spadesuit': '\u2660',
21170  'sqcaps': '\u2293\uFE00',
21171  'sqcups': '\u2294\uFE00',
21172  'sscr': '\uD835\uDCC8',
21173  'star': '\u2606',
21174  'sub': '\u2282',
21175  'subset': '\u2282',
21176  'subE': '\u2AC5',
21177  'subseteqq': '\u2AC5',
21178  'subdot': '\u2ABD',
21179  'subedot': '\u2AC3',
21180  'submult': '\u2AC1',
21181  'subnE': '\u2ACB',
21182  'subsetneqq': '\u2ACB',
21183  'subne': '\u228A',
21184  'subsetneq': '\u228A',
21185  'subplus': '\u2ABF',
21186  'subrarr': '\u2979',
21187  'subsim': '\u2AC7',
21188  'subsub': '\u2AD5',
21189  'subsup': '\u2AD3',
21190  'sung': '\u266A',
21191  'sup1': '\u00B9',
21192  'sup2': '\u00B2',
21193  'sup3': '\u00B3',
21194  'supE': '\u2AC6',
21195  'supseteqq': '\u2AC6',
21196  'supdot': '\u2ABE',
21197  'supdsub': '\u2AD8',
21198  'supedot': '\u2AC4',
21199  'suphsol': '\u27C9',
21200  'suphsub': '\u2AD7',
21201  'suplarr': '\u297B',
21202  'supmult': '\u2AC2',
21203  'supnE': '\u2ACC',
21204  'supsetneqq': '\u2ACC',
21205  'supne': '\u228B',
21206  'supsetneq': '\u228B',
21207  'supplus': '\u2AC0',
21208  'supsim': '\u2AC8',
21209  'supsub': '\u2AD4',
21210  'supsup': '\u2AD6',
21211  'swArr': '\u21D9',
21212  'swnwar': '\u292A',
21213  'szlig': '\u00DF',
21214  'target': '\u2316',
21215  'tau': '\u03C4',
21216  'tcaron': '\u0165',
21217  'tcedil': '\u0163',
21218  'tcy': '\u0442',
21219  'telrec': '\u2315',
21220  'tfr': '\uD835\uDD31',
21221  'theta': '\u03B8',
21222  'thetasym': '\u03D1',
21223  'thetav': '\u03D1',
21224  'vartheta': '\u03D1',
21225  'thorn': '\u00FE',
21226  'times': '\u00D7',
21227  'timesbar': '\u2A31',
21228  'timesd': '\u2A30',
21229  'topbot': '\u2336',
21230  'topcir': '\u2AF1',
21231  'topf': '\uD835\uDD65',
21232  'topfork': '\u2ADA',
21233  'tprime': '\u2034',
21234  'triangle': '\u25B5',
21235  'utri': '\u25B5',
21236  'triangleq': '\u225C',
21237  'trie': '\u225C',
21238  'tridot': '\u25EC',
21239  'triminus': '\u2A3A',
21240  'triplus': '\u2A39',
21241  'trisb': '\u29CD',
21242  'tritime': '\u2A3B',
21243  'trpezium': '\u23E2',
21244  'tscr': '\uD835\uDCC9',
21245  'tscy': '\u0446',
21246  'tshcy': '\u045B',
21247  'tstrok': '\u0167',
21248  'uHar': '\u2963',
21249  'uacute': '\u00FA',
21250  'ubrcy': '\u045E',
21251  'ubreve': '\u016D',
21252  'ucirc': '\u00FB',
21253  'ucy': '\u0443',
21254  'udblac': '\u0171',
21255  'ufisht': '\u297E',
21256  'ufr': '\uD835\uDD32',
21257  'ugrave': '\u00F9',
21258  'uhblk': '\u2580',
21259  'ulcorn': '\u231C',
21260  'ulcorner': '\u231C',
21261  'ulcrop': '\u230F',
21262  'ultri': '\u25F8',
21263  'umacr': '\u016B',
21264  'uogon': '\u0173',
21265  'uopf': '\uD835\uDD66',
21266  'upsi': '\u03C5',
21267  'upsilon': '\u03C5',
21268  'upuparrows': '\u21C8',
21269  'uuarr': '\u21C8',
21270  'urcorn': '\u231D',
21271  'urcorner': '\u231D',
21272  'urcrop': '\u230E',
21273  'uring': '\u016F',
21274  'urtri': '\u25F9',
21275  'uscr': '\uD835\uDCCA',
21276  'utdot': '\u22F0',
21277  'utilde': '\u0169',
21278  'uuml': '\u00FC',
21279  'uwangle': '\u29A7',
21280  'vBar': '\u2AE8',
21281  'vBarv': '\u2AE9',
21282  'vangrt': '\u299C',
21283  'varsubsetneq': '\u228A\uFE00',
21284  'vsubne': '\u228A\uFE00',
21285  'varsubsetneqq': '\u2ACB\uFE00',
21286  'vsubnE': '\u2ACB\uFE00',
21287  'varsupsetneq': '\u228B\uFE00',
21288  'vsupne': '\u228B\uFE00',
21289  'varsupsetneqq': '\u2ACC\uFE00',
21290  'vsupnE': '\u2ACC\uFE00',
21291  'vcy': '\u0432',
21292  'veebar': '\u22BB',
21293  'veeeq': '\u225A',
21294  'vellip': '\u22EE',
21295  'vfr': '\uD835\uDD33',
21296  'vopf': '\uD835\uDD67',
21297  'vscr': '\uD835\uDCCB',
21298  'vzigzag': '\u299A',
21299  'wcirc': '\u0175',
21300  'wedbar': '\u2A5F',
21301  'wedgeq': '\u2259',
21302  'weierp': '\u2118',
21303  'wp': '\u2118',
21304  'wfr': '\uD835\uDD34',
21305  'wopf': '\uD835\uDD68',
21306  'wscr': '\uD835\uDCCC',
21307  'xfr': '\uD835\uDD35',
21308  'xi': '\u03BE',
21309  'xnis': '\u22FB',
21310  'xopf': '\uD835\uDD69',
21311  'xscr': '\uD835\uDCCD',
21312  'yacute': '\u00FD',
21313  'yacy': '\u044F',
21314  'ycirc': '\u0177',
21315  'ycy': '\u044B',
21316  'yen': '\u00A5',
21317  'yfr': '\uD835\uDD36',
21318  'yicy': '\u0457',
21319  'yopf': '\uD835\uDD6A',
21320  'yscr': '\uD835\uDCCE',
21321  'yucy': '\u044E',
21322  'yuml': '\u00FF',
21323  'zacute': '\u017A',
21324  'zcaron': '\u017E',
21325  'zcy': '\u0437',
21326  'zdot': '\u017C',
21327  'zeta': '\u03B6',
21328  'zfr': '\uD835\uDD37',
21329  'zhcy': '\u0436',
21330  'zigrarr': '\u21DD',
21331  'zopf': '\uD835\uDD6B',
21332  'zscr': '\uD835\uDCCF',
21333  'zwj': '\u200D',
21334  'zwnj': '\u200C'
21335};
21336// The &ngsp; pseudo-entity is denoting a space.
21337// 0xE500 is a PUA (Private Use Areas) unicode character
21338// This is inspired by the Angular Dart implementation.
21339const NGSP_UNICODE = '\uE500';
21340NAMED_ENTITIES['ngsp'] = NGSP_UNICODE;
21341class TokenError extends ParseError {
21342  constructor(errorMsg, tokenType, span) {
21343    super(span, errorMsg);
21344    this.tokenType = tokenType;
21345  }
21346}
21347class TokenizeResult {
21348  constructor(tokens, errors, nonNormalizedIcuExpressions) {
21349    this.tokens = tokens;
21350    this.errors = errors;
21351    this.nonNormalizedIcuExpressions = nonNormalizedIcuExpressions;
21352  }
21353}
21354function tokenize(source, url, getTagDefinition, options = {}) {
21355  const tokenizer = new _Tokenizer(new ParseSourceFile(source, url), getTagDefinition, options);
21356  tokenizer.tokenize();
21357  return new TokenizeResult(mergeTextTokens(tokenizer.tokens), tokenizer.errors, tokenizer.nonNormalizedIcuExpressions);
21358}
21359const _CR_OR_CRLF_REGEXP = /\r\n?/g;
21360function _unexpectedCharacterErrorMsg(charCode) {
21361  const char = charCode === $EOF ? 'EOF' : String.fromCharCode(charCode);
21362  return `Unexpected character "${char}"`;
21363}
21364function _unknownEntityErrorMsg(entitySrc) {
21365  return `Unknown entity "${entitySrc}" - use the "&#<decimal>;" or  "&#x<hex>;" syntax`;
21366}
21367function _unparsableEntityErrorMsg(type, entityStr) {
21368  return `Unable to parse entity "${entityStr}" - ${type} character reference entities must end with ";"`;
21369}
21370var CharacterReferenceType;
21371(function (CharacterReferenceType) {
21372  CharacterReferenceType["HEX"] = "hexadecimal";
21373  CharacterReferenceType["DEC"] = "decimal";
21374})(CharacterReferenceType || (CharacterReferenceType = {}));
21375class _ControlFlowError {
21376  constructor(error) {
21377    this.error = error;
21378  }
21379}
21380// See https://www.w3.org/TR/html51/syntax.html#writing-html-documents
21381class _Tokenizer {
21382  /**
21383   * @param _file The html source file being tokenized.
21384   * @param _getTagDefinition A function that will retrieve a tag definition for a given tag name.
21385   * @param options Configuration of the tokenization.
21386   */
21387  constructor(_file, _getTagDefinition, options) {
21388    this._getTagDefinition = _getTagDefinition;
21389    this._currentTokenStart = null;
21390    this._currentTokenType = null;
21391    this._expansionCaseStack = [];
21392    this._inInterpolation = false;
21393    this.tokens = [];
21394    this.errors = [];
21395    this.nonNormalizedIcuExpressions = [];
21396    this._tokenizeIcu = options.tokenizeExpansionForms || false;
21397    this._interpolationConfig = options.interpolationConfig || DEFAULT_INTERPOLATION_CONFIG;
21398    this._leadingTriviaCodePoints = options.leadingTriviaChars && options.leadingTriviaChars.map(c => c.codePointAt(0) || 0);
21399    const range = options.range || {
21400      endPos: _file.content.length,
21401      startPos: 0,
21402      startLine: 0,
21403      startCol: 0
21404    };
21405    this._cursor = options.escapedString ? new EscapedCharacterCursor(_file, range) : new PlainCharacterCursor(_file, range);
21406    this._preserveLineEndings = options.preserveLineEndings || false;
21407    this._i18nNormalizeLineEndingsInICUs = options.i18nNormalizeLineEndingsInICUs || false;
21408    this._tokenizeBlocks = options.tokenizeBlocks ?? true;
21409    try {
21410      this._cursor.init();
21411    } catch (e) {
21412      this.handleError(e);
21413    }
21414  }
21415  _processCarriageReturns(content) {
21416    if (this._preserveLineEndings) {
21417      return content;
21418    }
21419    // https://www.w3.org/TR/html51/syntax.html#preprocessing-the-input-stream
21420    // In order to keep the original position in the source, we can not
21421    // pre-process it.
21422    // Instead CRs are processed right before instantiating the tokens.
21423    return content.replace(_CR_OR_CRLF_REGEXP, '\n');
21424  }
21425  tokenize() {
21426    while (this._cursor.peek() !== $EOF) {
21427      const start = this._cursor.clone();
21428      try {
21429        if (this._attemptCharCode($LT)) {
21430          if (this._attemptCharCode($BANG)) {
21431            if (this._attemptCharCode($LBRACKET)) {
21432              this._consumeCdata(start);
21433            } else if (this._attemptCharCode($MINUS)) {
21434              this._consumeComment(start);
21435            } else {
21436              this._consumeDocType(start);
21437            }
21438          } else if (this._attemptCharCode($SLASH)) {
21439            this._consumeTagClose(start);
21440          } else {
21441            this._consumeTagOpen(start);
21442          }
21443        } else if (this._tokenizeBlocks && this._attemptCharCode($AT)) {
21444          this._consumeBlockStart(start);
21445        } else if (this._tokenizeBlocks && !this._inInterpolation && !this._isInExpansionCase() && !this._isInExpansionForm() && this._attemptCharCode($RBRACE)) {
21446          this._consumeBlockEnd(start);
21447        } else if (!(this._tokenizeIcu && this._tokenizeExpansionForm())) {
21448          // In (possibly interpolated) text the end of the text is given by `isTextEnd()`, while
21449          // the premature end of an interpolation is given by the start of a new HTML element.
21450          this._consumeWithInterpolation(5 /* TokenType.TEXT */, 8 /* TokenType.INTERPOLATION */, () => this._isTextEnd(), () => this._isTagStart());
21451        }
21452      } catch (e) {
21453        this.handleError(e);
21454      }
21455    }
21456    this._beginToken(29 /* TokenType.EOF */);
21457    this._endToken([]);
21458  }
21459  _getBlockName() {
21460    // This allows us to capture up something like `@else if`, but not `@ if`.
21461    let spacesInNameAllowed = false;
21462    const nameCursor = this._cursor.clone();
21463    this._attemptCharCodeUntilFn(code => {
21464      if (isWhitespace(code)) {
21465        return !spacesInNameAllowed;
21466      }
21467      if (isBlockNameChar(code)) {
21468        spacesInNameAllowed = true;
21469        return false;
21470      }
21471      return true;
21472    });
21473    return this._cursor.getChars(nameCursor).trim();
21474  }
21475  _consumeBlockStart(start) {
21476    this._beginToken(24 /* TokenType.BLOCK_OPEN_START */, start);
21477    const startToken = this._endToken([this._getBlockName()]);
21478    if (this._cursor.peek() === $LPAREN) {
21479      // Advance past the opening paren.
21480      this._cursor.advance();
21481      // Capture the parameters.
21482      this._consumeBlockParameters();
21483      // Allow spaces before the closing paren.
21484      this._attemptCharCodeUntilFn(isNotWhitespace);
21485      if (this._attemptCharCode($RPAREN)) {
21486        // Allow spaces after the paren.
21487        this._attemptCharCodeUntilFn(isNotWhitespace);
21488      } else {
21489        startToken.type = 28 /* TokenType.INCOMPLETE_BLOCK_OPEN */;
21490        return;
21491      }
21492    }
21493    if (this._attemptCharCode($LBRACE)) {
21494      this._beginToken(25 /* TokenType.BLOCK_OPEN_END */);
21495      this._endToken([]);
21496    } else {
21497      startToken.type = 28 /* TokenType.INCOMPLETE_BLOCK_OPEN */;
21498    }
21499  }
21500  _consumeBlockEnd(start) {
21501    this._beginToken(26 /* TokenType.BLOCK_CLOSE */, start);
21502    this._endToken([]);
21503  }
21504  _consumeBlockParameters() {
21505    // Trim the whitespace until the first parameter.
21506    this._attemptCharCodeUntilFn(isBlockParameterChar);
21507    while (this._cursor.peek() !== $RPAREN && this._cursor.peek() !== $EOF) {
21508      this._beginToken(27 /* TokenType.BLOCK_PARAMETER */);
21509      const start = this._cursor.clone();
21510      let inQuote = null;
21511      let openParens = 0;
21512      // Consume the parameter until the next semicolon or brace.
21513      // Note that we skip over semicolons/braces inside of strings.
21514      while (this._cursor.peek() !== $SEMICOLON && this._cursor.peek() !== $EOF || inQuote !== null) {
21515        const char = this._cursor.peek();
21516        // Skip to the next character if it was escaped.
21517        if (char === $BACKSLASH) {
21518          this._cursor.advance();
21519        } else if (char === inQuote) {
21520          inQuote = null;
21521        } else if (inQuote === null && isQuote(char)) {
21522          inQuote = char;
21523        } else if (char === $LPAREN && inQuote === null) {
21524          openParens++;
21525        } else if (char === $RPAREN && inQuote === null) {
21526          if (openParens === 0) {
21527            break;
21528          } else if (openParens > 0) {
21529            openParens--;
21530          }
21531        }
21532        this._cursor.advance();
21533      }
21534      this._endToken([this._cursor.getChars(start)]);
21535      // Skip to the next parameter.
21536      this._attemptCharCodeUntilFn(isBlockParameterChar);
21537    }
21538  }
21539  /**
21540   * @returns whether an ICU token has been created
21541   * @internal
21542   */
21543  _tokenizeExpansionForm() {
21544    if (this.isExpansionFormStart()) {
21545      this._consumeExpansionFormStart();
21546      return true;
21547    }
21548    if (isExpansionCaseStart(this._cursor.peek()) && this._isInExpansionForm()) {
21549      this._consumeExpansionCaseStart();
21550      return true;
21551    }
21552    if (this._cursor.peek() === $RBRACE) {
21553      if (this._isInExpansionCase()) {
21554        this._consumeExpansionCaseEnd();
21555        return true;
21556      }
21557      if (this._isInExpansionForm()) {
21558        this._consumeExpansionFormEnd();
21559        return true;
21560      }
21561    }
21562    return false;
21563  }
21564  _beginToken(type, start = this._cursor.clone()) {
21565    this._currentTokenStart = start;
21566    this._currentTokenType = type;
21567  }
21568  _endToken(parts, end) {
21569    if (this._currentTokenStart === null) {
21570      throw new TokenError('Programming error - attempted to end a token when there was no start to the token', this._currentTokenType, this._cursor.getSpan(end));
21571    }
21572    if (this._currentTokenType === null) {
21573      throw new TokenError('Programming error - attempted to end a token which has no token type', null, this._cursor.getSpan(this._currentTokenStart));
21574    }
21575    const token = {
21576      type: this._currentTokenType,
21577      parts,
21578      sourceSpan: (end ?? this._cursor).getSpan(this._currentTokenStart, this._leadingTriviaCodePoints)
21579    };
21580    this.tokens.push(token);
21581    this._currentTokenStart = null;
21582    this._currentTokenType = null;
21583    return token;
21584  }
21585  _createError(msg, span) {
21586    if (this._isInExpansionForm()) {
21587      msg += ` (Do you have an unescaped "{" in your template? Use "{{ '{' }}") to escape it.)`;
21588    }
21589    const error = new TokenError(msg, this._currentTokenType, span);
21590    this._currentTokenStart = null;
21591    this._currentTokenType = null;
21592    return new _ControlFlowError(error);
21593  }
21594  handleError(e) {
21595    if (e instanceof CursorError) {
21596      e = this._createError(e.msg, this._cursor.getSpan(e.cursor));
21597    }
21598    if (e instanceof _ControlFlowError) {
21599      this.errors.push(e.error);
21600    } else {
21601      throw e;
21602    }
21603  }
21604  _attemptCharCode(charCode) {
21605    if (this._cursor.peek() === charCode) {
21606      this._cursor.advance();
21607      return true;
21608    }
21609    return false;
21610  }
21611  _attemptCharCodeCaseInsensitive(charCode) {
21612    if (compareCharCodeCaseInsensitive(this._cursor.peek(), charCo
21612de)) {
21613      this._cursor.advance();
21614      return true;
21615    }
21616    return false;
21617  }
21618  _requireCharCode(charCode) {
21619    const location = this._cursor.clone();
21620    if (!this._attemptCharCode(charCode)) {
21621      throw this._createError(_unexpectedCharacterErrorMsg(this._cursor.peek()), this._cursor.getSpan(location));
21622    }
21623  }
21624  _attemptStr(chars) {
21625    const len = chars.length;
21626    if (this._cursor.charsLeft() < len) {
21627      return false;
21628    }
21629    const initialPosition = this._cursor.clone();
21630    for (let i = 0; i < len; i++) {
21631      if (!this._attemptCharCode(chars.charCodeAt(i))) {
21632        // If attempting to parse the string fails, we want to reset the parser
21633        // to where it was before the attempt
21634        this._cursor = initialPosition;
21635        return false;
21636      }
21637    }
21638    return true;
21639  }
21640  _attemptStrCaseInsensitive(chars) {
21641    for (let i = 0; i < chars.length; i++) {
21642      if (!this._attemptCharCodeCaseInsensitive(chars.charCodeAt(i))) {
21643        return false;
21644      }
21645    }
21646    return true;
21647  }
21648  _requireStr(chars) {
21649    const location = this._cursor.clone();
21650    if (!this._attemptStr(chars)) {
21651      throw this._createError(_unexpectedCharacterErrorMsg(this._cursor.peek()), this._cursor.getSpan(location));
21652    }
21653  }
21654  _attemptCharCodeUntilFn(predicate) {
21655    while (!predicate(this._cursor.peek())) {
21656      this._cursor.advance();
21657    }
21658  }
21659  _requireCharCodeUntilFn(predicate, len) {
21660    const start = this._cursor.clone();
21661    this._attemptCharCodeUntilFn(predicate);
21662    if (this._cursor.diff(start) < len) {
21663      throw this._createError(_unexpectedCharacterErrorMsg(this._cursor.peek()), this._cursor.getSpan(start));
21664    }
21665  }
21666  _attemptUntilChar(char) {
21667    while (this._cursor.peek() !== char) {
21668      this._cursor.advance();
21669    }
21670  }
21671  _readChar() {
21672    // Don't rely upon reading directly from `_input` as the actual char value
21673    // may have been generated from an escape sequence.
21674    const char = String.fromCodePoint(this._cursor.peek());
21675    this._cursor.advance();
21676    return char;
21677  }
21678  _consumeEntity(textTokenType) {
21679    this._beginToken(9 /* TokenType.ENCODED_ENTITY */);
21680    const start = this._cursor.clone();
21681    this._cursor.advance();
21682    if (this._attemptCharCode($HASH)) {
21683      const isHex = this._attemptCharCode($x) || this._attemptCharCode($X);
21684      const codeStart = this._cursor.clone();
21685      this._attemptCharCodeUntilFn(isDigitEntityEnd);
21686      if (this._cursor.peek() != $SEMICOLON) {
21687        // Advance cursor to include the peeked character in the string provided to the error
21688        // message.
21689        this._cursor.advance();
21690        const entityType = isHex ? CharacterReferenceType.HEX : CharacterReferenceType.DEC;
21691        throw this._createError(_unparsableEntityErrorMsg(entityType, this._cursor.getChars(start)), this._cursor.getSpan());
21692      }
21693      const strNum = this._cursor.getChars(codeStart);
21694      this._cursor.advance();
21695      try {
21696        const charCode = parseInt(strNum, isHex ? 16 : 10);
21697        this._endToken([String.fromCharCode(charCode), this._cursor.getChars(start)]);
21698      } catch {
21699        throw this._createError(_unknownEntityErrorMsg(this._cursor.getChars(start)), this._cursor.getSpan());
21700      }
21701    } else {
21702      const nameStart = this._cursor.clone();
21703      this._attemptCharCodeUntilFn(isNamedEntityEnd);
21704      if (this._cursor.peek() != $SEMICOLON) {
21705        // No semicolon was found so abort the encoded entity token that was in progress, and treat
21706        // this as a text token
21707        this._beginToken(textTokenType, start);
21708        this._cursor = nameStart;
21709        this._endToken(['&']);
21710      } else {
21711        const name = this._cursor.getChars(nameStart);
21712        this._cursor.advance();
21713        const char = NAMED_ENTITIES[name];
21714        if (!char) {
21715          throw this._createError(_unknownEntityErrorMsg(name), this._cursor.getSpan(start));
21716        }
21717        this._endToken([char, `&${name};`]);
21718      }
21719    }
21720  }
21721  _consumeRawText(consumeEntities, endMarkerPredicate) {
21722    this._beginToken(consumeEntities ? 6 /* TokenType.ESCAPABLE_RAW_TEXT */ : 7 /* TokenType.RAW_TEXT */);
21723    const parts = [];
21724    while (true) {
21725      const tagCloseStart = this._cursor.clone();
21726      const foundEndMarker = endMarkerPredicate();
21727      this._cursor = tagCloseStart;
21728      if (foundEndMarker) {
21729        break;
21730      }
21731      if (consumeEntities && this._cursor.peek() === $AMPERSAND) {
21732        this._endToken([this._processCarriageReturns(parts.join(''))]);
21733        parts.length = 0;
21734        this._consumeEntity(6 /* TokenType.ESCAPABLE_RAW_TEXT */);
21735        this._beginToken(6 /* TokenType.ESCAPABLE_RAW_TEXT */);
21736      } else {
21737        parts.push(this._readChar());
21738      }
21739    }
21740    this._endToken([this._processCarriageReturns(parts.join(''))]);
21741  }
21742  _consumeComment(start) {
21743    this._beginToken(10 /* TokenType.COMMENT_START */, start);
21744    this._requireCharCode($MINUS);
21745    this._endToken([]);
21746    this._consumeRawText(false, () => this._attemptStr('-->'));
21747    this._beginToken(11 /* TokenType.COMMENT_END */);
21748    this._requireStr('-->');
21749    this._endToken([]);
21750  }
21751  _consumeCdata(start) {
21752    this._beginToken(12 /* TokenType.CDATA_START */, start);
21753    this._requireStr('CDATA[');
21754    this._endToken([]);
21755    this._consumeRawText(false, () => this._attemptStr(']]>'));
21756    this._beginToken(13 /* TokenType.CDATA_END */);
21757    this._requireStr(']]>');
21758    this._endToken([]);
21759  }
21760  _consumeDocType(start) {
21761    this._beginToken(18 /* TokenType.DOC_TYPE */, start);
21762    const contentStart = this._cursor.clone();
21763    this._attemptUntilChar($GT);
21764    const content = this._cursor.getChars(contentStart);
21765    this._cursor.advance();
21766    this._endToken([content]);
21767  }
21768  _consumePrefixAndName() {
21769    const nameOrPrefixStart = this._cursor.clone();
21770    let prefix = '';
21771    while (this._cursor.peek() !== $COLON && !isPrefixEnd(this._cursor.peek())) {
21772      this._cursor.advance();
21773    }
21774    let nameStart;
21775    if (this._cursor.peek() === $COLON) {
21776      prefix = this._cursor.getChars(nameOrPrefixStart);
21777      this._cursor.advance();
21778      nameStart = this._cursor.clone();
21779    } else {
21780      nameStart = nameOrPrefixStart;
21781    }
21782    this._requireCharCodeUntilFn(isNameEnd, prefix === '' ? 0 : 1);
21783    const name = this._cursor.getChars(nameStart);
21784    return [prefix, name];
21785  }
21786  _consumeTagOpen(start) {
21787    let tagName;
21788    let prefix;
21789    let openTagToken;
21790    try {
21791      if (!isAsciiLetter(this._cursor.peek())) {
21792        throw this._createError(_unexpectedCharacterErrorMsg(this._cursor.peek()), this._cursor.getSpan(start));
21793      }
21794      openTagToken = this._consumeTagOpenStart(start);
21795      prefix = openTagToken.parts[0];
21796      tagName = openTagToken.parts[1];
21797      this._attemptCharCodeUntilFn(isNotWhitespace);
21798      while (this._cursor.peek() !== $SLASH && this._cursor.peek() !== $GT && this._cursor.peek() !== $LT && this._cursor.peek() !== $EOF) {
21799        this._consumeAttributeName();
21800        this._attemptCharCodeUntilFn(isNotWhitespace);
21801        if (this._attemptCharCode($EQ)) {
21802          this._attemptCharCodeUntilFn(isNotWhitespace);
21803          this._consumeAttributeValue();
21804        }
21805        this._attemptCharCodeUntilFn(isNotWhitespace);
21806      }
21807      this._consumeTagOpenEnd();
21808    } catch (e) {
21809      if (e instanceof _ControlFlowError) {
21810        if (openTagToken) {
21811          // We errored before we could close the opening tag, so it is incomplete.
21812          openTagToken.type = 4 /* TokenType.INCOMPLETE_TAG_OPEN */;
21813        } else {
21814          // When the start tag is invalid, assume we want a "<" as text.
21815          // Back to back text tokens are merged at the end.
21816          this._beginToken(5 /* TokenType.TEXT */, start);
21817          this._endToken(['<']);
21818        }
21819        return;
21820      }
21821      throw e;
21822    }
21823    const contentTokenType = this._getTagDefinition(tagName).getContentType(prefix);
21824    if (contentTokenType === TagContentType.RAW_TEXT) {
21825      this._consumeRawTextWithTagClose(prefix, tagName, false);
21826    } else if (contentTokenType === TagContentType.ESCAPABLE_RAW_TEXT) {
21827      this._consumeRawTextWithTagClose(prefix, tagName, true);
21828    }
21829  }
21830  _consumeRawTextWithTagClose(prefix, tagName, consumeEntities) {
21831    this._consumeRawText(consumeEntities, () => {
21832      if (!this._attemptCharCode($LT)) return false;
21833      if (!this._attemptCharCode($SLASH)) return false;
21834      this._attemptCharCodeUntilFn(isNotWhitespace);
21835      if (!this._attemptStrCaseInsensitive(tagName)) return false;
21836      this._attemptCharCodeUntilFn(isNotWhitespace);
21837      return this._attemptCharCode($GT);
21838    });
21839    this._beginToken(3 /* TokenType.TAG_CLOSE */);
21840    this._requireCharCodeUntilFn(code => code === $GT, 3);
21841    this._cursor.advance(); // Consume the `>`
21842    this._endToken([prefix, tagName]);
21843  }
21844  _consumeTagOpenStart(start) {
21845    this._beginToken(0 /* TokenType.TAG_OPEN_START */, start);
21846    const parts = this._consumePrefixAndName();
21847    return this._endToken(parts);
21848  }
21849  _consumeAttributeName() {
21850    const attrNameStart = this._cursor.peek();
21851    if (attrNameStart === $SQ || attrNameStart === $DQ) {
21852      throw this._createError(_unexpectedCharacterErrorMsg(attrNameStart), this._cursor.getSpan());
21853    }
21854    this._beginToken(14 /* TokenType.ATTR_NAME */);
21855    const prefixAndName = this._consumePrefixAndName();
21856    this._endToken(prefixAndName);
21857  }
21858  _consumeAttributeValue() {
21859    if (this._cursor.peek() === $SQ || this._cursor.peek() === $DQ) {
21860      const quoteChar = this._cursor.peek();
21861      this._consumeQuote(quoteChar);
21862      // In an attribute then end of the attribute value and the premature end to an interpolation
21863      // are both triggered by the `quoteChar`.
21864      const endPredicate = () => this._cursor.peek() === quoteChar;
21865      this._consumeWithInterpolation(16 /* TokenType.ATTR_VALUE_TEXT */, 17 /* TokenType.ATTR_VALUE_INTERPOLATION */, endPredicate, endPredicate);
21866      this._consumeQuote(quoteChar);
21867    } else {
21868      const endPredicate = () => isNameEnd(this._cursor.peek());
21869      this._consumeWithInterpolation(16 /* TokenType.ATTR_VALUE_TEXT */, 17 /* TokenType.ATTR_VALUE_INTERPOLATION */, endPredicate, endPredicate);
21870    }
21871  }
21872  _consumeQuote(quoteChar) {
21873    this._beginToken(15 /* TokenType.ATTR_QUOTE */);
21874    this._requireCharCode(quoteChar);
21875    this._endToken([String.fromCodePoint(quoteChar)]);
21876  }
21877  _consumeTagOpenEnd() {
21878    const tokenType = this._attemptCharCode($SLASH) ? 2 /* TokenType.TAG_OPEN_END_VOID */ : 1 /* TokenType.TAG_OPEN_END */;
21879    this._beginToken(tokenType);
21880    this._requireCharCode($GT);
21881    this._endToken([]);
21882  }
21883  _consumeTagClose(start) {
21884    this._beginToken(3 /* TokenType.TAG_CLOSE */, start);
21885    this._attemptCharCodeUntilFn(isNotWhitespace);
21886    const prefixAndName = this._consumePrefixAndName();
21887    this._attemptCharCodeUntilFn(isNotWhitespace);
21888    this._requireCharCode($GT);
21889    this._endToken(prefixAndName);
21890  }
21891  _consumeExpansionFormStart() {
21892    this._beginToken(19 /* TokenType.EXPANSION_FORM_START */);
21893    this._requireCharCode($LBRACE);
21894    this._endToken([]);
21895    this._expansionCaseStack.push(19 /* TokenType.EXPANSION_FORM_START */);
21896    this._beginToken(7 /* TokenType.RAW_TEXT */);
21897    const condition = this._readUntil($COMMA);
21898    const normalizedCondition = this._processCarriageReturns(condition);
21899    if (this._i18nNormalizeLineEndingsInICUs) {
21900      // We explicitly want to normalize line endings for this text.
21901      this._endToken([normalizedCondition]);
21902    } else {
21903      // We are not normalizing line endings.
21904      const conditionToken = this._endToken([condition]);
21905      if (normalizedCondition !== condition) {
21906        this.nonNormalizedIcuExpressions.push(conditionToken);
21907      }
21908    }
21909    this._requireCharCode($COMMA);
21910    this._attemptCharCodeUntilFn(isNotWhitespace);
21911    this._beginToken(7 /* TokenType.RAW_TEXT */);
21912    const type = this._readUntil($COMMA);
21913    this._endToken([type]);
21914    this._requireCharCode($COMMA);
21915    this._attemptCharCodeUntilFn(isNotWhitespace);
21916  }
21917  _consumeExpansionCaseStart() {
21918    this._beginToken(20 /* TokenType.EXPANSION_CASE_VALUE */);
21919    const value = this._readUntil($LBRACE).trim();
21920    this._endToken([value]);
21921    this._attemptCharCodeUntilFn(isNotWhitespace);
21922    this._beginToken(21 /* TokenType.EXPANSION_CASE_EXP_START */);
21923    this._requireCharCode($LBRACE);
21924    this._endToken([]);
21925    this._attemptCharCodeUntilFn(isNotWhitespace);
21926    this._expansionCaseStack.push(21 /* TokenType.EXPANSION_CASE_EXP_START */);
21927  }
21928  _consumeExpansionCaseEnd() {
21929    this._beginToken(22 /* TokenType.EXPANSION_CASE_EXP_END */);
21930    this._requireCharCode($RBRACE);
21931    this._endToken([]);
21932    this._attemptCharCodeUntilFn(isNotWhitespace);
21933    this._expansionCaseStack.pop();
21934  }
21935  _consumeExpansionFormEnd() {
21936    this._beginToken(23 /* TokenType.EXPANSION_FORM_END */);
21937    this._requireCharCode($RBRACE);
21938    this._endToken([]);
21939    this._expansionCaseStack.pop();
21940  }
21941  /**
21942   * Consume a string that may contain interpolation expressions.
21943   *
21944   * The first token consumed will be of `tokenType` and then there will be alternating
21945   * `interpolationTokenType` and `tokenType` tokens until the `endPredicate()` returns true.
21946   *
21947   * If an interpolation token ends prematurely it will have no end marker in its `parts` array.
21948   *
21949   * @param textTokenType the kind of tokens to interleave around interpolation tokens.
21950   * @param interpolationTokenType the kind of tokens that contain interpolation.
21951   * @param endPredicate a function that should return true when we should stop consuming.
21952   * @param endInterpolation a function that should return true if there is a premature end to an
21953   *     interpolation expression - i.e. before we get to the normal interpolation closing marker.
21954   */
21955  _consumeWithInterpolation(textTokenType, interpolationTokenType, endPredicate, endInterpolation) {
21956    this._beginToken(textTokenType);
21957    const parts = [];
21958    while (!endPredicate()) {
21959      const current = this._cursor.clone();
21960      if (this._interpolationConfig && this._attemptStr(this._interpolationConfig.start)) {
21961        this._endToken([this._processCarriageReturns(parts.join(''))], current);
21962        parts.length = 0;
21963        this._consumeInterpolation(interpolationTokenType, current, endInterpolation);
21964        this._beginToken(textTokenType);
21965      } else if (this._cursor.peek() === $AMPERSAND) {
21966        this._endToken([this._processCarriageReturns(parts.join(''))]);
21967        parts.length = 0;
21968        this._consumeEntity(textTokenType);
21969        this._beginToken(textTokenType);
21970      } else {
21971        parts.push(this._readChar());
21972      }
21973    }
21974    // It is possible that an interpolation was started but not ended inside this text token.
21975    // Make sure that we reset the state of the lexer correctly.
21976    this._inInterpolation = false;
21977    this._endToken([this._processCarriageReturns(parts.join(''))]);
21978  }
21979  /**
21980   * Consume a block of text that has been interpreted as an Angular interpolation.
21981   *
21982   * @param interpolationTokenType the type of the interpolation token to generate.
21983   * @param interpolationStart a cursor that points to the start of this interpolation.
21984   * @param prematureEndPredicate a function that should return true if the next characters indicate
21985   *     an end to the interpolation before its normal closing marker.
21986   */
21987  _consumeInterpolation(interpolationTokenType, interpolationStart, prematureEndPredicate) {
21988    const parts = [];
21989    this._beginToken(interpolationTokenType, interpolationStart);
21990    parts.push(this._interpolationConfig.start);
21991    // Find the end of the interpolation, ignoring content inside quotes.
21992    const expressionStart = this._cursor.clone();
21993    let inQuote = null;
21994    let inComment = false;
21995    while (this._cursor.peek() !== $EOF && (prematureEndPredicate === null || !prematureEndPredicate())) {
21996      const current = this._cursor.clone();
21997      if (this._isTagStart()) {
21998        // We are starting what looks like an HTML element in the middle of this interpolation.
21999        // Reset the cursor to before the `<` character and end the interpolation token.
22000        // (This is actually wrong but here for backward compatibility).
22001        this._cursor = current;
22002        parts.push(this._getProcessedChars(expressionStart, current));
22003        this._endToken(parts);
22004        return;
22005      }
22006      if (inQuote === null) {
22007        if (this._attemptStr(this._interpolationConfig.end)) {
22008          // We are not in a string, and we hit the end interpolation marker
22009          parts.push(this._getProcessedChars(expressionStart, current));
22010          parts.push(this._interpolationConfig.end);
22011          this._endToken(parts);
22012          return;
22013        } else if (this._attemptStr('//')) {
22014          // Once we are in a comment we ignore any quotes
22015          inComment = true;
22016        }
22017      }
22018      const char = this._cursor.peek();
22019      this._cursor.advance();
22020      if (char === $BACKSLASH) {
22021        // Skip the next character because it was escaped.
22022        this._cursor.advance();
22023      } else if (char === inQuote) {
22024        // Exiting the current quoted string
22025        inQuote = null;
22026      } else if (!inComment && inQuote === null && isQuote(char)) {
22027        // Entering a new quoted string
22028        inQuote = char;
22029      }
22030    }
22031    // We hit EOF without finding a closing interpolation marker
22032    parts.push(this._getProcessedChars(expressionStart, this._cursor));
22033    this._endToken(parts);
22034  }
22035  _getProcessedChars(start, end) {
22036    return this._processCarriageReturns(end.getChars(start));
22037  }
22038  _isTextEnd() {
22039    if (this._isTagStart() || this._cursor.peek() === $EOF) {
22040      return true;
22041    }
22042    if (this._tokenizeIcu && !this._inInterpolation) {
22043      if (this.isExpansionFormStart()) {
22044        // start of an expansion form
22045        return true;
22046      }
22047      if (this._cursor.peek() === $RBRACE && this._isInExpansionCase()) {
22048        // end of and expansion case
22049        return true;
22050      }
22051    }
22052    if (this._tokenizeBlocks && !this._inInterpolation && !this._isInExpansion() && (this._cursor.peek() === $AT || this._cursor.peek() === $RBRACE)) {
22053      return true;
22054    }
22055    return false;
22056  }
22057  /**
22058   * Returns true if the current cursor is pointing to the start of a tag
22059   * (opening/closing/comments/cdata/etc).
22060   */
22061  _isTagStart() {
22062    if (this._cursor.peek() === $LT) {
22063      // We assume that `<` followed by whitespace is not the start of an HTML element.
22064      const tmp = this._cursor.clone();
22065      tmp.advance();
22066      // If the next character is alphabetic, ! nor / then it is a tag start
22067      const code = tmp.peek();
22068      if ($a <= code && code <= $z || $A <= code && code <= $Z || code === $SLASH || code === $BANG) {
22069        return true;
22070      }
22071    }
22072    return false;
22073  }
22074  _readUntil(char) {
22075    const start = this._cursor.clone();
22076    this._attemptUntilChar(char);
22077    return this._cursor.getChars(start);
22078  }
22079  _isInExpansion() {
22080    return this._isInExpansionCase() || this._isInExpansionForm();
22081  }
22082  _isInExpansionCase() {
22083    return this._expansionCaseStack.length > 0 && this._expansionCaseStack[this._expansionCaseStack.length - 1] === 21 /* TokenType.EXPANSION_CASE_EXP_START */;
22084  }
22085  _isInExpansionForm() {
22086    return this._expansionCaseStack.length > 0 && this._expansionCaseStack[this._expansionCaseStack.length - 1] === 19 /* TokenType.EXPANSION_FORM_START */;
22087  }
22088  isExpansionFormStart() {
22089    if (this._cursor.peek() !== $LBRACE) {
22090      return false;
22091    }
22092    if (this._interpolationConfig) {
22093      const start = this._cursor.clone();
22094      const isInterpolation = this._attemptStr(this._interpolationConfig.start);
22095      this._cursor = start;
22096      return !isInterpolation;
22097    }
22098    return true;
22099  }
22100}
22101function isNotWhitespace(code) {
22102  return !isWhitespace(code) || code === $EOF;
22103}
22104function isNameEnd(code) {
22105  return isWhitespace(code) || code === $GT || code === $LT || code === $SLASH || code === $SQ || code === $DQ || code === $EQ || code === $EOF;
22106}
22107function isPrefixEnd(code) {
22108  return (code < $a || $z < code) && (code < $A || $Z < code) && (code < $0 || code > $9);
22109}
22110function isDigitEntityEnd(code) {
22111  return code === $SEMICOLON || code === $EOF || !isAsciiHexDigit(code);
22112}
22113function isNamedEntityEnd(code) {
22114  return code === $SEMICOLON || code === $EOF || !isAsciiLetter(code);
22115}
22116function isExpansionCaseStart(peek) {
22117  return peek !== $RBRACE;
22118}
22119function compareCharCodeCaseInsensitive(code1, code2) {
22120  return toUpperCaseCharCode(code1) === toUpperCaseCharCode(code2);
22121}
22122function toUpperCaseCharCode(code) {
22123  return code >= $a && code <= $z ? code - $a + $A : code;
22124}
22125function isBlockNameChar(code) {
22126  return isAsciiLetter(code) || isDigit(code) || code === $_;
22127}
22128function isBlockParameterChar(code) {
22129  return code !== $SEMICOLON && isNotWhitespace(code);
22130}
22131function mergeTextTokens(srcTokens) {
22132  const dstTokens = [];
22133  let lastDstToken = undefined;
22134  for (let i = 0; i < srcTokens.length; i++) {
22135    const token = srcTokens[i];
22136    if (lastDstToken && lastDstToken.type === 5 /* TokenType.TEXT */ && token.type === 5 /* TokenType.TEXT */ || lastDstToken && lastDstToken.type === 16 /* TokenType.ATTR_VALUE_TEXT */ && token.type === 16 /* TokenType.ATTR_VALUE_TEXT */) {
22137      lastDstToken.parts[0] += token.parts[0];
22138      lastDstToken.sourceSpan.end = token.sourceSpan.end;
22139    } else {
22140      lastDstToken = token;
22141      dstTokens.push(lastDstToken);
22142    }
22143  }
22144  return dstTokens;
22145}
22146class PlainCharacterCursor {
22147  constructor(fileOrCursor, range) {
22148    if (fileOrCursor instanceof PlainCharacterCursor) {
22149      this.file = fileOrCursor.file;
22150      this.input = fileOrCursor.input;
22151      this.end = fileOrCursor.end;
22152      const state = fileOrCursor.state;
22153      // Note: avoid using `{...fileOrCursor.state}` here as that has a severe performance penalty.
22154      // In ES5 bundles the object spread operator is translated into the `__assign` helper, which
22155      // is not optimized by VMs as efficiently as a raw object literal. Since this constructor is
22156      // called in tight loops, this difference matters.
22157      this.state = {
22158        peek: state.peek,
22159        offset: state.offset,
22160        line: state.line,
22161        column: state.column
22162      };
22163    } else {
22164      if (!range) {
22165        throw new Error('Programming error: the range argument must be provided with a file argument.');
22166      }
22167      this.file = fileOrCursor;
22168      this.input = fileOrCursor.content;
22169      this.end = range.endPos;
22170      this.state = {
22171        peek: -1,
22172        offset: range.startPos,
22173        line: range.startLine,
22174        column: range.startCol
22175      };
22176    }
22177  }
22178  clone() {
22179    return new PlainCharacterCursor(this);
22180  }
22181  peek() {
22182    return this.state.peek;
22183  }
22184  charsLeft() {
22185    return this.end - this.state.offset;
22186  }
22187  diff(other) {
22188    return this.state.offset - other.state.offset;
22189  }
22190  advance() {
22191    this.advanceState(this.state);
22192  }
22193  init() {
22194    this.updatePeek(this.state);
22195  }
22196  getSpan(start, leadingTriviaCodePoints) {
22197    start = start || this;
22198    let fullStart = start;
22199    if (leadingTriviaCodePoints) {
22200      while (this.diff(start) > 0 && leadingTriviaCodePoints.indexOf(start.peek()) !== -1) {
22201        if (fullStart === start) {
22202          start = start.clone();
22203        }
22204        start.advance();
22205      }
22206    }
22207    const startLocation = this.locationFromCursor(start);
22208    const endLocation = this.locationFromCursor(this);
22209    const fullStartLocation = fullStart !== start ? this.locationFromCursor(fullStart) : startLocation;
22210    return new ParseSourceSpan(startLocation, endLocation, fullStartLocation);
22211  }
22212  getChars(start) {
22213    return this.input.substring(start.state.offset, this.state.offset);
22214  }
22215  charAt(pos) {
22216    return this.input.charCodeAt(pos);
22217  }
22218  advanceState(state) {
22219    if (state.offset >= this.end) {
22220      this.state = state;
22221      throw new CursorError('Unexpected character "EOF"', this);
22222    }
22223    const currentChar = this.charAt(state.offset);
22224    if (currentChar === $LF) {
22225      state.line++;
22226      state.column = 0;
22227    } else if (!isNewLine(currentChar)) {
22228      state.column++;
22229    }
22230    state.offset++;
22231    this.updatePeek(state);
22232  }
22233  updatePeek(state) {
22234    state.peek = state.offset >= this.end ? $EOF : this.charAt(state.offset);
22235  }
22236  locationFromCursor(cursor) {
22237    return new ParseLocation(cursor.file, cursor.state.offset, cursor.state.line, cursor.state.column);
22238  }
22239}
22240class EscapedCharacterCursor extends PlainCharacterCursor {
22241  constructor(fileOrCursor, range) {
22242    if (fileOrCursor instanceof EscapedCharacterCursor) {
22243      super(fileOrCursor);
22244      this.internalState = {
22245        ...fileOrCursor.internalState
22246      };
22247    } else {
22248      super(fileOrCursor, range);
22249      this.internalState = this.state;
22250    }
22251  }
22252  advance() {
22253    this.state = this.internalState;
22254    super.advance();
22255    this.processEscapeSequence();
22256  }
22257  init() {
22258    super.init();
22259    this.processEscapeSequence();
22260  }
22261  clone() {
22262    return new EscapedCharacterCursor(this);
22263  }
22264  getChars(start) {
22265    const cursor = start.clone();
22266    let chars = '';
22267    while (cursor.internalState.offset < this.internalState.offset) {
22268      chars += String.fromCodePoint(cursor.peek());
22269      cursor.advance();
22270    }
22271    return chars;
22272  }
22273  /**
22274   * Process the escape sequence that starts at the current position in the text.
22275   *
22276   * This method is called to ensure that `peek` has the unescaped value of escape sequences.
22277   */
22278  processEscapeSequence() {
22279    const peek = () => this.internalState.peek;
22280    if (peek() === $BACKSLASH) {
22281      // We have hit an escape sequence so we need the internal state to become independent
22282      // of the external state.
22283      this.internalState = {
22284        ...this.state
22285      };
22286      // Move past the backslash
22287      this.advanceState(this.internalState);
22288      // First check for standard control char sequences
22289      if (peek() === $n) {
22290        this.state.peek = $LF;
22291      } else if (peek() === $r) {
22292        this.state.peek = $CR;
22293      } else if (peek() === $v) {
22294        this.state.peek = $VTAB;
22295      } else if (peek() === $t) {
22296        this.state.peek = $TAB;
22297      } else if (peek() === $b) {
22298        this.state.peek = $BSPACE;
22299      } else if (peek() === $f) {
22300        this.state.peek = $FF;
22301      }
22302      // Now consider more complex sequences
22303      else if (peek() === $u) {
22304        // Unicode code-point sequence
22305        this.advanceState(this.internalState); // advance past the `u` char
22306        if (peek() === $LBRACE) {
22307          // Variable length Unicode, e.g. `\x{123}`
22308          this.advanceState(this.internalState); // advance past the `{` char
22309          // Advance past the variable number of hex digits until we hit a `}` char
22310          const digitStart = this.clone();
22311          let length = 0;
22312          while (peek() !== $RBRACE) {
22313            this.advanceState(this.internalState);
22314            length++;
22315          }
22316          this.state.peek = this.decodeHexDigits(digitStart, length);
22317        } else {
22318          // Fixed length Unicode, e.g. `\u1234`
22319          const digitStart = this.clone();
22320          this.advanceState(this.internalState);
22321          this.advanceState(this.internalState);
22322          this.advanceState(this.internalState);
22323          this.state.peek = this.decodeHexDigits(digitStart, 4);
22324        }
22325      } else if (peek() === $x) {
22326        // Hex char code, e.g. `\x2F`
22327        this.advanceState(this.internalState); // advance past the `x` char
22328        const digitStart = this.clone();
22329        this.advanceState(this.internalState);
22330        this.state.peek = this.decodeHexDigits(digitStart, 2);
22331      } else if (isOctalDigit(peek())) {
22332        // Octal char code, e.g. `\012`,
22333        let octal = '';
22334        let length = 0;
22335        let previous = this.clone();
22336        while (isOctalDigit(peek()) && length < 3) {
22337          previous = this.clone();
22338          octal += String.fromCodePoint(peek());
22339          this.advanceState(this.internalState);
22340          length++;
22341        }
22342        this.state.peek = parseInt(octal, 8);
22343        // Backup one char
22344        this.internalState = previous.internalState;
22345      } else if (isNewLine(this.internalState.peek)) {
22346        // Line continuation `\` followed by a new line
22347        this.advanceState(this.internalState); // advance over the newline
22348        this.state = this.internalState;
22349      } else {
22350        // If none of the `if` blocks were executed then we just have an escaped normal character.
22351        // In that case we just, effectively, skip the backslash from the character.
22352        this.state.peek = this.internalState.peek;
22353      }
22354    }
22355  }
22356  decodeHexDigits(start, length) {
22357    const hex = this.input.slice(start.internalState.offset, start.internalState.offset + length);
22358    const charCode = parseInt(hex, 16);
22359    if (!isNaN(charCode)) {
22360      return charCode;
22361    } else {
22362      start.state = start.internalState;
22363      throw new CursorError('Invalid hexadecimal escape sequence', start);
22364    }
22365  }
22366}
22367class CursorError {
22368  constructor(msg, cursor) {
22369    this.msg = msg;
22370    this.cursor = cursor;
22371  }
22372}
22373class TreeError extends ParseError {
22374  static create(elementName, span, msg) {
22375    return new TreeError(elementName, span, msg);
22376  }
22377  constructor(elementName, span, msg) {
22378    super(span, msg);
22379    this.elementName = elementName;
22380  }
22381}
22382class ParseTreeResult {
22383  constructor(rootNodes, errors) {
22384    this.rootNodes = rootNodes;
22385    this.errors = errors;
22386  }
22387}
22388class Parser {
22389  constructor(getTagDefinition) {
22390    this.getTagDefinition = getTagDefinition;
22391  }
22392  parse(source, url, options) {
22393    const tokenizeResult = tokenize(source, url, this.getTagDefinition, options);
22394    const parser = new _TreeBuilder(tokenizeResult.tokens, this.getTagDefinition);
22395    parser.build();
22396    return new ParseTreeResult(parser.rootNodes, tokenizeResult.errors.concat(parser.errors));
22397  }
22398}
22399class _TreeBuilder {
22400  constructor(tokens, getTagDefinition) {
22401    this.tokens = tokens;
22402    this.getTagDefinition = getTagDefinition;
22403    this._index = -1;
22404    this._containerStack = [];
22405    this.rootNodes = [];
22406    this.errors = [];
22407    this._advance();
22408  }
22409  build() {
22410    while (this._peek.type !== 29 /* TokenType.EOF */) {
22411      if (this._peek.type === 0 /* TokenType.TAG_OPEN_START */ || this._peek.type === 4 /* TokenType.INCOMPLETE_TAG_OPEN */) {
22412        this._consumeStartTag(this._advance());
22413      } else if (this._peek.type === 3 /* TokenType.TAG_CLOSE */) {
22414        this._consumeEndTag(this._advance());
22415      } else if (this._peek.type === 12 /* TokenType.CDATA_START */) {
22416        this._closeVoidElement();
22417        this._consumeCdata(this._advance());
22418      } else if (this._peek.type === 10 /* TokenType.COMMENT_START */) {
22419        this._closeVoidElement();
22420        this._consumeComment(this._advance());
22421      } else if (this._peek.type === 5 /* TokenType.TEXT */ || this._peek.type === 7 /* TokenType.RAW_TEXT */ || this._peek.type === 6 /* TokenType.ESCAPABLE_RAW_TEXT */) {
22422        this._closeVoidElement();
22423        this._consumeText(this._advance());
22424      } else if (this._peek.type === 19 /* TokenType.EXPANSION_FORM_START */) {
22425        this._consumeExpansion(this._advance());
22426      } else if (this._peek.type === 24 /* TokenType.BLOCK_OPEN_START */) {
22427        this._closeVoidElement();
22428        this._consumeBlockOpen(this._advance());
22429      } else if (this._peek.type === 26 /* TokenType.BLOCK_CLOSE */) {
22430        this._closeVoidElement();
22431        this._consumeBlockClose(this._advance());
22432      } else if (this._peek.type === 28 /* TokenType.INCOMPLETE_BLOCK_OPEN */) {
22433        this._closeVoidElement();
22434        this._consumeIncompleteBlock(this._advance());
22435      } else {
22436        // Skip all other tokens...
22437        this._advance();
22438      }
22439    }
22440    for (const leftoverContainer of this._containerStack) {
22441      // Unlike HTML elements, blocks aren't closed implicitly by the end of the file.
22442      if (leftoverContainer instanceof Block) {
22443        this.errors.push(TreeError.create(leftoverContainer.name, leftoverContainer.sourceSpan, `Unclosed block "${leftoverContainer.name}"`));
22444      }
22445    }
22446  }
22447  _advance() {
22448    const prev = this._peek;
22449    if (this._index < this.tokens.length - 1) {
22450      // Note: there is always an EOF token at the end
22451      this._index++;
22452    }
22453    this._peek = this.tokens[this._index];
22454    return prev;
22455  }
22456  _advanceIf(type) {
22457    if (this._peek.type === type) {
22458      return this._advance();
22459    }
22460    return null;
22461  }
22462  _consumeCdata(_startToken) {
22463    this._consumeText(this._advance());
22464    this._advanceIf(13 /* TokenType.CDATA_END */);
22465  }
22466  _consumeComment(token) {
22467    const text = this._advanceIf(7 /* TokenType.RAW_TEXT */);
22468    const endToken = this._advanceIf(11 /* TokenType.COMMENT_END */);
22469    const value = text != null ? text.parts[0].trim() : null;
22470    const sourceSpan = endToken == null ? token.sourceSpan : new ParseSourceSpan(token.sourceSpan.start, endToken.sourceSpan.end, token.sourceSpan.fullStart);
22471    this._addToParent(new Comment(value, sourceSpan));
22472  }
22473  _consumeExpansion(token) {
22474    const switchValue = this._advance();
22475    const type = this._advance();
22476    const cases = [];
22477    // read =
22478    while (this._peek.type === 20 /* TokenType.EXPANSION_CASE_VALUE */) {
22479      const expCase = this._parseExpansionCase();
22480      if (!expCase) return; // error
22481      cases.push(expCase);
22482    }
22483    // read the final }
22484    if (this._peek.type !== 23 /* TokenType.EXPANSION_FORM_END */) {
22485      this.errors.push(TreeError.create(null, this._peek.sourceSpan, `Invalid ICU message. Missing '}'.`));
22486      return;
22487    }
22488    const sourceSpan = new ParseSourceSpan(token.sourceSpan.start, this._peek.sourceSpan.end, token.sourceSpan.fullStart);
22489    this._addToParent(new Expansion(switchValue.parts[0], type.parts[0], cases, sourceSpan, switchValue.sourceSpan));
22490    this._advance();
22491  }
22492  _parseExpansionCase() {
22493    const value = this._advance();
22494    // read {
22495    if (this._peek.type !== 21 /* TokenType.EXPANSION_CASE_EXP_START */) {
22496      this.errors.push(TreeError.create(null, this._peek.sourceSpan, `Invalid ICU message. Missing '{'.`));
22497      return null;
22498    }
22499    // read until }
22500    const start = this._advance();
22501    const exp = this._collectExpansionExpTokens(start);
22502    if (!exp) return null;
22503    const end = this._advance();
22504    exp.push({
22505      type: 29 /* TokenType.EOF */,
22506      parts: [],
22507      sourceSpan: end.sourceSpan
22508    });
22509    // parse everything in between { and }
22510    const expansionCaseParser = new _TreeBuilder(exp, this.getTagDefinition);
22511    expansionCaseParser.build();
22512    if (expansionCaseParser.errors.length > 0) {
22513      this.errors = this.errors.concat(expansionCaseParser.errors);
22514      return null;
22515    }
22516    const sourceSpan = new ParseSourceSpan(value.sourceSpan.start, end.sourceSpan.end, value.sourceSpan.fullStart);
22517    const expSourceSpan = new ParseSourceSpan(start.sourceSpan.start, end.sourceSpan.end, start.sourceSpan.fullStart);
22518    return new ExpansionCase(value.parts[0], expansionCaseParser.rootNodes, sourceSpan, value.sourceSpan, expSourceSpan);
22519  }
22520  _collectExpansionExpTokens(start) {
22521    const exp = [];
22522    const expansionFormStack = [21 /* TokenType.EXPANSION_CASE_EXP_START */];
22523    while (true) {
22524      if (this._peek.type === 19 /* TokenType.EXPANSION_FORM_START */ || this._peek.type === 21 /* TokenType.EXPANSION_CASE_EXP_START */) {
22525        expansionFormStack.push(this._peek.type);
22526      }
22527      if (this._peek.type === 22 /* TokenType.EXPANSION_CASE_EXP_END */) {
22528        if (lastOnStack(expansionFormStack, 21 /* TokenType.EXPANSION_CASE_EXP_START */)) {
22529          expansionFormStack.pop();
22530          if (expansionFormStack.length === 0) return exp;
22531        } else {
22532          this.errors.push(TreeError.create(null, start.sourceSpan, `Invalid ICU message. Missing '}'.`));
22533          return null;
22534        }
22535      }
22536      if (this._peek.type === 23 /* TokenType.EXPANSION_FORM_END */) {
22537        if (lastOnStack(expansionFormStack, 19 /* TokenType.EXPANSION_FORM_START */)) {
22538          expansionFormStack.pop();
22539        } else {
22540          this.errors.push(TreeError.create(null, start.sourceSpan, `Invalid ICU message. Missing '}'.`));
22541          return null;
22542        }
22543      }
22544      if (this._peek.type === 29 /* TokenType.EOF */) {
22545        this.errors.push(TreeError.create(null, start.sourceSpan, `Invalid ICU message. Missing '}'.`));
22546        return null;
22547      }
22548      exp.push(this._advance());
22549    }
22550  }
22551  _consumeText(token) {
22552    const tokens = [token];
22553    const startSpan = token.sourceSpan;
22554    let text = token.parts[0];
22555    if (text.length > 0 && text[0] === '\n') {
22556      const parent = this._getContainer();
22557      if (parent != null && parent.children.length === 0 && this.getTagDefinition(parent.name).ignoreFirstLf) {
22558        text = text.substring(1);
22559        tokens[0] = {
22560          type: token.type,
22561          sourceSpan: token.sourceSpan,
22562          parts: [text]
22563        };
22564      }
22565    }
22566    while (this._peek.type === 8 /* TokenType.INTERPOLATION */ || this._peek.type === 5 /* TokenType.TEXT */ || this._peek.type === 9 /* TokenType.ENCODED_ENTITY */) {
22567      token = this._advance();
22568      tokens.push(token);
22569      if (token.type === 8 /* TokenType.INTERPOLATION */) {
22570        // For backward compatibility we decode HTML entities that appear in interpolation
22571        // expressions. This is arguably a bug, but it could be a considerable breaking change to
22572        // fix it. It should be addressed in a larger project to refactor the entire parser/lexer
22573        // chain after View Engine has been removed.
22574        text += token.parts.join('').replace(/&([^;]+);/g, decodeEntity);
22575      } else if (token.type === 9 /* TokenType.ENCODED_ENTITY */) {
22576        text += token.parts[0];
22577      } else {
22578        text += token.parts.join('');
22579      }
22580    }
22581    if (text.length > 0) {
22582      const endSpan = token.sourceSpan;
22583      this._addToParent(new Text(text, new ParseSourceSpan(start
22583Span.start, endSpan.end, startSpan.fullStart, startSpan.details), tokens));
22584    }
22585  }
22586  _closeVoidElement() {
22587    const el = this._getContainer();
22588    if (el instanceof Element && this.getTagDefinition(el.name).isVoid) {
22589      this._containerStack.pop();
22590    }
22591  }
22592  _consumeStartTag(startTagToken) {
22593    const [prefix, name] = startTagToken.parts;
22594    const attrs = [];
22595    while (this._peek.type === 14 /* TokenType.ATTR_NAME */) {
22596      attrs.push(this._consumeAttr(this._advance()));
22597    }
22598    const fullName = this._getElementFullName(prefix, name, this._getClosestParentElement());
22599    let selfClosing = false;
22600    // Note: There could have been a tokenizer error
22601    // so that we don't get a token for the end tag...
22602    if (this._peek.type === 2 /* TokenType.TAG_OPEN_END_VOID */) {
22603      this._advance();
22604      selfClosing = true;
22605      const tagDef = this.getTagDefinition(fullName);
22606      if (!(tagDef.canSelfClose || getNsPrefix(fullName) !== null || tagDef.isVoid)) {
22607        this.errors.push(TreeError.create(fullName, startTagToken.sourceSpan, `Only void, custom and foreign elements can be self closed "${startTagToken.parts[1]}"`));
22608      }
22609    } else if (this._peek.type === 1 /* TokenType.TAG_OPEN_END */) {
22610      this._advance();
22611      selfClosing = false;
22612    }
22613    const end = this._peek.sourceSpan.fullStart;
22614    const span = new ParseSourceSpan(startTagToken.sourceSpan.start, end, startTagToken.sourceSpan.fullStart);
22615    // Create a separate `startSpan` because `span` will be modified when there is an `end` span.
22616    const startSpan = new ParseSourceSpan(startTagToken.sourceSpan.start, end, startTagToken.sourceSpan.fullStart);
22617    const el = new Element(fullName, attrs, [], span, startSpan, undefined);
22618    const parentEl = this._getContainer();
22619    this._pushContainer(el, parentEl instanceof Element && this.getTagDefinition(parentEl.name).isClosedByChild(el.name));
22620    if (selfClosing) {
22621      // Elements that are self-closed have their `endSourceSpan` set to the full span, as the
22622      // element start tag also represents the end tag.
22623      this._popContainer(fullName, Element, span);
22624    } else if (startTagToken.type === 4 /* TokenType.INCOMPLETE_TAG_OPEN */) {
22625      // We already know the opening tag is not complete, so it is unlikely it has a corresponding
22626      // close tag. Let's optimistically parse it as a full element and emit an error.
22627      this._popContainer(fullName, Element, null);
22628      this.errors.push(TreeError.create(fullName, span, `Opening tag "${fullName}" not terminated.`));
22629    }
22630  }
22631  _pushContainer(node, isClosedByChild) {
22632    if (isClosedByChild) {
22633      this._containerStack.pop();
22634    }
22635    this._addToParent(node);
22636    this._containerStack.push(node);
22637  }
22638  _consumeEndTag(endTagToken) {
22639    const fullName = this._getElementFullName(endTagToken.parts[0], endTagToken.parts[1], this._getClosestParentElement());
22640    if (this.getTagDefinition(fullName).isVoid) {
22641      this.errors.push(TreeError.create(fullName, endTagToken.sourceSpan, `Void elements do not have end tags "${endTagToken.parts[1]}"`));
22642    } else if (!this._popContainer(fullName, Element, endTagToken.sourceSpan)) {
22643      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`;
22644      this.errors.push(TreeError.create(fullName, endTagToken.sourceSpan, errMsg));
22645    }
22646  }
22647  /**
22648   * Closes the nearest element with the tag name `fullName` in the parse tree.
22649   * `endSourceSpan` is the span of the closing tag, or null if the element does
22650   * not have a closing tag (for example, this happens when an incomplete
22651   * opening tag is recovered).
22652   */
22653  _popContainer(expectedName, expectedType, endSourceSpan) {
22654    let unexpectedCloseTagDetected = false;
22655    for (let stackIndex = this._containerStack.length - 1; stackIndex >= 0; stackIndex--) {
22656      const node = this._containerStack[stackIndex];
22657      if ((node.name === expectedName || expectedName === null) && node instanceof expectedType) {
22658        // Record the parse span with the element that is being closed. Any elements that are
22659        // removed from the element stack at this point are closed implicitly, so they won't get
22660        // an end source span (as there is no explicit closing element).
22661        node.endSourceSpan = endSourceSpan;
22662        node.sourceSpan.end = endSourceSpan !== null ? endSourceSpan.end : node.sourceSpan.end;
22663        this._containerStack.splice(stackIndex, this._containerStack.length - stackIndex);
22664        return !unexpectedCloseTagDetected;
22665      }
22666      // Blocks and most elements are not self closing.
22667      if (node instanceof Block || node instanceof Element && !this.getTagDefinition(node.name).closedByParent) {
22668        // Note that we encountered an unexpected close tag but continue processing the element
22669        // stack so we can assign an `endSourceSpan` if there is a corresponding start tag for this
22670        // end tag in the stack.
22671        unexpectedCloseTagDetected = true;
22672      }
22673    }
22674    return false;
22675  }
22676  _consumeAttr(attrName) {
22677    const fullName = mergeNsAndName(attrName.parts[0], attrName.parts[1]);
22678    let attrEnd = attrName.sourceSpan.end;
22679    // Consume any quote
22680    if (this._peek.type === 15 /* TokenType.ATTR_QUOTE */) {
22681      this._advance();
22682    }
22683    // Consume the attribute value
22684    let value = '';
22685    const valueTokens = [];
22686    let valueStartSpan = undefined;
22687    let valueEnd = undefined;
22688    // NOTE: We need to use a new variable `nextTokenType` here to hide the actual type of
22689    // `_peek.type` from TS. Otherwise TS will narrow the type of `_peek.type` preventing it from
22690    // being able to consider `ATTR_VALUE_INTERPOLATION` as an option. This is because TS is not
22691    // able to see that `_advance()` will actually mutate `_peek`.
22692    const nextTokenType = this._peek.type;
22693    if (nextTokenType === 16 /* TokenType.ATTR_VALUE_TEXT */) {
22694      valueStartSpan = this._peek.sourceSpan;
22695      valueEnd = this._peek.sourceSpan.end;
22696      while (this._peek.type === 16 /* TokenType.ATTR_VALUE_TEXT */ || this._peek.type === 17 /* TokenType.ATTR_VALUE_INTERPOLATION */ || this._peek.type === 9 /* TokenType.ENCODED_ENTITY */) {
22697        const valueToken = this._advance();
22698        valueTokens.push(valueToken);
22699        if (valueToken.type === 17 /* TokenType.ATTR_VALUE_INTERPOLATION */) {
22700          // For backward compatibility we decode HTML entities that appear in interpolation
22701          // expressions. This is arguably a bug, but it could be a considerable breaking change to
22702          // fix it. It should be addressed in a larger project to refactor the entire parser/lexer
22703          // chain after View Engine has been removed.
22704          value += valueToken.parts.join('').replace(/&([^;]+);/g, decodeEntity);
22705        } else if (valueToken.type === 9 /* TokenType.ENCODED_ENTITY */) {
22706          value += valueToken.parts[0];
22707        } else {
22708          value += valueToken.parts.join('');
22709        }
22710        valueEnd = attrEnd = valueToken.sourceSpan.end;
22711      }
22712    }
22713    // Consume any quote
22714    if (this._peek.type === 15 /* TokenType.ATTR_QUOTE */) {
22715      const quoteToken = this._advance();
22716      attrEnd = quoteToken.sourceSpan.end;
22717    }
22718    const valueSpan = valueStartSpan && valueEnd && new ParseSourceSpan(valueStartSpan.start, valueEnd, valueStartSpan.fullStart);
22719    return new Attribute(fullName, value, new ParseSourceSpan(attrName.sourceSpan.start, attrEnd, attrName.sourceSpan.fullStart), attrName.sourceSpan, valueSpan, valueTokens.length > 0 ? valueTokens : undefined, undefined);
22720  }
22721  _consumeBlockOpen(token) {
22722    const parameters = [];
22723    while (this._peek.type === 27 /* TokenType.BLOCK_PARAMETER */) {
22724      const paramToken = this._advance();
22725      parameters.push(new BlockParameter(paramToken.parts[0], paramToken.sourceSpan));
22726    }
22727    if (this._peek.type === 25 /* TokenType.BLOCK_OPEN_END */) {
22728      this._advance();
22729    }
22730    const end = this._peek.sourceSpan.fullStart;
22731    const span = new ParseSourceSpan(token.sourceSpan.start, end, token.sourceSpan.fullStart);
22732    // Create a separate `startSpan` because `span` will be modified when there is an `end` span.
22733    const startSpan = new ParseSourceSpan(token.sourceSpan.start, end, token.sourceSpan.fullStart);
22734    const block = new Block(token.parts[0], parameters, [], span, token.sourceSpan, startSpan);
22735    this._pushContainer(block, false);
22736  }
22737  _consumeBlockClose(token) {
22738    if (!this._popContainer(null, Block, token.sourceSpan)) {
22739      this.errors.push(TreeError.create(null, token.sourceSpan, `Unexpected closing block. The block may have been closed earlier. ` + `If you meant to write the } character, you should use the "&#125;" ` + `HTML entity instead.`));
22740    }
22741  }
22742  _consumeIncompleteBlock(token) {
22743    const parameters = [];
22744    while (this._peek.type === 27 /* TokenType.BLOCK_PARAMETER */) {
22745      const paramToken = this._advance();
22746      parameters.push(new BlockParameter(paramToken.parts[0], paramToken.sourceSpan));
22747    }
22748    const end = this._peek.sourceSpan.fullStart;
22749    const span = new ParseSourceSpan(token.sourceSpan.start, end, token.sourceSpan.fullStart);
22750    // Create a separate `startSpan` because `span` will be modified when there is an `end` span.
22751    const startSpan = new ParseSourceSpan(token.sourceSpan.start, end, token.sourceSpan.fullStart);
22752    const block = new Block(token.parts[0], parameters, [], span, token.sourceSpan, startSpan);
22753    this._pushContainer(block, false);
22754    // Incomplete blocks don't have children so we close them immediately and report an error.
22755    this._popContainer(null, Block, null);
22756    this.errors.push(TreeError.create(token.parts[0], span, `Incomplete block "${token.parts[0]}". If you meant to write the @ character, ` + `you should use the "&#64;" HTML entity instead.`));
22757  }
22758  _getContainer() {
22759    return this._containerStack.length > 0 ? this._containerStack[this._containerStack.length - 1] : null;
22760  }
22761  _getClosestParentElement() {
22762    for (let i = this._containerStack.length - 1; i > -1; i--) {
22763      if (this._containerStack[i] instanceof Element) {
22764        return this._containerStack[i];
22765      }
22766    }
22767    return null;
22768  }
22769  _addToParent(node) {
22770    const parent = this._getContainer();
22771    if (parent === null) {
22772      this.rootNodes.push(node);
22773    } else {
22774      parent.children.push(node);
22775    }
22776  }
22777  _getElementFullName(prefix, localName, parentElement) {
22778    if (prefix === '') {
22779      prefix = this.getTagDefinition(localName).implicitNamespacePrefix || '';
22780      if (prefix === '' && parentElement != null) {
22781        const parentTagName = splitNsName(parentElement.name)[1];
22782        const parentTagDefinition = this.getTagDefinition(parentTagName);
22783        if (!parentTagDefinition.preventNamespaceInheritance) {
22784          prefix = getNsPrefix(parentElement.name);
22785        }
22786      }
22787    }
22788    return mergeNsAndName(prefix, localName);
22789  }
22790}
22791function lastOnStack(stack, element) {
22792  return stack.length > 0 && stack[stack.length - 1] === element;
22793}
22794/**
22795 * Decode the `entity` string, which we believe is the contents of an HTML entity.
22796 *
22797 * If the string is not actually a valid/known entity then just return the original `match` string.
22798 */
22799function decodeEntity(match, entity) {
22800  if (NAMED_ENTITIES[entity] !== undefined) {
22801    return NAMED_ENTITIES[entity] || match;
22802  }
22803  if (/^#x[a-f0-9]+$/i.test(entity)) {
22804    return String.fromCodePoint(parseInt(entity.slice(2), 16));
22805  }
22806  if (/^#\d+$/.test(entity)) {
22807    return String.fromCodePoint(parseInt(entity.slice(1), 10));
22808  }
22809  return match;
22810}
22811
22812/**
22813 * Set of tagName|propertyName corresponding to Trusted Types sinks. Properties applying to all
22814 * tags use '*'.
22815 *
22816 * Extracted from, and should be kept in sync with
22817 * https://w3c.github.io/webappsec-trusted-types/dist/spec/#integrations
22818 */
22819const TRUSTED_TYPES_SINKS = new Set([
22820// NOTE: All strings in this set *must* be lowercase!
22821// TrustedHTML
22822'iframe|srcdoc', '*|innerhtml', '*|outerhtml',
22823// NB: no TrustedScript here, as the corresponding tags are stripped by the compiler.
22824// TrustedScriptURL
22825'embed|src', 'object|codebase', 'object|data']);
22826/**
22827 * isTrustedTypesSink returns true if the given property on the given DOM tag is a Trusted Types
22828 * sink. In that case, use `ElementSchemaRegistry.securityContext` to determine which particular
22829 * Trusted Type is required for values passed to the sink:
22830 * - SecurityContext.HTML corresponds to TrustedHTML
22831 * - SecurityContext.RESOURCE_URL corresponds to TrustedScriptURL
22832 */
22833function isTrustedTypesSink(tagName, propName) {
22834  // Make sure comparisons are case insensitive, so that case differences between attribute and
22835  // property names do not have a security impact.
22836  tagName = tagName.toLowerCase();
22837  propName = propName.toLowerCase();
22838  return TRUSTED_TYPES_SINKS.has(tagName + '|' + propName) || TRUSTED_TYPES_SINKS.has('*|' + propName);
22839}
22840const setI18nRefs = (htmlNode, i18nNode) => {
22841  if (htmlNode instanceof NodeWithI18n) {
22842    if (i18nNode instanceof IcuPlaceholder && htmlNode.i18n instanceof Message) {
22843      // This html node represents an ICU but this is a second processing pass, and the legacy id
22844      // was computed in the previous pass and stored in the `i18n` property as a message.
22845      // We are about to wipe out that property so capture the previous message to be reused when
22846      // generating the message for this ICU later. See `_generateI18
22846nMessage()`.
22847      i18nNode.previousMessage = htmlNode.i18n;
22848    }
22849    htmlNode.i18n = i18nNode;
22850  }
22851  return i18nNode;
22852};
22853/**
22854 * This visitor walks over HTML parse tree and converts information stored in
22855 * i18n-related attributes ("i18n" and "i18n-*") into i18n meta object that is
22856 * stored with other element's and attribute's information.
22857 */
22858class I18nMetaVisitor {
22859  constructor(interpolationConfig = DEFAULT_INTERPOLATION_CONFIG, keepI18nAttrs = false, enableI18nLegacyMessageIdFormat = false, containerBlocks = DEFAULT_CONTAINER_BLOCKS) {
22860    this.interpolationConfig = interpolationConfig;
22861    this.keepI18nAttrs = keepI18nAttrs;
22862    this.enableI18nLegacyMessageIdFormat = enableI18nLegacyMessageIdFormat;
22863    this.containerBlocks = containerBlocks;
22864    // whether visited nodes contain i18n information
22865    this.hasI18nMeta = false;
22866    this._errors = [];
22867  }
22868  _generateI18nMessage(nodes, meta = '', visitNodeFn) {
22869    const {
22870      meaning,
22871      description,
22872      customId
22873    } = this._parseMetadata(meta);
22874    const createI18nMessage = createI18nMessageFactory(this.interpolationConfig, this.containerBlocks);
22875    const message = createI18nMessage(nodes, meaning, description, customId, visitNodeFn);
22876    this._setMessageId(message, meta);
22877    this._setLegacyIds(message, meta);
22878    return message;
22879  }
22880  visitAllWithErrors(nodes) {
22881    const result = nodes.map(node => node.visit(this, null));
22882    return new ParseTreeResult(result, this._errors);
22883  }
22884  visitElement(element) {
22885    let message = undefined;
22886    if (hasI18nAttrs(element)) {
22887      this.hasI18nMeta = true;
22888      const attrs = [];
22889      const attrsMeta = {};
22890      for (const attr of element.attrs) {
22891        if (attr.name === I18N_ATTR) {
22892          // root 'i18n' node attribute
22893          const i18n = element.i18n || attr.value;
22894          message = this._generateI18nMessage(element.children, i18n, setI18nRefs);
22895          if (message.nodes.length === 0) {
22896            // Ignore the message if it is empty.
22897            message = undefined;
22898          }
22899          // Store the message on the element
22900          element.i18n = message;
22901        } else if (attr.name.startsWith(I18N_ATTR_PREFIX)) {
22902          // 'i18n-*' attributes
22903          const name = attr.name.slice(I18N_ATTR_PREFIX.length);
22904          if (isTrustedTypesSink(element.name, name)) {
22905            this._reportError(attr, `Translating attribute '${name}' is disallowed for security reasons.`);
22906          } else {
22907            attrsMeta[name] = attr.value;
22908          }
22909        } else {
22910          // non-i18n attributes
22911          attrs.push(attr);
22912        }
22913      }
22914      // set i18n meta for attributes
22915      if (Object.keys(attrsMeta).length) {
22916        for (const attr of attrs) {
22917          const meta = attrsMeta[attr.name];
22918          // do not create translation for empty attributes
22919          if (meta !== undefined && attr.value) {
22920            attr.i18n = this._generateI18nMessage([attr], attr.i18n || meta);
22921          }
22922        }
22923      }
22924      if (!this.keepI18nAttrs) {
22925        // update element's attributes,
22926        // keeping only non-i18n related ones
22927        element.attrs = attrs;
22928      }
22929    }
22930    visitAll(this, element.children, message);
22931    return element;
22932  }
22933  visitExpansion(expansion, currentMessage) {
22934    let message;
22935    const meta = expansion.i18n;
22936    this.hasI18nMeta = true;
22937    if (meta instanceof IcuPlaceholder) {
22938      // set ICU placeholder name (e.g. "ICU_1"),
22939      // generated while processing root element contents,
22940      // so we can reference it when we output translation
22941      const name = meta.name;
22942      message = this._generateI18nMessage([expansion], meta);
22943      const icu = icuFromI18nMessage(message);
22944      icu.name = name;
22945      if (currentMessage !== null) {
22946        // Also update the placeholderToMessage map with this new message
22947        currentMessage.placeholderToMessage[name] = message;
22948      }
22949    } else {
22950      // ICU is a top level message, try to use metadata from container element if provided via
22951      // `context` argument. Note: context may not be available for standalone ICUs (without
22952      // wrapping element), so fallback to ICU metadata in this case.
22953      message = this._generateI18nMessage([expansion], currentMessage || meta);
22954    }
22955    expansion.i18n = message;
22956    return expansion;
22957  }
22958  visitText(text) {
22959    return text;
22960  }
22961  visitAttribute(attribute) {
22962    return attribute;
22963  }
22964  visitComment(comment) {
22965    return comment;
22966  }
22967  visitExpansionCase(expansionCase) {
22968    return expansionCase;
22969  }
22970  visitBlock(block, context) {
22971    visitAll(this, block.children, context);
22972    return block;
22973  }
22974  visitBlockParameter(parameter, context) {
22975    return parameter;
22976  }
22977  /**
22978   * Parse the general form `meta` passed into extract the explicit metadata needed to create a
22979   * `Message`.
22980   *
22981   * There are three possibilities for the `meta` variable
22982   * 1) a string from an `i18n` template attribute: parse it to extract the metadata values.
22983   * 2) a `Message` from a previous processing pass: reuse the metadata values in the message.
22984   * 4) other: ignore this and just process the message metadata as normal
22985   *
22986   * @param meta the bucket that holds information about the message
22987   * @returns the parsed metadata.
22988   */
22989  _parseMetadata(meta) {
22990    return typeof meta === 'string' ? parseI18nMeta(meta) : meta instanceof Message ? meta : {};
22991  }
22992  /**
22993   * Generate (or restore) message id if not specified already.
22994   */
22995  _setMessageId(message, meta) {
22996    if (!message.id) {
22997      message.id = meta instanceof Message && meta.id || decimalDigest(message);
22998    }
22999  }
23000  /**
23001   * Update the `message` with a `legacyId` if necessary.
23002   *
23003   * @param message the message whose legacy id should be set
23004   * @param meta information about the message being processed
23005   */
23006  _setLegacyIds(message, meta) {
23007    if (this.enableI18nLegacyMessageIdFormat) {
23008      message.legacyIds = [computeDigest(message), computeDecimalDigest(message)];
23009    } else if (typeof meta !== 'string') {
23010      // This occurs if we are doing the 2nd pass after whitespace removal (see `parseTemplate()` in
23011      // `packages/compiler/src/render3/view/template.ts`).
23012      // In that case we want to reuse the legacy message generated in the 1st pass (see
23013      // `setI18nRefs()`).
23014      const previousMessage = meta instanceof Message ? meta : meta instanceof IcuPlaceholder ? meta.previousMessage : undefined;
23015      message.legacyIds = previousMessage ? previousMessage.legacyIds : [];
23016    }
23017  }
23018  _reportError(node, msg) {
23019    this._errors.push(new I18nError(node.sourceSpan, msg));
23020  }
23021}
23022/** I18n separators for metadata **/
23023const I18N_MEANING_SEPARATOR = '|';
23024const I18N_ID_SEPARATOR = '@@';
23025/**
23026 * Parses i18n metas like:
23027 *  - "@@id",
23028 *  - "description[@@id]",
23029 *  - "meaning|description[@@id]"
23030 * and returns an object with parsed output.
23031 *
23032 * @param meta String that represents i18n meta
23033 * @returns Object with id, meaning and description fields
23034 */
23035function parseI18nMeta(meta = '') {
23036  let customId;
23037  let meaning;
23038  let description;
23039  meta = meta.trim();
23040  if (meta) {
23041    const idIndex = meta.indexOf(I18N_ID_SEPARATOR);
23042    const descIndex = meta.indexOf(I18N_MEANING_SEPARATOR);
23043    let meaningAndDesc;
23044    [meaningAndDesc, customId] = idIndex > -1 ? [meta.slice(0, idIndex), meta.slice(idIndex + 2)] : [meta, ''];
23045    [meaning, description] = descIndex > -1 ? [meaningAndDesc.slice(0, descIndex), meaningAndDesc.slice(descIndex + 1)] : ['', meaningAndDesc];
23046  }
23047  return {
23048    customId,
23049    meaning,
23050    description
23051  };
23052}
23053// Converts i18n meta information for a message (id, description, meaning)
23054// to a JsDoc statement formatted as expected by the Closure compiler.
23055function i18nMetaToJSDoc(meta) {
23056  const tags = [];
23057  if (meta.description) {
23058    tags.push({
23059      tagName: "desc" /* o.JSDocTagName.Desc */,
23060      text: meta.description
23061    });
23062  } else {
23063    // Suppress the JSCompiler warning that a `@desc` was not given for this message.
23064    tags.push({
23065      tagName: "suppress" /* o.JSDocTagName.Suppress */,
23066      text: '{msgDescriptions}'
23067    });
23068  }
23069  if (meta.meaning) {
23070    tags.push({
23071      tagName: "meaning" /* o.JSDocTagName.Meaning */,
23072      text: meta.meaning
23073    });
23074  }
23075  return jsDocComment(tags);
23076}
23077
23078/** Closure uses `goog.getMsg(message)` to lookup translations */
23079const GOOG_GET_MSG = 'goog.getMsg';
23080/**
23081 * Generates a `goog.getMsg()` statement and reassignment. The template:
23082 *
23083 * ```html
23084 * <div i18n>Sent from {{ sender }} to <span class="receiver">{{ receiver }}</span></div>
23085 * ```
23086 *
23087 * Generates:
23088 *
23089 * ```typescript
23090 * const MSG_FOO = goog.getMsg(
23091 *   // Message template.
23092 *   'Sent from {$interpolation} to {$startTagSpan}{$interpolation_1}{$closeTagSpan}.',
23093 *   // Placeholder values, set to magic strings which get replaced by the Angular runtime.
23094 *   {
23095 *     'interpolation': '\uFFFD0\uFFFD',
23096 *     'startTagSpan': '\uFFFD1\uFFFD',
23097 *     'interpolation_1': '\uFFFD2\uFFFD',
23098 *     'closeTagSpan': '\uFFFD3\uFFFD',
23099 *   },
23100 *   // Options bag.
23101 *   {
23102 *     // Maps each placeholder to the original Angular source code which generates it's value.
23103 *     original_code: {
23104 *       'interpolation': '{{ sender }}',
23105 *       'startTagSpan': '<span class="receiver">',
23106 *       'interpolation_1': '{{ receiver }}',
23107 *       'closeTagSpan': '</span>',
23108 *     },
23109 *   },
23110 * );
23111 * const I18N_0 = MSG_FOO;
23112 * ```
23113 */
23114function createGoogleGetMsgStatements(variable$1, message, closureVar, placeholderValues) {
23115  const messageString = serializeI18nMessageForGetMsg(message);
23116  const args = [literal(messageString)];
23117  if (Object.keys(placeholderValues).length) {
23118    // Message template parameters containing the magic strings replaced by the Angular runtime with
23119    // real data, e.g. `{'interpolation': '\uFFFD0\uFFFD'}`.
23120    args.push(mapLiteral(formatI18nPlaceholderNamesInMap(placeholderValues, true /* useCamelCase */), true /* quoted */));
23121    // Message options object, which contains original source code for placeholders (as they are
23122    // present in a template, e.g.
23123    // `{original_code: {'interpolation': '{{ name }}', 'startTagSpan': '<span>'}}`.
23124    args.push(mapLiteral({
23125      original_code: literalMap(Object.keys(placeholderValues).map(param => ({
23126        key: formatI18nPlaceholderName(param),
23127        quoted: true,
23128        value: message.placeholders[param] ?
23129        // Get source span for typical placeholder if it exists.
23130        literal(message.placeholders[param].sourceSpan.toString()) :
23131        // Otherwise must be an ICU expression, get it's source span.
23132        literal(message.placeholderToMessage[param].nodes.map(node => node.sourceSpan.toString()).join(''))
23133      })))
23134    }));
23135  }
23136  // /**
23137  //  * @desc description of message
23138  //  * @meaning meaning of message
23139  //  */
23140  // const MSG_... = goog.getMsg(..);
23141  // I18N_X = MSG_...;
23142  const googGetMsgStmt = closureVar.set(variable(GOOG_GET_MSG).callFn(args)).toConstDecl();
23143  googGetMsgStmt.addLeadingComment(i18nMetaToJSDoc(message));
23144  const i18nAssignmentStmt = new ExpressionStatement(variable$1.set(closureVar));
23145  return [googGetMsgStmt, i18nAssignmentStmt];
23146}
23147/**
23148 * This visitor walks over i18n tree and generates its string representation, including ICUs and
23149 * placeholders in `{$placeholder}` (for plain messages) or `{PLACEHOLDER}` (inside ICUs) format.
23150 */
23151class GetMsgSerializerVisitor {
23152  formatPh(value) {
23153    return `{$${formatI18nPlaceholderName(value)}}`;
23154  }
23155  visitText(text) {
23156    return text.value;
23157  }
23158  visitContainer(container) {
23159    return container.children.map(child => child.visit(this)).join('');
23160  }
23161  visitIcu(icu) {
23162    return serializeIcuNode(icu);
23163  }
23164  visitTagPlaceholder(ph) {
23165    return ph.isVoid ? this.formatPh(ph.startName) : `${this.formatPh(ph.startName)}${ph.children.map(child => child.visit(this)).join('')}${this.formatPh(ph.closeName)}`;
23166  }
23167  visitPlaceholder(ph) {
23168    return this.formatPh(ph.name);
23169  }
23170  visitBlockPlaceholder(ph) {
23171    return `${this.formatPh(ph.startName)}${ph.children.map(child => child.visit(this)).join('')}${this.formatPh(ph.closeName)}`;
23172  }
23173  visitIcuPlaceholder(ph, context) {
23174    return this.formatPh(ph.name);
23175  }
23176}
23177const serializerVisitor = new GetMsgSerializerVisitor();
23178function serializeI18nMessageForGetMsg(message) {
23179  return message.nodes.map(node => node.visit(serializerVisitor, null)).join('');
23180}
23181function createLocalizeStatements(variable, message, params) {
23182  const {
23183    messageParts,
23184    placeHolders
23185  } = serializeI18nMessageForLocalize(message);
23186  const sourceSpan = getSourceSpan(message);
23187  const expressions = placeHolders.map(ph => params[ph.text]);
23188  const localizedString$1 = localizedString(message, messageParts, placeHolders, expressions, sourceSpan);
23189  const variableInitialization = variable.set(localizedString$1);
23190  return [new ExpressionStatement(variableInitialization)];
23191}
23192/**
23193 * This visitor walks over an i18n tree, capturing literal strings and placeholders.
23194 *
23195 * The result can be used for generating the `$localize` tagged template literals.
23196 */
23197class LocalizeSerializerVisitor {
23198  constructor(placeholderToMessage, pieces) {
23199    this.placeholderToMessage = placeholderToMessage;
23200    this.pieces = pieces;
23201  }
23202  visitText(text) {
23203    if (this.pieces[this.pieces.length - 1] instanceof LiteralPiece) {
23204      // Two literal pieces in a row means that there was some comment node in-between.
23205      this.pieces[this.pieces.length - 1].text += text.value;
23206    } else {
23207      const sourceSpan = new ParseSourceSpan(text.sourceSpan.fullStart, text.sourceSpan.end, text.sourceSpan.fullStart, text.sourceSpan.details);
23208      this.pieces.push(new LiteralPiece(text.value, sourceSpan));
23209    }
23210  }
23211  visitContainer(container) {
23212    container.children.forEach(child => child.visit(this));
23213  }
23214  visitIcu(icu) {
23215    this.pieces.push(new LiteralPiece(serializeIcuNode(icu), icu.sourceSpan));
23216  }
23217  visitTagPlaceholder(ph) {
23218    this.pieces.push(this.createPlaceholderPiece(ph.startName, ph.startSourceSpan ?? ph.sourceSpan));
23219    if (!ph.isVoid) {
23220      ph.children.forEach(child => child.visit(this));
23221      this.pieces.push(this.createPlaceholderPiece(ph.closeName, ph.endSourceSpan ?? ph.sourceSpan));
23222    }
23223  }
23224  visitPlaceholder(ph) {
23225    this.pieces.push(this.createPlaceholderPiece(ph.name, ph.sourceSpan));
23226  }
23227  visitBlockPlaceholder(ph) {
23228    this.pieces.push(this.createPlaceholderPiece(ph.startName, ph.startSourceSpan ?? ph.sourceSpan));
23229    ph.children.forEach(child => child.visit(this));
23230    this.pieces.push(this.createPlaceholderPiece(ph.closeName, ph.endSourceSpan ?? ph.sourceSpan));
23231  }
23232  visitIcuPlaceholder(ph) {
23233    this.pieces.push(this.createPlaceholderPiece(ph.name, ph.sourceSpan, this.placeholderToMessage[ph.name]));
23234  }
23235  createPlaceholderPiece(name, sourceSpan, associatedMessage) {
23236    return new PlaceholderPiece(formatI18nPlaceholderName(name, /* useCamelCase */false), sourceSpan, associatedMessage);
23237  }
23238}
23239/**
23240 * Serialize an i18n message into two arrays: messageParts and placeholders.
23241 *
23242 * These arrays will be used to generate `$localize` tagged template literals.
23243 *
23244 * @param message The message to be serialized.
23245 * @returns an object containing the messageParts and placeholders.
23246 */
23247function serializeI18nMessageForLocalize(message) {
23248  const pieces = [];
23249  const serializerVisitor = new LocalizeSerializerVisitor(message.placeholderToMessage, pieces);
23250  message.nodes.forEach(node => node.visit(serializerVisitor));
23251  return processMessagePieces(pieces);
23252}
23253function getSourceSpan(message) {
23254  const startNode = message.nodes[0];
23255  const endNode = message.nodes[message.nodes.length - 1];
23256  return new ParseSourceSpan(startNode.sourceSpan.fullStart, endNode.sourceSpan.end, startNode.sourceSpan.fullStart, startNode.sourceSpan.details);
23257}
23258/**
23259 * Convert the list of serialized MessagePieces into two arrays.
23260 *
23261 * One contains the literal string pieces and the other the placeholders that will be replaced by
23262 * expressions when rendering `$localize` tagged template literals.
23263 *
23264 * @param pieces The pieces to process.
23265 * @returns an object containing the messageParts and placeholders.
23266 */
23267function processMessagePieces(pieces) {
23268  const messageParts = [];
23269  const placeHolders = [];
23270  if (pieces[0] instanceof PlaceholderPiece) {
23271    // The first piece was a placeholder so we need to add an initial empty message part.
23272    messageParts.push(createEmptyMessagePart(pieces[0].sourceSpan.start));
23273  }
23274  for (let i = 0; i < pieces.length; i++) {
23275    const part = pieces[i];
23276    if (part instanceof LiteralPiece) {
23277      messageParts.push(part);
23278    } else {
23279      placeHolders.push(part);
23280      if (pieces[i - 1] instanceof PlaceholderPiece) {
23281        // There were two placeholders in a row, so we need to add an empty message part.
23282        messageParts.push(createEmptyMessagePart(pieces[i - 1].sourceSpan.end));
23283      }
23284    }
23285  }
23286  if (pieces[pieces.length - 1] instanceof PlaceholderPiece) {
23287    // The last piece was a placeholder so we need to add a final empty message part.
23288    messageParts.push(createEmptyMessagePart(pieces[pieces.length - 1].sourceSpan.end));
23289  }
23290  return {
23291    messageParts,
23292    placeHolders
23293  };
23294}
23295function createEmptyMessagePart(location) {
23296  return new LiteralPiece('', new ParseSourceSpan(location, location));
23297}
23298
23299/** Name of the global variable that is used to determine if we use Closure translations or not */
23300const NG_I18N_CLOSURE_MODE$1 = 'ngI18nClosureMode';
23301/**
23302 * Prefix for non-`goog.getMsg` i18n-related vars.
23303 * Note: the prefix uses lowercase characters intentionally due to a Closure behavior that
23304 * considers variables like `I18N_0` as constants and throws an error when their value changes.
23305 */
23306const TRANSLATION_VAR_PREFIX = 'i18n_';
23307/** Prefix of ICU expressions for post processing */
23308const I18N_ICU_MAPPING_PREFIX = 'I18N_EXP_';
23309/**
23310 * The escape sequence used for message param values.
23311 */
23312const ESCAPE = '\uFFFD';
23313/**
23314 * Lifts i18n properties into the consts array.
23315 * TODO: Can we use `ConstCollectedExpr`?
23316 * TODO: The way the various attributes are linked together is very complex. Perhaps we 
23316could
23317 * simplify the process, maybe by combining the context and message ops?
23318 */
23319function collectI18nConsts(job) {
23320  const fileBasedI18nSuffix = job.relativeContextFilePath.replace(/[^A-Za-z0-9]/g, '_').toUpperCase() + '_';
23321  // Step One: Build up various lookup maps we need to collect all the consts.
23322  // Context Xref -> Extracted Attribute Ops
23323  const extractedAttributesByI18nContext = new Map();
23324  // Element/ElementStart Xref -> I18n Attributes config op
23325  const i18nAttributesByElement = new Map();
23326  // Element/ElementStart Xref -> All I18n Expression ops for attrs on that target
23327  const i18nExpressionsByElement = new Map();
23328  // I18n Message Xref -> I18n Message Op (TODO: use a central op map)
23329  const messages = new Map();
23330  for (const unit of job.units) {
23331    for (const op of unit.ops()) {
23332      if (op.kind === OpKind.ExtractedAttribute && op.i18nContext !== null) {
23333        const attributes = extractedAttributesByI18nContext.get(op.i18nContext) ?? [];
23334        attributes.push(op);
23335        extractedAttributesByI18nContext.set(op.i18nContext, attributes);
23336      } else if (op.kind === OpKind.I18nAttributes) {
23337        i18nAttributesByElement.set(op.target, op);
23338      } else if (op.kind === OpKind.I18nExpression && op.usage === I18nExpressionFor.I18nAttribute) {
23339        const expressions = i18nExpressionsByElement.get(op.target) ?? [];
23340        expressions.push(op);
23341        i18nExpressionsByElement.set(op.target, expressions);
23342      } else if (op.kind === OpKind.I18nMessage) {
23343        messages.set(op.xref, op);
23344      }
23345    }
23346  }
23347  // Step Two: Serialize the extracted i18n messages for root i18n blocks and i18n attributes into
23348  // the const array.
23349  //
23350  // Also, each i18n message will have a variable expression that can refer to its
23351  // value. Store these expressions in the appropriate place:
23352  // 1. For normal i18n content, it also goes in the const array. We save the const index to use
23353  // later.
23354  // 2. For extracted attributes, it becomes the value of the extracted attribute instruction.
23355  // 3. For i18n bindings, it will go in a separate const array instruction below; for now, we just
23356  // save it.
23357  const i18nValuesByContext = new Map();
23358  const messageConstIndices = new Map();
23359  for (const unit of job.units) {
23360    for (const op of unit.create) {
23361      if (op.kind === OpKind.I18nMessage) {
23362        if (op.messagePlaceholder === null) {
23363          const {
23364            mainVar,
23365            statements
23366          } = collectMessage(job, fileBasedI18nSuffix, messages, op);
23367          if (op.i18nBlock !== null) {
23368            // This is a regular i18n message with a corresponding i18n block. Collect it into the
23369            // const array.
23370            const i18nConst = job.addConst(mainVar, statements);
23371            messageConstIndices.set(op.i18nBlock, i18nConst);
23372          } else {
23373            // This is an i18n attribute. Extract the initializers into the const pool.
23374            job.constsInitializers.push(...statements);
23375            // Save the i18n variable value for later.
23376            i18nValuesByContext.set(op.i18nContext, mainVar);
23377            // This i18n message may correspond to an individual extracted attribute. If so, The
23378            // value of that attribute is updated to read the extracted i18n variable.
23379            const attributesForMessage = extractedAttributesByI18nContext.get(op.i18nContext);
23380            if (attributesForMessage !== undefined) {
23381              for (const attr of attributesForMessage) {
23382                attr.expression = mainVar.clone();
23383              }
23384            }
23385          }
23386        }
23387        OpList.remove(op);
23388      }
23389    }
23390  }
23391  // Step Three: Serialize I18nAttributes configurations into the const array. Each I18nAttributes
23392  // instruction has a config array, which contains k-v pairs describing each binding name, and the
23393  // i18n variable that provides the value.
23394  for (const unit of job.units) {
23395    for (const elem of unit.create) {
23396      if (isElementOrContainerOp(elem)) {
23397        const i18nAttributes = i18nAttributesByElement.get(elem.xref);
23398        if (i18nAttributes === undefined) {
23399          // This element is not associated with an i18n attributes configuration instruction.
23400          continue;
23401        }
23402        let i18nExpressions = i18nExpressionsByElement.get(elem.xref);
23403        if (i18nExpressions === undefined) {
23404          // Unused i18nAttributes should have already been removed.
23405          // TODO: Should the removal of those dead instructions be merged with this phase?
23406          throw new Error('AssertionError: Could not find any i18n expressions associated with an I18nAttributes instruction');
23407        }
23408        // Find expressions for all the unique property names, removing duplicates.
23409        const seenPropertyNames = new Set();
23410        i18nExpressions = i18nExpressions.filter(i18nExpr => {
23411          const seen = seenPropertyNames.has(i18nExpr.name);
23412          seenPropertyNames.add(i18nExpr.name);
23413          return !seen;
23414        });
23415        const i18nAttributeConfig = i18nExpressions.flatMap(i18nExpr => {
23416          const i18nExprValue = i18nValuesByContext.get(i18nExpr.context);
23417          if (i18nExprValue === undefined) {
23418            throw new Error('AssertionError: Could not find i18n expression\'s value');
23419          }
23420          return [literal(i18nExpr.name), i18nExprValue];
23421        });
23422        i18nAttributes.i18nAttributesConfig = job.addConst(new LiteralArrayExpr(i18nAttributeConfig));
23423      }
23424    }
23425  }
23426  // Step Four: Propagate the extracted const index into i18n ops that messages were extracted from.
23427  for (const unit of job.units) {
23428    for (const op of unit.create) {
23429      if (op.kind === OpKind.I18nStart) {
23430        const msgIndex = messageConstIndices.get(op.root);
23431        if (msgIndex === undefined) {
23432          throw new Error('AssertionError: Could not find corresponding i18n block 
23432index for an i18n message op; was an i18n message incorrectly assumed to correspond to an attribute?');
23433        }
23434        op.messageIndex = msgIndex;
23435      }
23436    }
23437  }
23438}
23439/**
23440 * Collects the given message into a set of statements that can be added to the const array.
23441 * This will recursively collect any sub-messages referenced from the parent message as well.
23442 */
23443function collectMessage(job, fileBasedI18nSuffix, messages, messageOp) {
23444  // Recursively collect any sub-messages, record each sub-message's main variable under its
23445  // placeholder so that we can add them to the params for the parent message. It is possible
23446  // that multiple sub-messages will share the same placeholder, so we need to track an array of
23447  // variables for each placeholder.
23448  const statements = [];
23449  const subMessagePlaceholders = new Map();
23450  for (const subMessageId of messageOp.subMessages) {
23451    const subMessage = messages.get(subMessageId);
23452    const {
23453      mainVar: subMessageVar,
23454      statements: subMessageStatements
23455    } = collectMessage(job, fileBasedI18nSuffix, messages, subMessage);
23456    statements.push(...subMessageStatements);
23457    const subMessages = subMessagePlaceholders.get(subMessage.messagePlaceholder) ?? [];
23458    subMessages.push(subMessageVar);
23459    subMessagePlaceholders.set(subMessage.messagePlaceholder, subMessages);
23460  }
23461  addSubMessageParams(messageOp, subMessagePlaceholders);
23462  // Sort the params for consistency with TemaplateDefinitionBuilder output.
23463  messageOp.params = new Map([...messageOp.params.entries()].sort());
23464  const mainVar = variable(job.pool.uniqueName(TRANSLATION_VAR_PREFIX));
23465  // Closure Compiler requires const names to start with `MSG_` but disallows any other
23466  // const to start with `MSG_`. We define a variable starting with `MSG_` just for the
23467  // `goog.getMsg` call
23468  const closureVar = i18nGenerateClosureVar(job.pool, messageOp.message.id, fileBasedI18nSuffix, job.i18nUseExternalIds);
23469  let transformFn = undefined;
23470  // If nescessary, add a post-processing step and resolve any placeholder params that are
23471  // set in post-processing.
23472  if (messageOp.needsPostprocessing || messageOp.postprocessingParams.size > 0) {
23473    // Sort the post-processing params for consistency with TemaplateDefinitionBuilder output.
23474    const postprocessingParams = Object.fromEntries([...messageOp.postprocessingParams.entries()].sort());
23475    const formattedPostprocessingParams = formatI18nPlaceholderNamesInMap(postprocessingParams, /* useCamelCase */false);
23476    const extraTransformFnParams = [];
23477    if (messageOp.postprocessingParams.size > 0) {
23478      extraTransformFnParams.push(mapLiteral(formattedPostprocessingParams, /* quoted */true));
23479    }
23480    transformFn = expr => importExpr(Identifiers.i18nPostprocess).callFn([expr, ...extraTransformFnParams]);
23481  }
23482  // Add the message's statements
23483  statements.push(...getTranslationDeclStmts$1(messageOp.message, mainVar, closureVar, messageOp.params, transformFn));
23484  return {
23485    mainVar,
23486    statements
23487  };
23488}
23489/**
23490 * Adds the given subMessage placeholders to the given message op.
23491 *
23492 * If a placeholder only corresponds to a single sub-message variable, we just set that variable
23493 * as the param value. However, if the placeholder corresponds to multiple sub-message
23494 * variables, we need to add a special placeholder value that is handled by the post-processing
23495 * step. We then add the array of variables as a post-processing param.
23496 */
23497function addSubMessageParams(messageOp, subMessagePlaceholders) {
23498  for (const [placeholder, subMessages] of subMessagePlaceholders) {
23499    if (subMessages.length === 1) {
23500      messageOp.params.set(placeholder, subMessages[0]);
23501    } else {
23502      messageOp.params.set(placeholder, literal(`${ESCAPE}${I18N_ICU_MAPPING_PREFIX}${placeholder}${ESCAPE}`));
23503      messageOp.postprocessingParams.set(placeholder, literalArr(subMessages));
23504    }
23505  }
23506}
23507/**
23508 * Generate statements that define a given translation message.
23509 *
23510 * ```
23511 * var I18N_1;
23512 * if (typeof ngI18nClosureMode !== undefined && ngI18nClosureMode) {
23513 *     var MSG_EXTERNAL_XXX = goog.getMsg(
23514 *          "Some message with {$interpolation}!",
23515 *          { "interpolation": "\uFFFD0\uFFFD" }
23516 *     );
23517 *     I18N_1 = MSG_EXTERNAL_XXX;
23518 * }
23519 * else {
23520 *     I18N_1 = $localize`Some message with ${'\uFFFD0\uFFFD'}!`;
23521 * }
23522 * ```
23523 *
23524 * @param message The original i18n AST message node
23525 * @param variable The variable that will be assigned the translation, e.g. `I18N_1`.
23526 * @param closureVar The variable for Closure `goog.getMsg` calls, e.g. `MSG_EXTERNAL_XXX`.
23527 * @param params Object mapping placeholder names to their values (e.g.
23528 * `{ "interpolation": "\uFFFD0\uFFFD" }`).
23529 * @param transformFn Optional transformation function that will be applied to the translation
23530 *     (e.g.
23531 * post-processing).
23532 * @returns An array of statements that defined a given translation.
23533 */
23534function getTranslationDeclStmts$1(message, variable, closureVar, params, transformFn) {
23535  const paramsObject = Object.fromEntries(params);
23536  const statements = [declareI18nVariable(variable), ifStmt(createClosureModeGuard$1(), createGoogleGetMsgStatements(variable, message, closureVar, paramsObject), createLocalizeStatements(variable, message, formatI18nPlaceholderNamesInMap(paramsObject, /* useCamelCase */false)))];
23537  if (transformFn) {
23538    statements.push(new ExpressionStatement(variable.set(transformFn(variable))));
23539  }
23540  return statements;
23541}
23542/**
23543 * Create the expression that will be used to guard the closure mode block
23544 * It is equivalent to:
23545 *
23546 * ```
23547 * typeof ngI18nClosureMode !== undefined && ngI18nClosureMode
23548 * ```
23549 */
23550function createClosureModeGuard$1() {
23551  return typeofExpr(variable(NG_I18N_CLOSURE_MODE$1)).notIdentical(literal('undefined', STRING_TYPE)).and(variable(NG_I18N_CLOSURE_MODE$1));
23552}
23553/**
23554 * Generates vars with Closure-specific names for i18n blocks (i.e. `MSG_XXX`).
23555 */
23556function i18nGenerateClosureVar(pool, messageId, fileBasedI18nSuffix, useExternalIds) {
23557  let name;
23558  const suffix = fileBasedI18nSuffix;
23559  if (useExternalIds) {
23560    const prefix = getTranslationConstPrefix(`EXTERNAL_`);
23561    const uniqueSuffix = pool.uniqueName(suffix);
23562    name = `${prefix}${sanitizeIdentifier(messageId)}$$${uniqueSuffix}`;
23563  } else {
23564    const prefix = getTranslationConstPrefix(suffix);
23565    name = pool.uniqueName(prefix);
23566  }
23567  return variable(name);
23568}
23569
23570/**
23571 * Removes text nodes within i18n blocks since they are already hardcoded into the i18n message.
23572 * Also, replaces interpolations on these text nodes with i18n expressions of the non-text portions,
23573 * which will be applied later.
23574 */
23575function convertI18nText(job) {
23576  for (const unit of job.units) {
23577    // Remove all text nodes within i18n blocks, their content is already captured in the i18n
23578    // message.
23579    let currentI18n = null;
23580    let currentIcu = null;
23581    const textNodeI18nBlocks = new Map();
23582    const textNodeIcus = new Map();
23583    const icuPlaceholderByText = new Map();
23584    for (const op of unit.create) {
23585      switch (op.kind) {
23586        case OpKind.I18nStart:
23587          if (op.context === null) {
23588            throw Error('I18n op should have its context set.');
23589          }
23590          currentI18n = op;
23591          break;
23592        case OpKind.I18nEnd:
23593          currentI18n = null;
23594          break;
23595        case OpKind.IcuStart:
23596          if (op.context === null) {
23597            throw Error('Icu op should have its context set.');
23598          }
23599          currentIcu = op;
23600          break;
23601        case OpKind.IcuEnd:
23602          currentIcu = null;
23603          break;
23604        case OpKind.Text:
23605          if (currentI18n !== null) {
23606            textNodeI18nBlocks.set(op.xref, currentI18n);
23607            textNodeIcus.set(op.xref, currentIcu);
23608            if (op.icuPlaceholder !== null) {
23609              // Create an op to represent the ICU placeholder. Initially set its static text to the
23610              // value of the text op, though this may be overwritten later if this text op is a
23611              // placeholder for an interpolation.
23612              const icuPlaceholderOp = createIcuPlaceholderOp(job.allocateXrefId(), op.icuPlaceholder, [op.initialValue]);
23613              OpList.replace(op, icuPlaceholderOp);
23614              icuPlaceholderByText.set(op.xref, icuPlaceholderOp);
23615            } else {
23616              // Otherwise just remove the text op, since its value is already accounted for in the
23617              // translated message.
23618              OpList.remove(op);
23619            }
23620          }
23621          break;
23622      }
23623    }
23624    // Update any interpolations to the removed text, and instead represent them as a series of i18n
23625    // expressions that we then apply.
23626    for (const op of unit.update) {
23627      switch (op.kind) {
23628        case OpKind.InterpolateText:
23629          if (!textNodeI18nBlocks.has(op.target)) {
23630            continue;
23631          }
23632          const i18nOp = textNodeI18nBlocks.get(op.target);
23633          const icuOp = textNodeIcus.get(op.target);
23634          const icuPlaceholder = icuPlaceholderByText.get(op.target);
23635          const contextId = icuOp ? icuOp.context : i18nOp.context;
23636          const resolutionTime = icuOp ? I18nParamResolutionTime.Postproccessing : I18nParamResolutionTime.Creation;
23637          const ops = [];
23638          for (let i = 0; i < op.interpolation.expressions.length; i++) {
23639            const expr = op.interpolation.expressions[i];
23640            // For now, this i18nExpression depends on the slot context of the enclosing i18n block.
23641            // Later, we will modify this, and advance to a different point.
23642            ops.push(createI18nExpressionOp(contextId, i18nOp.xref, i18nOp.xref, i18nOp.handle, expr, icuPlaceholder?.xref ?? null, op.interpolation.i18nPlaceholders[i] ?? null, resolutionTime, I18nExpressionFor.I18nText, '', expr.sourceSpan ?? op.sourceSpan));
23643          }
23644          OpList.replaceWithMany(op, ops);
23645          // If this interpolation is part of an ICU placeholder, add the strings and expressions to
23646          // the placeholder.
23647          if (icuPlaceholder !== undefined) {
23648            icuPlaceholder.strings = op.interpolation.strings;
23649          }
23650          break;
23651      }
23652    }
23653  }
23654}
23655
23656/**
23657 * Lifts local reference declarations on element-like structures within each view into an entry in
23658 * the `consts` array for the whole component.
23659 */
23660function liftLocalRefs(job) {
23661  for (const unit of job.units) {
23662    for (const op of unit.create) {
23663      switch (op.kind) {
23664        case OpKind.ElementStart:
23665        case OpKind.Template:
23666          if (!Array.isArray(op.localRefs)) {
23667            throw new Error(`AssertionError: expected localRefs to be an array still`);
23668          }
23669          op.numSlotsUsed += op.localRefs.length;
23670          if (op.localRefs.length > 0) {
23671            const localRefs = serializeLocalRefs(op.localRefs);
23672            op.localRefs = job.addConst(localRefs);
23673          } else {
23674            op.localRefs = null;
23675          }
23676          break;
23677      }
23678    }
23679  }
23680}
23681function serializeLocalRefs(refs) {
23682  const constRefs = [];
23683  for (const ref of refs) {
23684    constRefs.push(literal(ref.name), literal(ref.target));
23685  }
23686  return literalArr(constRefs);
23687}
23688
23689/**
23690 * Change namespaces between HTML, SVG and MathML, depending on the next element.
23691 */
23692function emitNamespaceChanges(job) {
23693  for (const unit of job.units) {
23694    let activeNamespace = Namespace.HTML;
23695    for (const op of unit.create) {
23696      if (op.kind !== OpKind.ElementStart) {
23697        continue;
23698      }
23699      if (op.namespace !== activeNamespace) {
23700        OpList.insertBefore(createNamespaceOp(op.namespace), op);
23701        activeNamespace = op.namespace;
23702      }
23703    }
23704  }
23705}
23706
23707/**
23708 * Parses string representation of a style and converts it into object literal.
23709 *
23710 * @param value string representation of style as used in the `style` attribute in HTML.
23711 *   Example: `color: red; height: auto`.
23712 * @returns An array of style property name and value pairs, e.g. `['color', 'red', 'height',
23713 * 'auto']`
23714 */
23715function parse(value) {
23716  // we use a string array here instead of a string map
23717  // because a string-map is not guaranteed to retain the
23718  // order of the entries whereas a string array can be
23719  // constructed in a [key, value, key, value] format.
23720  const styles = [];
23721  let i = 0;
23722  let parenDepth = 0;
23723  let quote = 0 /* Char.QuoteNone */;
23724  let valueStart = 0;
23725  let propStart = 0;
23726  let currentProp = null;
23727  while (i < value.length) {
23728    const token = value.charCodeAt(i++);
23729    switch (token) {
23730      case 40 /* Char.OpenParen */:
23731        parenDepth++;
23732        break;
23733      case 41 /* Char.CloseParen */:
23734        parenDepth--;
23735        break;
23736      case 39 /* Char.QuoteSingle */:
23737        // valueStart needs to be there since prop values don't
23738        // have quotes in CSS
23739        if (quote === 0 /* Char.QuoteNone */) {
23740          quote = 39 /* Char.QuoteSingle */;
23741        } else if (quote === 39 /* Char.QuoteSingle */ && value.charCodeAt(i - 1) !== 92 /* Char.BackSlash */) {
23742          quote = 0 /* Char.QuoteNone */;
23743        }
23744        break;
23745      case 34 /* Char.QuoteDouble */:
23746        // same logic as above
23747        if (quote === 0 /* Char.QuoteNone */) {
23748          quote = 34 /* Char.QuoteDouble */;
23749        } else if (quote === 34 /* Char.QuoteDouble */ && value.charCodeAt(i - 1) !== 92 /* Char.BackSlash */) {
23750          quote = 0 /* Char.QuoteNone */;
23751        }
23752        break;
23753      case 58 /* Char.Colon */:
23754        if (!currentProp && parenDepth === 0 && quote === 0 /* Char.QuoteNone */) {
23755          // TODO: Do not hyphenate CSS custom property names like: `--intentionallyCamelCase`
23756          currentProp = hyphenate(value.substring(propStart, i - 1).trim());
23757          valueStart = i;
23758        }
23759        break;
23760      case 59 /* Char.Semicolon */:
23761        if (currentProp && valueStart > 0 && parenDepth === 0 && quote === 0 /* Char.QuoteNone */) {
23762          const styleVal = value.substring(valueStart, i - 1).trim();
23763          styles.push(currentProp, styleVal);
23764          propStart = i;
23765          valueStart = 0;
23766          currentProp = null;
23767        }
23768        break;
23769    }
23770  }
23771  if (currentProp && valueStart) {
23772    const styleVal = value.slice(valueStart).trim();
23773    styles.push(currentProp, styleVal);
23774  }
23775  return styles;
23776}
23777function hyphenate(value) {
23778  return value.replace(/[a-z][A-Z]/g, v => {
23779    return v.charAt(0) + '-' + v.charAt(1);
23780  }).toLowerCase();
23781}
23782
23783/**
23784 * Generate names for functions and variables across all views.
23785 *
23786 * This includes propagating those names into any `ir.ReadVariableExpr`s of those variables, so that
23787 * the reads can be emitted correctly.
23788 */
23789function nameFunctionsAndVariables(job) {
23790  addNamesToView(job.root, job.componentName, {
23791    index: 0
23792  }, job.compatibility === CompatibilityMode.TemplateDefinitionBuilder);
23793}
23794function addNamesToView(unit, baseName, state, compatibility) {
23795  if (unit.fnName === null) {
23796    // Ensure unique names for view units. This is necessary because there might be multiple
23797    // components with same names in the context of the same pool. Only add the suffix
23798    // if really needed.
23799    unit.fnName = unit.job.pool.uniqueName(sanitizeIdentifier(`${baseName}_${unit.job.fnSuffix}`), /* alwaysIncludeSuffix */false);
23800  }
23801  // Keep track of the names we assign to variables in the view. We'll need to propagate these
23802  // into reads of those variables afterwards.
23803  const varNames = new Map();
23804  for (const op of unit.ops()) {
23805    switch (op.kind) {
23806      case OpKind.Property:
23807      case OpKind.HostProperty:
23808        if (op.isAnimationTrigger) {
23809          op.name = '@' + op.name;
23810        }
23811        break;
23812      case OpKind.Listener:
23813        if (op.handlerFnName !== null) {
23814          break;
23815        }
23816        if (!op.hostListener && op.targetSlot.slot === null) {
23817          throw new Error(`Expected a slot to be assigned`);
23818        }
23819        let animation = '';
23820        if (op.isAnimationListener) {
23821          op.name = `@${op.name}.${op.animationPhase}`;
23822          animation = 'animation';
23823        }
23824        if (op.hostListener) {
23825          op.handlerFnName = `${baseName}_${animation}${op.name}_HostBindingHandler`;
23826        } else {
23827          op.handlerFnName = `${unit.fnName}_${op.tag.replace('-', '_')}_${animation}${op.name}_${op.targetSlot.slot}_listener`;
23828        }
23829        op.handlerFnName = sanitizeIdentifier(op.handlerFnName);
23830        break;
23831      case OpKind.TwoWayListener:
23832        if (op.handlerFnName !== null) {
23833          break;
23834        }
23835        if (op.targetSlot.slot === null) {
23836          throw new Error(`Expected a slot to be assigned`);
23837        }
23838        op.handlerFnName = sanitizeIdentifier(`${unit.fnName}_${op.tag.replace('-', '_')}_${op.name}_${op.targetSlot.slot}_listener`);
23839        break;
23840      case OpKind.Variable:
23841        varNames.set(op.xref, getVariableName(unit, op.variable, state));
23842        break;
23843      case OpKind.RepeaterCreate:
23844        if (!(unit instanceof ViewCompilationUnit)) {
23845          throw new Error(`AssertionError: must be compiling a component`);
23846        }
23847        if (op.handle.slot === null) {
23848          throw new Error(`Expected slot to be assigned`);
23849        }
23850        if (op.emptyView !== null) {
23851          const emptyView = unit.job.views.get(op.emptyView);
23852          // Repeater empty view function is at slot +2 (metadata is in the first slot).
23853          addNamesToView(emptyView, `${baseName}_${op.functionNameSuffix}Empty_${op.handle.slot + 2}`, state, compatibility);
23854        }
23855        // Repeater primary view function is at slot +1 (metadata is in the first slot).
23856        addNamesToView(unit.job.views.get(op.xref), `${baseName}_${op.functionNameSuffix}_${op.handle.slot + 1}`, state, compatibility);
23857        break;
23858      case OpKind.Template:
23859        if (!(unit instanceof ViewCompilationUnit)) {
23860          throw new Error(`AssertionError: must be compiling a component`);
23861        }
23862        const childView = unit.job.views.get(op.xref);
23863        if (op.handle.slot === null) {
23864          throw new Error(`Expected slot to be assigned`);
23865        }
23866        const suffix = op.functionNameSuffix.length === 0 ? '' : `_${op.functionNameSuffix}`;
23867        addNamesToView(childView, `${baseName}${suffix}_${op.handle.slot}`, state, compatibility);
23868        break;
23869      case OpKind.StyleProp:
23870        op.name = normalizeStylePropName(op.name);
23871        if (compatibility) {
23872          op.name = stripImportant(op.name);
23873        }
23874        break;
23875      case OpKind.ClassProp:
23876        if (compatibility) {
23877          op.name = stripImportant(op.name);
23878        }
23879        break;
23880    }
23881  }
23882  // Having named all variables declared in the view, now we can push those names into the
23883  // `ir.ReadVariableExpr` expressions which represent reads of those variables.
23884  for (const op of unit.ops()) {
23885    visitExpressionsInOp(op, expr => {
23886      if (!(expr instanceof ReadVariableExpr) || expr.name !== null) {
23887        return;
23888      }
23889      if (!varNames.has(expr.xref)) {
23890        throw new Error(`Variable ${expr.xref} not yet named`);
23891      }
23892      expr.name = varNames.get(expr.xref);
23893    });
23894  }
23895}
23896function getVariableName(unit, variable, state) {
23897  if (variable.name === null) {
23898    switch (variable.kind) {
23899      case SemanticVariableKind.Context:
23900        variable.name = `ctx_r${state.index++}`;
23901        break;
23902      case SemanticVariableKind.Identifier:
23903        if (unit.job.compatibility === CompatibilityMode.TemplateDefinitionBuilder) {
23904          // TODO: Prefix increment and `_r` are for compatiblity with the old naming scheme.
23905          // This has the potential to cause collisions when `ctx` is the identifier, so we need a
23906          // special check for that as well.
23907          const compatPrefix = variable.identifier === 'ctx' ? 'i' : '';
23908          variable.name = `${variable.identifier}_${compatPrefix}r${++state.index}`;
23909        } else {
23910          variable.name = `${variable.identifier}_i${state.index++}`;
23911        }
23912        break;
23913      default:
23914        // TODO: Prefix increment for compatibility only.
23915        variable.name = `_r${++state.index}`;
23916        break;
23917    }
23918  }
23919  return variable.name;
23920}
23921/**
23922 * Normalizes a style prop name by hyphenating it (unless its a CSS variable).
23923 */
23924function normalizeStylePropName(name) {
23925  return name.startsWith('--') ? name : hyphenate(name);
23926}
23927/**
23928 * Strips `!important` out of the given style or class name.
23929 */
23930function stripImportant(name) {
23931  const importantIndex = name.indexOf('!important');
23932  if (importantIndex > -1) {
23933    return name.substring(0, importantIndex);
23934  }
23935  return name;
23936}
23937
23938/**
23939 * Merges logically sequential `NextContextExpr` operations.
23940 *
23941 * `NextContextExpr` can be referenced repeatedly, "popping" the runtime's context stack each time.
23942 * When two such expressions appear back-to-back, it's possible to merge them together into a single
23943 * `NextContextExpr` that steps multiple contexts. This merging is possible if all conditions are
23944 * met:
23945 *
23946 *   * The result of the `NextContextExpr` that's folded into the subsequent one is not stored (that
23947 *     is, the call is purely side-effectful).
23948 *   * No operations in between them uses the implicit context.
23949 */
23950function mergeNextContextExpressions(job) {
23951  for (const unit of job.units) {
23952    for (const op of unit.create) {
23953      if (op.kind === OpKind.Listener || op.kind === OpKind.TwoWayListener) {
23954        mergeNextContextsInOps(op.handlerOps);
23955      }
23956    }
23957    mergeNextContextsInOps(unit.update);
23958  }
23959}
23960function mergeNextContextsInOps(ops) {
23961  for (const op of ops) {
23962    // Look for a candidate operation to maybe merge.
23963    if (op.kind !== OpKind.Statement || !(op.statement instanceof ExpressionStatement) || !(op.statement.expr instanceof NextContextExpr)) {
23964      continue;
23965    }
23966    const mergeSteps = op.statement.expr.steps;
23967    // Try to merge this `ir.NextContextExpr`.
23968    let tryToMerge = true;
23969    for (let candidate = op.next; candidate.kind !== OpKind.ListEnd && tryToMerge; candidate = candidate.next) {
23970      visitExpressionsInOp(candidate, (expr, flags) => {
23971        if (!isIrExpression(expr)) {
23972          return expr;
23973        }
23974        if (!tryToMerge) {
23975          // Either we've already merged, or failed to merge.
23976          return;
23977        }
23978        if (flags & VisitorContextFlag.InChildOperation) {
23979          // We cannot merge into child operations.
23980          return;
23981        }
23982        switch (expr.kind) {
23983          case ExpressionKind.NextContext:
23984            // Merge the previous `ir.NextContextExpr` into this one.
23985            expr.steps += mergeSteps;
23986            OpList.remove(op);
23987            tryToMerge = false;
23988            break;
23989          case ExpressionKind.GetCurrentView:
23990          case ExpressionKind.Reference:
23991            // Can't merge past a dependency on the context.
23992            tryToMerge = false;
23993            break;
23994        }
23995        return;
23996      });
23997    }
23998  }
23999}
24000const CONTAINER_TAG = 'ng-container';
24001/**
24002 * Replace an `Element` or `ElementStart` whose tag is `ng-container` with a specific op.
24003 */
24004function generateNgContainerOps(job) {
24005  for (const unit of job.units) {
24006    const updatedElementXrefs = new Set();
24007    for (const op of unit.create) {
24008      if (op.kind === OpKind.ElementStart && op.tag === CONTAINER_TAG) {
24009        // Transmute the `ElementStart` instruction to `ContainerStart`.
24010        op.kind = OpKind.ContainerStart;
24011        updatedElementXrefs.add(op.xref);
24012      }
24013      if (op.kind === OpKind.ElementEnd && updatedElementXrefs.has(op.xref)) {
24014        // This `ElementEnd` is associated with an `ElementStart` we already transmuted.
24015        op.kind = OpKind.ContainerEnd;
24016      }
24017    }
24018  }
24019}
24020
24021/**
24022 * Looks up an element in the given map by xref ID.
24023 */
24024function lookupElement(elements, xref) {
24025  const el = elements.get(xref);
24026  if (el === undefined) {
24027    throw new Error('All attributes should have an element-like target.');
24028  }
24029  return el;
24030}
24031/**
24032 * When a container is marked with `ngNonBindable`, the non-bindable characteristic also applies to
24033 * all descendants of that container. Therefore, we must emit `disableBindings` and `enableBindings`
24034 * instructions for every such container.
24035 */
24036function disableBindings$1(job) {
24037  const elements = new Map();
24038  for (const view of job.units) {
24039    for (const op of view.create) {
24040      if (!isElementOrContainerOp(op)) {
24041        continue;
24042      }
24043      elements.set(op.xref, op);
24044    }
24045  }
24046  for (const unit of job.units) {
24047    for (const op of unit.create) {
24048      if ((op.kind === OpKind.ElementStart || op.kind === OpKind.ContainerStart) && op.nonBindable) {
24049        OpList.insertAfter(createDisableBindingsOp(op.xref), op);
24050      }
24051      if ((op.kind === OpKind.ElementEnd || op.kind === OpKind.ContainerEnd) && lookupElement(elements, op.xref).nonBindable) {
24052        OpList.insertBefore(createEnableBindingsOp(op.xref), op);
24053      }
24054    }
24055  }
24056}
24057
24058/**
24059 * Nullish coalescing expressions such as `a ?? b` have different semantics in Angular templates as
24060 * compared to JavaScript. In particular, they default to `null` instead of `undefined`. Therefore,
24061 * we replace them with ternary expressions, assigning temporaries as needed to avoid re-evaluating
24062 * the same sub-expression multiple times.
24063 */
24064function generateNullishCoalesceExpressions(job) {
24065  for (const unit of job.units) {
24066    for (const op of unit.ops()) {
24067      transformExpressionsInOp(op, expr => {
24068        if (!(expr instanceof BinaryOperatorExpr) || expr.operator !== BinaryOperator.NullishCoalesce) {
24069          return expr;
24070        }
24071        const assignment = new AssignTemporaryExpr(expr.lhs.clone(), job.allocateXrefId());
24072        const read = new ReadTemporaryExpr(assignment.xref);
24073        // TODO: When not in compatibility mode for TemplateDefinitionBuilder, we can just emit
24074        // `t != null` instead of including an undefined check as well.
24075        return new ConditionalExpr(new BinaryOperatorExpr(BinaryOperator.And, new BinaryOperatorExpr(BinaryOperator.NotIdentical, assignment, NULL_EXPR), new BinaryOperatorExpr(BinaryOperator.NotIdentical, read, new LiteralExpr(undefined))), read.clone(), expr.rhs);
24076      }, VisitorContextFlag.None);
24077    }
24078  }
24079}
24080function kindTest(kind) {
24081  return op => op.kind === kind;
24082}
24083function kindWithInterpolationTest(kind, interpolation) {
24084  return op => {
24085    return op.kind === kind && interpolation === op.expression instanceof Interpolation;
24086  };
24087}
24088function basicListenerKindTest(op) {
24089  return op.kind === OpKind.Listener && !(op.hostListener && op.isAnimationListener) || op.
24089kind === OpKind.TwoWayListener;
24090}
24091function nonInterpolationPropertyKindTest(op) {
24092  return (op.kind === OpKind.Property || op.kind === OpKind.TwoWayProperty) && !(op.expression instanceof Interpolation);
24093}
24094/**
24095 * Defines the groups based on `OpKind` that ops will be divided into, for the various create
24096 * op kinds. Ops will be collected into groups, then optionally transformed, before recombining
24097 * the groups in the order defined here.
24098 */
24099const CREATE_ORDERING = [{
24100  test: op => op.kind === OpKind.Listener && op.hostListener && op.isAnimationListener
24101}, {
24102  test: basicListenerKindTest
24103}];
24104/**
24105 * Defines the groups based on `OpKind` that ops will be divided into, for the various update
24106 * op kinds.
24107 */
24108const UPDATE_ORDERING = [{
24109  test: kindTest(OpKind.StyleMap),
24110  transform: keepLast
24111}, {
24112  test: kindTest(OpKind.ClassMap),
24113  transform: keepLast
24114}, {
24115  test: kindTest(OpKind.StyleProp)
24116}, {
24117  test: kindTest(OpKind.ClassProp)
24118}, {
24119  test: kindWithInterpolationTest(OpKind.Attribute, true)
24120}, {
24121  test: kindWithInterpolationTest(OpKind.Property, true)
24122}, {
24123  test: nonInterpolationPropertyKindTest
24124}, {
24125  test: kindWithInterpolationTest(OpKind.Attribute, false)
24126}];
24127/**
24128 * Host bindings have their own update ordering.
24129 */
24130const UPDATE_HOST_ORDERING = [{
24131  test: kindWithInterpolationTest(OpKind.HostProperty, true)
24132}, {
24133  test: kindWithInterpolationTest(OpKind.HostProperty, false)
24134}, {
24135  test: kindTest(OpKind.Attribute)
24136}, {
24137  test: kindTest(OpKind.StyleMap),
24138  transform: keepLast
24139}, {
24140  test: kindTest(OpKind.ClassMap),
24141  transform: keepLast
24142}, {
24143  test: kindTest(OpKind.StyleProp)
24144}, {
24145  test: kindTest(OpKind.ClassProp)
24146}];
24147/**
24148 * The set of all op kinds we handle in the reordering phase.
24149 */
24150const handledOpKinds = new Set([OpKind.Listener, OpKind.TwoWayListener, OpKind.StyleMap, OpKind.ClassMap, OpKind.StyleProp, OpKind.ClassProp, OpKind.Property, OpKind.TwoWayProperty, OpKind.HostProperty, OpKind.Attribute]);
24151/**
24152 * Many type of operations have ordering constraints that must be respected. For example, a
24153 * `ClassMap` instruction must be ordered after a `StyleMap` instruction, in order to have
24154 * predictable semantics that match TemplateDefinitionBuilder and don't break applications.
24155 */
24156function orderOps(job) {
24157  for (const unit of job.units) {
24158    // First, we pull out ops that need to be ordered. Then, when we encounter an op that shouldn't
24159    // be reordered, put the ones we've pulled so far back in the correct order. Finally, if we
24160    // still have ops pulled at the end, put them back in the correct order.
24161    // Create mode:
24162    orderWithin(unit.create, CREATE_ORDERING);
24163    // Update mode:
24164    const ordering = unit.job.kind === CompilationJobKind.Host ? UPDATE_HOST_ORDERING : UPDATE_ORDERING;
24165    orderWithin(unit.update, ordering);
24166  }
24167}
24168/**
24169 * Order all the ops within the specified group.
24170 */
24171function orderWithin(opList, ordering) {
24172  let opsToOrder = [];
24173  // Only reorder ops that target the same xref; do not mix ops that target different xrefs.
24174  let firstTargetInGroup = null;
24175  for (const op of opList) {
24176    const currentTarget = hasDependsOnSlotContextTrait(op) ? op.target : null;
24177    if (!handledOpKinds.has(op.kind) || currentTarget !== firstTargetInGroup && firstTargetInGroup !== null && currentTarget !== null) {
24178      OpList.insertBefore(reorder(opsToOrder, ordering), op);
24179      opsToOrder = [];
24180      firstTargetInGroup = null;
24181    }
24182    if (handledOpKinds.has(op.kind)) {
24183      opsToOrder.push(op);
24184      OpList.remove(op);
24185      firstTargetInGroup = currentTarget ?? firstTargetInGroup;
24186    }
24187  }
24188  opList.push(reorder(opsToOrder, ordering));
24189}
24190/**
24191 * Reorders the given list of ops according to the ordering defined by `ORDERING`.
24192 */
24193function reorder(ops, ordering) {
24194  // Break the ops list into groups based on OpKind.
24195  const groups = Array.from(ordering, () => new Array());
24196  for (const op of ops) {
24197    const groupIndex = ordering.findIndex(o => o.test(op));
24198    groups[groupIndex].push(op);
24199  }
24200  // Reassemble the groups into a single list, in the correct order.
24201  return groups.flatMap((group, i) => {
24202    const transform = ordering[i].transform;
24203    return transform ? transform(group) : group;
24204  });
24205}
24206/**
24207 * Keeps only the last op in a list of ops.
24208 */
24209function keepLast(ops) {
24210  return ops.slice(ops.length - 1);
24211}
24212
24213/**
24214 * Parses extracted style and class attributes into separate ExtractedAttributeOps per style or
24215 * class property.
24216 */
24217function parseExtractedStyles(job) {
24218  const elements = new Map();
24219  for (const unit of job.units) {
24220    for (const op of unit.create) {
24221      if (isElementOrContainerOp(op)) {
24222        elements.set(op.xref, op);
24223      }
24224    }
24225  }
24226  for (const unit of job.units) {
24227    for (const op of unit.create) {
24228      if (op.kind === OpKind.ExtractedAttribute && op.bindingKind === BindingKind.Attribute && isStringLiteral(op.expression)) {
24229        const target = elements.get(op.target);
24230        if (target !== undefined && target.kind === OpKind.Template && target.templateKind === TemplateKind.Structural) {
24231          // TemplateDefinitionBuilder will not apply class and style bindings to structural
24232          // directives; instead, it will leave them as attributes.
24233          // (It's not clear what that would mean, anyway -- classes and styles on a structural
24234          // element should probably be a parse error.)
24235          // TODO: We may be able to remove this once Template Pipeline is the default.
24236          continue;
24237        }
24238        if (op.name === 'style') {
24239          const parsedStyles = parse(op.expression.value);
24240          for (let i = 0; i < parsedStyles.length - 1; i += 2) {
24241            OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.StyleProperty, null, parsedStyles[i], literal(parsedStyles[i + 1]), null, null, SecurityContext.STYLE), op);
24242          }
24243          OpList.remove(op);
24244        } else if (op.name === 'class') {
24245          const parsedClasses = op.expression.value.trim().split(/\s+/g);
24246          for (const parsedClass of parsedClasses) {
24247            OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.ClassName, null, parsedClass, null, null, null, SecurityContext.NONE), op);
24248          }
24249          OpList.remove(op);
24250        }
24251      }
24252    }
24253  }
24254}
24255
24256/**
24257 * Attributes of `ng-content` named 'select' are specifically removed, because they control which
24258 * content matches as a property of the `projection`, and are not a plain attribute.
24259 */
24260function removeContentSelectors(job) {
24261  for (const unit of job.units) {
24262    const elements = createOpXrefMap(unit);
24263    for (const op of unit.ops()) {
24264      switch (op.kind) {
24265        case OpKind.Binding:
24266          const target = lookupInXrefMap(elements, op.target);
24267          if (isSelectAttribute(op.name) && target.kind === OpKind.Projection) {
24268            OpList.remove(op);
24269          }
24270          break;
24271      }
24272    }
24273  }
24274}
24275function isSelectAttribute(name) {
24276  return name.toLowerCase() === 'select';
24277}
24278/**
24279 * Looks up an element in the given map by xref ID.
24280 */
24281function lookupInXrefMap(map, xref) {
24282  const el = map.get(xref);
24283  if (el === undefined) {
24284    throw new Error('All attributes should have an slottable target.');
24285  }
24286  return el;
24287}
24288
24289/**
24290 * This phase generates pipe creation instructions. We do this based on the pipe bindings found in
24291 * the update block, in the order we see them.
24292 *
24293 * When not in compatibility mode, we can simply group all these creation instructions together, to
24294 * maximize chaining opportunities.
24295 */
24296function createPipes(job) {
24297  for (const unit of job.units) {
24298    processPipeBindingsInView(unit);
24299  }
24300}
24301function processPipeBindingsInView(unit) {
24302  for (const updateOp of unit.update) {
24303    visitExpressionsInOp(updateOp, (expr, flags) => {
24304      if (!isIrExpression(expr)) {
24305        return;
24306      }
24307      if (expr.kind !== ExpressionKind.PipeBinding) {
24308        return;
24309      }
24310      if (flags & VisitorContextFlag.InChildOperation) {
24311        throw new Error(`AssertionError: pipe bindings should not appear in child expressions`);
24312      }
24313      if (unit.job.compatibility) {
24314        // TODO: We can delete this cast and check once compatibility mode is removed.
24315        const slotHandle = updateOp.target;
24316        if (slotHandle == undefined) {
24317          throw new Error(`AssertionError: expected slot handle to be assigned for pipe creation`);
24318        }
24319        addPipeToCreationBlock(unit, updateOp.target, expr);
24320      } else {
24321        // When not in compatibility mode, we just add the pipe to the end of the create block. This
24322        // is not only simpler and faster, but allows more chaining opportunities for other
24323        // instructions.
24324        unit.create.push(createPipeOp(expr.target, expr.targetSlot, expr.name));
24325      }
24326    });
24327  }
24328}
24329function addPipeToCreationBlock(unit, afterTargetXref, binding) {
24330  // Find the appropriate point to insert the Pipe creation operation.
24331  // We're looking for `afterTargetXref` (and also want to insert after any other pipe operations
24332  // which might be beyond it).
24333  for (let op = unit.create.head.next; op.kind !== OpKind.ListEnd; op = op.next) {
24334    if (!hasConsumesSlotTrait(op)) {
24335      continue;
24336    }
24337    if (op.xref !== afterTargetXref) {
24338      continue;
24339    }
24340    // We've found a tentative insertion point; however, we also want to skip past any _other_ pipe
24341    // operations present.
24342    while (op.next.kind === OpKind.Pipe) {
24343      op = op.next;
24344    }
24345    const pipe = createPipeOp(binding.target, binding.targetSlot, binding.name);
24346    OpList.insertBefore(pipe, op.next);
24347    // This completes adding the pipe to the creation block.
24348    return;
24349  }
24350  // At this point, we've failed to add the pipe to the creation block.
24351  throw new Error(`AssertionError: unable to find insertion point for pipe ${binding.name}`);
24352}
24353
24354/**
24355 * Pipes that accept more than 4 arguments are variadic, and are handled with a different runtime
24356 * instruction.
24357 */
24358function createVariadicPipes(job) {
24359  for (const unit of job.units) {
24360    for (const op of unit.update) {
24361      transformExpressionsInOp(op, expr => {
24362        if (!(expr instanceof PipeBindingExpr)) {
24363          return expr;
24364        }
24365        // Pipes are variadic if they have more than 4 arguments.
24366        if (expr.args.length <= 4) {
24367          return expr;
24368        }
24369        return new PipeBindingVariadicExpr(expr.target, expr.targetSlot, expr.name, literalArr(expr.args), expr.args.length);
24370      }, VisitorContextFlag.None);
24371    }
24372  }
24373}
24374
24375/**
24376 * Propagate i18n blocks down through child templates that act as placeholders in the root i18n
24377 * message. Specifically, perform an in-order traversal of all the views, and add i18nStart/i18nEnd
24378 * op pairs into descending views. Also, assign an increasing sub-template index to each
24379 * descending view.
24380 */
24381function propagateI18nBlocks(job) {
24382  propagateI18nBlocksToTemplates(job.root, 0);
24383}
24384/**
24385 * Propagates i18n ops in the given view through to any child views recursively.
24386 */
24387function propagateI18nBlocksToTemplates(unit, subTemplateIndex) {
24388  let i18nBlock = null;
24389  for (const op of unit.create) {
24390    switch (op.kind) {
24391      case OpKind.I18nStart:
24392        op.subTemplateIndex = subTemplateIndex === 0 ? null : subTemplateIndex;
24393        i18nBlock = op;
24394        break;
24395      case OpKind.I18nEnd:
24396        // When we exit a root-level i18n block, reset the sub-template index counter.
24397        if (i18nBlock.subTemplateIndex === null) {
24398          subTemplateIndex = 0;
24399        }
24400        i18nBlock = null;
24401        break;
24402      case OpKind.Template:
24403        subTemplateIndex = propagateI18nBlocksForView(unit.job.views.get(op.xref), i18nBlock, op.i18nPlaceholder, subTemplateIndex);
24404        break;
24405      case OpKind.RepeaterCreate:
24406        // Propagate i18n blocks to the @for template.
24407        const forView = unit.job.views.get(op.xref);
24408        subTemplateIndex = propagateI18nBlocksForView(forView, i18nBlock, op.i18nPlaceholder, subTemplateIndex);
24409        // Then if there's an @empty template, propagate the i18n blocks for it as well.
24410        if (op.emptyView !== null) {
24411          subTemplateIndex = propagateI18nBlocksForView(unit.job.views.get(op.emptyView), i18nBlock, op.emptyI18nPlaceholder, subTemplateIndex);
24412        }
24413        break;
24414    }
24415  }
24416  return subTemplateIndex;
24417}
24418/**
24419 * Propagate i18n blocks for a view.
24420 */
24421function propagateI18nBlocksForView(view, i18nBlock, i18nPlaceholder, subTemplateIndex) {
24422  // We found an <ng-template> inside an i18n block; increment the sub-template counter and
24423  // wrap the template's view in a child i18n block.
24424  if (i18nPlaceholder !== undefined) {
24425    if (i18nBlock === null) {
24426      throw Error('Expected template with i18n placeholder to be in an i18n block.');
24427    }
24428    subTemplateIndex++;
24429    wrapTemplateWithI18n(view, i18nBlock);
24430  }
24431  // Continue traversing inside the template's view.
24432  return propagateI18nBlocksToTemplates(view, subTemplateIndex);
24433}
24434/**
24435 * Wraps a template view with i18n start and end ops.
24436 */
24437function wrapTemplateWithI18n(unit, parentI18n) {
24438  // Only add i18n ops if they have not already been propagated to this template.
24439  if (unit.create.head.next?.kind !== OpKind.I18nStart) {
24440    const id = unit.job.allocateXrefId();
24441    OpList.insertAfter(
24442    // Nested ng-template i18n start/end ops should not recieve source spans.
24443    createI18nStartOp(id, parentI18n.message, parentI18n.root, null), unit.create.head);
24444    OpList.insertBefore(createI18nEndOp(id, null), unit.create.tail);
24445  }
24446}
24447function extractPureFunctions(job) {
24448  for (const view of job.units) {
24449    for (const op of view.ops()) {
24450      visitExpressionsInOp(op, expr => {
24451        if (!(expr instanceof PureFunctionExpr) || expr.body === null) {
24452          return;
24453        }
24454        const constantDef = new PureFunctionConstant(expr.args.length);
24455        expr.fn = job.pool.getSharedConstant(constantDef, expr.body);
24456        expr.body = null;
24457      });
24458    }
24459  }
24460}
24461class PureFunctionConstant extends GenericKeyFn {
24462  constructor(numArgs) {
24463    super();
24464    this.numArgs = numArgs;
24465  }
24466  keyOf(expr) {
24467    if (expr instanceof PureFunctionParameterExpr) {
24468      return `param(${expr.index})`;
24469    } else {
24470      return super.keyOf(expr);
24471    }
24472  }
24473  // TODO: Use the new pool method `getSharedFunctionReference`
24474  toSharedConstantDeclaration(declName, keyExpr) {
24475    const fnParams = [];
24476    for (let idx = 0; idx < this.numArgs; idx++) {
24477      fnParams.push(new FnParam('a' + idx));
24478    }
24479    // We will never visit `ir.PureFunctionParameterExpr`s that don't belong to us, because this
24480    // transform runs inside another visitor which will visit nested pure functions before this one.
24481    const returnExpr = transformExpressionsInExpression(keyExpr, expr => {
24482      if (!(expr instanceof PureFunctionParameterExpr)) {
24483        return expr;
24484      }
24485      return variable('a' + expr.index);
24486    }, VisitorContextFlag.None);
24487    return new DeclareVarStmt(declName, new ArrowFunctionExpr(fnParams, returnExpr), undefined, StmtModifier.Final);
24488  }
24489}
24490function generatePureLiteralStructures(job) {
24491  for (const unit of job.units) {
24492    for (const op of unit.update) {
24493      transformExpressionsInOp(op, (expr, flags) => {
24494        if (flags & VisitorContextFlag.InChildOperation) {
24495          return expr;
24496        }
24497        if (expr instanceof LiteralArrayExpr) {
24498          return transformLiteralArray(expr);
24499        } else if (expr instanceof LiteralMapExpr) {
24500          return transformLiteralMap(expr);
24501        }
24502        return expr;
24503      }, VisitorContextFlag.None);
24504    }
24505  }
24506}
24507function transformLiteralArray(expr) {
24508  const derivedEntries = [];
24509  const nonConstantArgs = [];
24510  for (const entry of expr.entries) {
24511    if (entry.isConstant()) {
24512      derivedEntries.push(entry);
24513    } else {
24514      const idx = nonConstantArgs.length;
24515      nonConstantArgs.push(entry);
24516      derivedEntries.push(new PureFunctionParameterExpr(idx));
24517    }
24518  }
24519  return new PureFunctionExpr(literalArr(derivedEntries), nonConstantArgs);
24520}
24521function transformLiteralMap(expr) {
24522  let derivedEntries = [];
24523  const nonConstantArgs = [];
24524  for (const entry of expr.entries) {
24525    if (entry.value.isConstant()) {
24526      derivedEntries.push(entry);
24527    } else {
24528      const idx = nonConstantArgs.length;
24529      nonConstantArgs.push(entry.value);
24530      derivedEntries.push(new LiteralMapEntry(entry.key, new PureFunctionParameterExpr(idx), entry.quoted));
24531    }
24532  }
24533  return new PureFunctionExpr(literalMap(derivedEntries), nonConstantArgs);
24534}
24535
24536// This file contains helpers for generating calls to Ivy instructions. In particular, each
24537// instruction type is represented as a function, which may select a specific instruction variant
24538// depending on the exact arguments.
24539function element(slot, tag, constIndex, localRefIndex, sourceSpan) {
24540  return elementOrContainerBase(Identifiers.element, slot, tag, constIndex, localRefIndex, sourceSpan);
24541}
24542function elementStart(slot, tag, constIndex, localRefIndex, sourceSpan) {
24543  return elementOrContainerBase(Identifiers.elementStart, slot, tag, constIndex, localRefIndex, sourceSpan);
24544}
24545function elementOrContainerBase(instruction, slot, tag, constIndex, localRefIndex, sourceSpan) {
24546  const args = [literal(slot)];
24547  if (tag !== null) {
24548    args.push(literal(tag));
24549  }
24550  if (localRefIndex !== null) {
24551    args.push(literal(constIndex),
24552    // might be null, but that's okay.
24553    literal(localRefIndex));
24554  } else if (constIndex !== null) {
24555    args.push(literal(constIndex));
24556  }
24557  return call(instruction, args, sourceSpan);
24558}
24559function elementEnd(sourceSpan) {
24560  return call(Identifiers.elementEnd, [], sourceSpan);
24561}
24562function elementContainerStart(slot, constIndex, localRefIndex, sourceSpan) {
24563  return elementOrContainerBase(Identifiers.elementContainerStart, slot, /* tag */null, constIndex, localRefIndex, sourceSpan);
24564}
24565function elementContainer(slot, constIndex, localRefIndex, sourceSpan) {
24566  return elementOrContainerBase(Identifiers.elementContainer, slot, /* tag */null, constIndex, localRefIndex, sourceSpan);
24567}
24568function elementContainerEnd() {
24569  return call(Identifiers.elementContainerEnd, [], null);
24570}
24571function template(slot, templateFnRef, decls, vars, tag, constIndex, localRefs, sourceSpan) {
24572  const args = [literal(slot), templateFnRef, literal(decls), literal(vars), literal(tag), literal(constIndex)];
24573  if (localRefs !== null) {
24574    args.push(literal(localRefs));
24575    args.push(importExpr(Identifiers.templateRefExtractor));
24576  }
24577  while (args[args.length - 1].isEquivalent(NULL_EXPR)) {
24578    args.pop();
24579  }
24580  return call(Identifiers.templateCreate, args, sourceSpan);
24581}
24582function disableBindings() {
24583  return call(Identifiers.disableBindings, [], null);
24584}
24585function enableBindings() {
24586  return call(Identifiers.enableBindings, [], null);
24587}
24588function listener(name, handlerFn, eventTargetResolver, syntheticHost, sourceSpan) {
24589  const args = [literal(name), handlerFn];
24590  if (eventTargetResolver !== null) {
24591    args.push(literal(false)); // `useCapture` flag, defaults to `false`
24592    args.push(importExpr(eventTargetResolver));
24593  }
24594  return call(syntheticHost ? Identifiers.syntheticHostListener : Identifiers.listener, args, sourceSpan);
24595}
24596function twoWayBindingSet(target, value) {
24597  return importExpr(Identifiers.twoWayBindingSet).callFn([target, value]);
24598}
24599function twoWayListener(name, handlerFn, sourceSpan) {
24600  return call(Identifiers.twoWayListener, [literal(name), handlerFn], sourceSpan);
24601}
24602function pipe(slot, name) {
24603  return call(Identifiers.pipe, [literal(slot), literal(name)], null);
24604}
24605function namespaceHTML() {
24606  return call(Identifiers.namespaceHTML, [], null);
24607}
24608function namespaceSVG() {
24609  return call(Identifiers.namespaceSVG, [], null);
24610}
24611function namespaceMath() {
24612  return call(Identifiers.namespaceMathML, [], null);
24613}
24614function advance(delta, sourceSpan) {
24615  return call(Identifiers.advance, delta > 1 ? [literal(delta)] : [], sourceSpan);
24616}
24617function reference(slot) {
24618  return importExpr(Identifiers.reference).callFn([literal(slot)]);
24619}
24620function nextContext(steps) {
24621  return importExpr(Identifiers.nextContext).callFn(steps === 1 ? [] : [literal(steps)]);
24622}
24623function getCurrentView() {
24624  return importExpr(Identifiers.getCurrentView).callFn([]);
24625}
24626function restoreView(savedView) {
24627  return importExpr(Identifiers.restoreView).callFn([savedView]);
24628}
24629function resetView(returnValue) {
24630  return importExpr(Identifiers.resetView).callFn([returnValue]);
24631}
24632function text(slot, initialValue, sourceSpan) {
24633  const args = [literal(slot, null)];
24634  if (initialValue !== '') {
24635    args.push(literal(initialValue));
24636  }
24637  return call(Identifiers.text, args, sourceSpan);
24638}
24639function defer(selfSlot, primarySlot, dependencyResolverFn, loadingSlot, placeholderSlot, errorSlot, loadingConfig, placeholderConfig, enableTimerScheduling, sourceSpan) {
24640  const args = [literal(selfSlot), literal(primarySlot), dependencyResolverFn ?? literal(null), literal(loadingSlot), literal(placeholderSlot), literal(errorSlot), loadingConfig ?? literal(null), placeholderConfig ?? literal(null), enableTimerScheduling ? importExpr(Identifiers.deferEnableTimerScheduling) : literal(null)];
24641  let expr;
24642  while ((expr = args[args.length - 1]) !== null && expr instanceof LiteralExpr && expr.value === null) {
24643    args.pop();
24644  }
24645  return call(Identifiers.defer, args, sourceSpan);
24646}
24647const deferTriggerToR3TriggerInstructionsMap = new Map([[DeferTriggerKind.Idle, [Identifiers.deferOnIdle, Identifiers.deferPrefetchOnIdle]], [DeferTriggerKind.Immediate, [Identifiers.deferOnImmediate, Identifiers.deferPrefetchOnImmediate]], [DeferTriggerKind.Timer, [Identifiers.deferOnTimer, Identifiers.deferPrefetchOnTimer]], [DeferTriggerKind.Hover, [Identifiers.deferOnHover, Identifiers.deferPrefetchOnHover]], [DeferTriggerKind.Interaction, [Identifiers.deferOnInteraction, Identifiers.deferPrefetchOnInteraction]], [DeferTriggerKind.Viewport, [Identifiers.deferOnViewport, Identifiers.deferPrefetchOnViewport]]]);
24648function deferOn(trigger, args, prefetch, sourceSpan) {
24649  const instructions = deferTriggerToR3TriggerInstructionsMap.get(trigger);
24650  if (instructions === undefined) {
24651    throw new Error(`Unable to determine instruction for trigger ${trigger}`);
24652  }
24653  const instructionToCall = prefetch ? instructions[1] : instructions[0];
24654  return call(instructionToCall, args.map(a => literal(a)), sourceSpan);
24655}
24656function projectionDef(def) {
24657  return call(Identifiers.projectionDef, def ? [def] : [], null);
24658}
24659function projection(slot, projectionSlotIndex, attributes, sourceSpan) {
24660  const args = [literal(slot)];
24661  if (projectionSlotIndex !== 0 || attributes !== null) {
24662    args.push(literal(projectionSlotIndex));
24663    if (attributes !== null) {
24664      args.push(attributes);
24665    }
24666  }
24667  return call(Identifiers.projection, args, sourceSpan);
24668}
24669function i18nStart(slot, constIndex, subTemplateIndex, sourceSpan) {
24670  const args = [literal(slot), literal(constIndex)];
24671  if (subTemplateIndex !== null) {
24672    args.push(literal(subTemplateIndex));
24673  }
24674  return call(Identifiers.i18nStart, args, sourceSpan);
24675}
24676function repeaterCreate(slot, viewFnName, decls, vars, tag, constIndex, trackByFn, trackByUsesComponentInstance, emptyViewFnName, emptyDecls, emptyVars, emptyTag, emptyConstIndex, sourceSpan) {
24677  const args = [literal(slot), variable(viewFnName), literal(decls), literal(vars), literal(tag), literal(constIndex), trackByFn];
24678  if (trackByUsesComponentInstance || emptyViewFnName !== null) {
24679    args.push(literal(trackByUsesComponentInstance));
24680    if (emptyViewFnName !== null) {
24681      args.push(variable(emptyViewFnName), literal(emptyDecls), literal(emptyVars));
24682      if (emptyTag !== null || emptyConstIndex !== null) {
24683        args.push(literal(emptyTag));
24684      }
24685      if (emptyConstIndex !== null) {
24686        args.push(literal(emptyConstIndex));
24687      }
24688    }
24689  }
24690  return call(Identifiers.repeaterCreate, args, sourceSpan);
24691}
24692function repeater(collection, sourceSpan) {
24693  return call(Identifiers.repeater, [collection], sourceSpan);
24694}
24695function deferWhen(prefetch, expr, sourceSpan) {
24696  return call(prefetch ? Identifiers.deferPrefetchWhen : Identifiers.deferWhen, [expr], sourceSpan);
24697}
24698function i18n(slot, constIndex, subTemplateIndex, sourceSpan) {
24699  const args = [literal(slot), literal(constIndex)];
24700  if (subTemplateIndex) {
24701    args.push(literal(subTemplateIndex));
24702  }
24703  return call(Identifiers.i18n, args, sourceSpan);
24704}
24705function i18nEnd(endSourceSpan) {
24706  return call(Identifiers.i18nEnd, [], endSourceSpan);
24707}
24708function i18nAttributes(slot, i18nAttributesConfig) {
24709  const args = [literal(slot), literal(i18nAttributesConfig)];
24710  return call(Identifiers.i18nAttributes, args, null);
24711}
24712function property(name, expression, sanitizer, sourceSpan) {
24713  const args = [literal(name), expression];
24714  if (sanitizer !== null) {
24715    args.push(sanitizer);
24716  }
24717  return call(Identifiers.property, args, sourceSpan);
24718}
24719function twoWayProperty(name, expression, sanitizer, sourceSpan) {
24720  const args = [literal(name), expression];
24721  if (sanitizer !== null) {
24722    args.push(sanitizer);
24723  }
24724  return call(Identifiers.twoWayProperty, args, sourceSpan);
24725}
24726function attribute(name, expression, sanitizer, namespace) {
24727  const args = [literal(name), expression];
24728  if (sanitizer !== null || namespace !== null) {
24729    args.push(sanitizer ?? literal(null));
24730  }
24731  if (namespace !== null) {
24732    args.push(literal(namespace));
24733  }
24734  return call(Identifiers.attribute, args, null);
24735}
24736function styleProp(name, expression, unit, sourceSpan) {
24737  const args = [literal(name), expression];
24738  if (unit !== null) {
24739    args.push(literal(unit));
24740  }
24741  return call(Identifiers.styleProp, args, sourceSpan);
24742}
24743function classProp(name, expression, sourceSpan) {
24744  return call(Identifiers.classProp, [literal(name), expression], sourceSpan);
24745}
24746function styleMap(expression, sourceSpan) {
24747  return call(Identifiers.styleMap, [expression], sourceSpan);
24748}
24749function classMap(expression, sourceSpan) {
24750  return call(Identifiers.classMap, [expression], sourceSpan);
24751}
24752const PIPE_BINDINGS = [Identifiers.pipeBind1, Identifiers.pipeBind2, Identifiers.pipeBind3, Identifiers.pipeBind4];
24753function pipeBind(slot, varOffset, args) {
24754  if (args.length < 1 || args.length > PIPE_BINDINGS.length) {
24755    throw new Error(`pipeBind() argument count out of bounds`);
24756  }
24757  const instruction = PIPE_BINDINGS[args.length - 1];
24758  return importExpr(instruction).callFn([literal(slot), literal(varOffset), ...args]);
24759}
24760function pipeBindV(slot, varOffset, args) {
24761  return importExpr(Identifiers.pipeBindV).callFn([literal(slot), literal(varOffset), args]);
24762}
24763function textInterpolate(strings, expressions, sourceSpan) {
24764  if (strings.length < 1 || expressions.length !== strings.length - 1) {
24765    throw new Error(`AssertionError: expected specific shape of args for strings/expressions in interpolation`);
24766  }
24767  const interpolationArgs = [];
24768  if (expressions.length === 1 && strings[0] === '' && strings[1] === '') {
24769    interpolationArgs.push(expressions[0]);
24770  } else {
24771    let idx;
24772    for (idx = 0; idx < expressions.length; idx++) {
24773      interpolationArgs.push(literal(strings[idx]), expressions[idx]);
24774    }
24775    // idx points at the last string.
24776    interpolationArgs.push(literal(strings[idx]));
24777  }
24778  return callVariadicInstruction(TEXT_INTERPOLATE_CONFIG, [], interpolationArgs, [], sourceSpan);
24779}
24780function i18nExp(expr, sourceSpan) {
24781  return call(Identifiers.i18nExp, [expr], sourceSpan);
24782}
24783function i18nApply(slot, sourceSpan) {
24784  return call(Identifiers.i18nApply, [literal(slot)], sourceSpan);
24785}
24786function propertyInterpolate(name, strings, expressions, sanitizer, sourceSpan) {
24787  const interpolationArgs = collateInterpolationArgs(strings, expressions);
24788  const extraArgs = [];
24789  if (sanitizer !== null) {
24790    extraArgs.push(sanitizer);
24791  }
24792  return callVariadicInstruction(PROPERTY_INTERPOLATE_CONFIG, [literal(name)], interpolationArgs, extraArgs, sourceSpan);
24793}
24794function attributeInterpolate(name, strings, expressions, sanitizer, sourceSpan) {
24795  const interpolationArgs = collateInterpolationArgs(strings, expressions);
24796  const extraArgs = [];
24797  if (sanitizer !== null) {
24798    extraArgs.push(sanitizer);
24799  }
24800  return callVariadicInstruction(ATTRIBUTE_INTERPOLATE_CONFIG, [literal(name)], interpolationArgs, extraArgs, sourceSpan);
24801}
24802function stylePropInterpolate(name, strings, expressions, unit, sourceSpan) {
24803  const interpolationArgs = collateInterpolationArgs(strings, expressions);
24804  const extraArgs = [];
24805  if (unit !== null) {
24806    extraArgs.push(literal(unit));
24807  }
24808  return callVariadicInstruction(STYLE_PROP_INTERPOLATE_CONFIG, [literal(name)], interpolationArgs, extraArgs, sourceSpan);
24809}
24810function styleMapInterpolate(strings, expressions, sourceSpan) {
24811  const interpolationArgs = collateInterpolationArgs(strings, expressions);
24812  return callVariadicInstruction(STYLE_MAP_INTERPOLATE_CONFIG, [], interpolationArgs, [], sourceSpan);
24813}
24814function classMapInterpolate(strings, expressions, sourceSpan) {
24815  const interpolationArgs = collateInterpolationArgs(strings, expressions);
24816  return callVariadicInstruction(CLASS_MAP_INTERPOLATE_CONFIG, [], interpolationArgs, [], sourceSpan);
24817}
24818function hostProperty(name, expression, sanitizer, sourceSpan) {
24819  const args = [literal(name), expression];
24820  if (sanitizer !== null) {
24821    args.push(sanitizer);
24822  }
24823  return call(Identifiers.hostProperty, args, sourceSpan);
24824}
24825function syntheticHostProperty(name, expression, sourceSpan) {
24826  return call(Identifiers.syntheticHostProperty, [literal(name), expression], sourceSpan);
24827}
24828function pureFunction(varOffset, fn, args) {
24829  return callVariadicInstructionExpr(PURE_FUNCTION_CONFIG, [literal(varOffset), fn], args, [], null);
24830}
24831/**
24832 * Collates the string an expression arguments for an interpolation instruction.
24833 */
24834function collateInterpolationArgs(strings, expressions) {
24835  if (strings.length < 1 || expressions.length !== strings.length - 1) {
24836    throw new Error(`AssertionError: expected specific shape of args for strings/expressions in interpolation`);
24837  }
24838  const interpolationArgs = [];
24839  if (expressions.length === 1 && strings[0] === '' && strings[1] === '') {
24840    interpolationArgs.push(expressions[0]);
24841  } else {
24842    let idx;
24843    for (idx = 0; idx < expressions.length; idx++) {
24844      interpolationArgs.push(literal(strings[idx]), expressions[idx]);
24845    }
24846    // idx points at the last string.
24847    interpolationArgs.push(literal(strings[idx]));
24848  }
24849  return interpolationArgs;
24850}
24851function call(instruction, args, sourceSpan) {
24852  const expr = importExpr(instruction).callFn(args, sourceSpan);
24853  return createStatementOp(new ExpressionStatement(expr, sourceSpan));
24854}
24855function conditional(slot, condition, contextValue, sourceSpan) {
24856  const args = [literal(slot), condition];
24857  if (contextValue !== null) {
24858    args.push(contextValue);
24859  }
24860  return call(Identifiers.conditional, args, sourceSpan);
24861}
24862/**
24863 * `InterpolationConfig` for the `textInterpolate` instruction.
24864 */
24865const TEXT_INTERPOLATE_CONFIG = {
24866  constant: [Identifiers.textInterpolate, Identifiers.textInterpolate1, Identifiers.textInterpolate2, Identifiers.textInterpolate3, Identifiers.textInterpolate4, Identifiers.textInterpolate5, Identifiers.textInterpolate6, Identifiers.textInterpolate7, Identifiers.textInterpolate8],
24867  variable: Identifiers.textInterpolateV,
24868  mapping: n => {
24869    if (n % 2 === 0) {
24870      throw new Error(`Expected odd number of arguments`);
24871    }
24872    return (n - 1) / 2;
24873  }
24874};
24875/**
24876 * `InterpolationConfig` for the `propertyInterpolate` instruction.
24877 */
24878const PROPERTY_INTERPOLATE_CONFIG = {
24879  constant: [Identifiers.propertyInterpolate, Identifiers.propertyInterpolate1, Identifiers.propertyInterpolate2, Identifiers.propertyInterpolate3, Identifiers.propertyInterpolate4, Identifiers.propertyInterpolate5, Identifiers.propertyInterpolate6, Identifiers.propertyInterpolate7, Identifiers.propertyInterpolate8],
24880  variable: Identifiers.propertyInterpolateV,
24881  mapping: n => {
24882    if (n % 2 === 0) {
24883      throw new Error(`Expected odd number of arguments`);
24884    }
24885    return (n - 1) / 2;
24886  }
24887};
24888/**
24889 * `InterpolationConfig` for the `stylePropInterpolate` instruction.
24890 */
24891const STYLE_PROP_INTERPOLATE_CONFIG = {
24892  constant: [Identifiers.styleProp, Identifiers.stylePropInterpolate1, Identifiers.stylePropInterpolate2, Identifiers.stylePropInterpolate3, Identifiers.stylePropInterpolate4, Identifiers.stylePropInterpolate5, Identifiers.stylePropInterpolate6, Identifiers.stylePropInterpolate7, Identifiers.stylePropInterpolate8],
24893  variable: Identifiers.stylePropInterpolateV,
24894  mapping: n => {
24895    if (n % 2 === 0) {
24896      throw new Error(`Expected odd number of arguments`);
24897    }
24898    return (n - 1) / 2;
24899  }
24900};
24901/**
24902 * `InterpolationConfig` for the `attributeInterpolate` instruction.
24903 */
24904const ATTRIBUTE_INTERPOLATE_CONFIG = {
24905  constant: [Identifiers.attribute, Identifiers.attributeInterpolate1, Identifiers.attributeInterpolate2, Identifiers.attributeInterpolate3, Identifiers.attributeInterpolate4, Identifiers.attributeInterpolate5, Identifiers.attributeInterpolate6, Identifiers.attributeInterpolate7, Identifiers.attributeInterpolate8],
24906  variable: Identifiers.attributeInterpolateV,
24907  mapping: n => {
24908    if (n % 2 === 0) {
24909      throw new Error(`Expected odd number of arguments`);
24910    }
24911    return (n - 1) / 2;
24912  }
24913};
24914/**
24915 * `InterpolationConfig` for the `styleMapInterpolate` instruction.
24916 */
24917const STYLE_MAP_INTERPOLATE_CONFIG = {
24918  constant: [Identifiers.styleMap, Identifiers.styleMapInterpolate1, Identifiers.styleMapInterpolate2, Identifiers.styleMapInterpolate3, Identifiers.styleMapInterpolate4, Identifiers.styleMapInterpolate5, Identifiers.styleMapInterpolate6, Identifiers.styleMapInterpolate7, Identifiers.styleMapInterpolate8],
24919  variable: Identifiers.styleMapInterpolateV,
24920  mapping: n => {
24921    if (n % 2 === 0) {
24922      throw new Error(`Expected odd number of arguments`);
24923    }
24924    return (n - 1) / 2;
24925  }
24926};
24927/**
24928 * `InterpolationConfig` for the `classMapInterpolate` instruction.
24929 */
24930const CLASS_MAP_INTERPOLATE_CONFIG = {
24931  constant: [Identifiers.classMap, Identifiers.classMapInterpolate1, Identifiers.classMapInterpolate2, Identifiers.classMapInterpolate3, Identifiers.classMapInterpolate4, Identifiers.classMapInterpolate5, Identifiers.classMapInterpolate6, Identifiers.classMapInterpolate7, Identifiers.classMapInterpolate8],
24932  variable: Identifiers.classMapInterpolateV,
24933  mapping: n => {
24934    if (n % 2 === 0) {
24935      throw new Error(`Expected odd number of arguments`);
24936    }
24937    return (n - 1) / 2;
24938  }
24939};
24940const PURE_FUNCTION_CONFIG = {
24941  constant: [Identifiers.pureFunction0, Identifiers.pureFunction1, Identifiers.pureFunction2, Identifiers.pureFunction3, Identifiers.pureFunction4, Identifiers.pureFunction5, Identifiers.pureFunction6, Identifiers.pureFunction7, Identifiers.pureFunction8],
24942  variable: Identifiers.pureFunctionV,
24943  mapping: n => n
24944};
24945function callVariadicInstructionExpr(config, baseArgs, interpolationArgs, extraArgs, sourceSpan) {
24946  const n = config.mapping(interpolationArgs.length);
24947  if (n < config.constant.length) {
24948    // Constant calling pattern.
24949    return importExpr(config.constant[n]).callFn([...baseArgs, ...interpolationArgs, ...extraArgs], sourceSpan);
24950  } else if (config.variable !== null) {
24951    // Variable calling pattern.
24952    return importExpr(config.variable).callFn([...baseArgs, literalArr(interpolationArgs), ...extraArgs], sourceSpan);
24953  } else {
24954    throw new Error(`AssertionError: unable to call variadic function`);
24955  }
24956}
24957function callVariadicInstruction(config, baseArgs, interpolationArgs, extraArgs, sourceSpan) {
24958  return createStatementOp(callVariadicInstructionExpr(config, baseArgs, interpolationArgs, extraArgs, sourceSpan).toStmt());
24959}
24960
24961/**
24962 * Map of target resolvers for event listeners.
24963 */
24964const GLOBAL_TARGET_RESOLVERS$1 = new Map([['window', Identifiers.resolveWindow], ['document', Identifiers.resolveDocument], ['body', Identifiers.resolveBody]]);
24965/**
24966 * Compiles semantic operations across all views and generates output `o.Statement`s with actual
24967 * runtime calls in their place.
24968 *
24969 * Reification replaces semantic operations with selected Ivy instructions and other generated code
24970 * structures. After reification, the create/update operation lists of all views should only contain
24971 * `ir.StatementOp`s (which wrap generated `o.Statement`s).
24972 */
24973function reify(job) {
24974  for (const unit of job.units) {
24975    reifyCreateOperations(unit, unit.create);
24976    reifyUpdateOperations(unit, unit.update);
24977  }
24978}
24979/**
24980 * This function can be used a sanity check -- it walks every expression in the const pool, and
24981 * every expression reachable from an op, and makes sure that there are no IR expressions
24982 * left. This is nice to use for debugging mysterious failures where an IR expression cannot be
24983 * output from the output AST code.
24984 */
24985function ensureNoIrForDebug(job) {
24986  for (const stmt of job.pool.statements) {
24987    transformExpressionsInStatement(stmt, expr => {
24988      if (isIrExpression(expr)) {
24989        throw new Error(`AssertionError: IR expression found during reify: ${ExpressionKind[expr.kind]}`);
24990      }
24991      return expr;
24992    }, VisitorContextFlag.None);
24993  }
24994  for (const unit of job.units) {
24995    for (const op of unit.ops()) {
24996      visitExpressionsInOp(op, expr => {
24997        if (isIrExpression(expr)) {
24998          throw new Error(`AssertionError: IR expression found during reify: ${ExpressionKind[expr.kind]}`);
24999        }
25000      });
25001    }
25002  }
25003}
25004function reifyCreateOperations(unit, ops) {
25005  for (const op of ops) {
25006    transformExpressionsInOp(op, reifyIrExpression, VisitorContextFlag.None);
25007    switch (op.kind) {
25008      case OpKind.Text:
25009        OpList.replace(op, text(op.handle.slot, op.initialValue, op.sourceSpan));
25010        break;
25011      case OpKind.ElementStart:
25012        OpList.replace(op, elementStart(op.handle.slot, op.tag, op.attributes, op.localRefs, op.startSourceSpan));
25013        break;
25014      case OpKind.Element:
25015        OpList.replace(op, element(op.handle.slot, op.tag, op.attributes, op.localRefs, op.wholeSourceSpan));
25016        break;
25017      case OpKind.ElementEnd:
25018        OpList.replace(op, elementEnd(op.sourceSpan));
25019        break;
25020      case OpKind.ContainerStart:
25021        OpList.replace(op, elementContainerStart(op.handle.slot, op.attributes, op.localRefs, op.startSourceSpan));
25022        break;
25023      case OpKind.Container:
25024        OpList.replace(op, elementContainer(op.handle.slot, op.attributes, op.localRefs, op.wholeSourceSpan));
25025        break;
25026      case OpKind.ContainerEnd:
25027        OpList.replace(op, elementContainerEnd());
25028        break;
25029      case OpKind.I18nStart:
25030        OpList.replace(op, i18nStart(op.handle.slot, op.messageIndex, op.subTemplateIndex, op.sourceSpan));
25031        break;
25032      case OpKind.I18nEnd:
25033        OpList.replace(op, i18nEnd(op.sourceSpan));
25034        break;
25035      case OpKind.I18n:
25036        OpList.replace(op, i18n(op.handle.slot, op.messageIndex, op.subTemplateIndex, op.sourceSpan));
25037        break;
25038      case OpKind.I18nAttributes:
25039        if (op.i18nAttributesConfig === null) {
25040          throw new Error(`AssertionError: i18nAttributesConfig was not set`);
25041        }
25042        OpList.replace(op, i18nAttributes(op.handle.slot, op.i18nAttributesConfig));
25043        break;
25044      case OpKind.Template:
25045        if (!(unit instanceof ViewCompilationUnit)) {
25046          throw new Error(`AssertionError: must be compiling a component`);
25047        }
25048        if (Array.isArray(op.localRefs)) {
25049          throw new Error(`AssertionError: local refs array should have been extracted into a constant`);
25050        }
25051        const childView = unit.job.views.get(op.xref);
25052        OpList.replace(op, template(op.handle.slot, variable(childView.fnName), childView.decls, childView.vars, op.tag, op.attributes, op.localRefs, op.startSourceSpan));
25053        break;
25054      case OpKind.DisableBindings:
25055        OpList.replace(op, disableBindings());
25056        break;
25057      case OpKind.EnableBindings:
25058        OpList.replace(op, enableBindings());
25059        break;
25060      case OpKind.Pipe:
25061        OpList.replace(op, pipe(op.handle.slot, op.name));
25062        break;
25063      case OpKind.Listener:
25064        const listenerFn = reifyListenerHandler(unit, op.handlerFnName, op.handlerOps, op.consumesDollarEvent);
25065        const eventTargetResolver = op.eventTarget ? GLOBAL_TARGET_RESOLVERS$1.get(op.eventTarget) : null;
25066        if (eventTargetResolver === undefined) {
25067          throw new Error(`Unexpected global target '${op.eventTarget}' defined for '${op.name}' event. Supported list of global targets: window,document,body.`);
25068        }
25069        OpList.replace(op, listener(op.name, listenerFn, eventTargetResolver, op.hostListener && op.isAnimationListener, op.sourceSpan));
25070        break;
25071      case OpKind.TwoWayListener:
25072        OpList.replace(op, twoWayListener(op.name, reifyListenerHandler(unit, op.handlerFnName, op.handlerOps, true), op.sourceSpan));
25073        break;
25074      case OpKind.Variable:
25075        if (op.variable.name === null) {
25076          throw new Error(`AssertionError: unnamed variable ${op.xref}`);
25077        }
25078        OpList.replace(op, createStatementOp(new DeclareVarStmt(op.variable.name, op.initializer, undefined, StmtModifier.Final)));
25079        break;
25080      case OpKind.Namespace:
25081        switch (op.active) {
25082          case Namespace.HTML:
25083            OpList.replace(op, namespaceHTML());
25084            break;
25085          case Namespace.SVG:
25086            OpList.replace(op, namespaceSVG());
25087            break;
25088          case Namespace.Math:
25089            OpList.replace(op, namespaceMath());
25090            break;
25091        }
25092        break;
25093      case OpKind.Defer:
25094        const timerScheduling = !!op.loadingMinimumTime || !!op.loadingAfterTime || !!op.placeholderMinimumTime;
25095        OpList.replace(op, defer(op.handle.slot, op.mainSlot.slot, op.resolverFn, op.loadingSlot?.slot ?? null, op.placeholderSlot?.slot ?? null, op.errorSlot?.slot ?? null, op.loadingConfig, op.placeholderConfig, timerScheduling, op.sourceSpan));
25096        break;
25097      case OpKind.DeferOn:
25098        let args = [];
25099        switch (op.trigger.kind) {
25100          case DeferTriggerKind.Idle:
25101          case DeferTriggerKind.Immediate:
25102            break;
25103          case DeferTriggerKind.Timer:
25104            args = [op.trigger.delay];
25105            break;
25106          case DeferTriggerKind.Interaction:
25107          case DeferTriggerKind.Hover:
25108          case DeferTriggerKind.Viewport:
25109            if (op.trigger.targetSlot?.slot == null || op.trigger.targetSlotViewSteps === null) {
25110              throw new Error(`Slot or view steps not set in trigger reification for trigger kind ${op.trigger.kind}`);
25111            }
25112            args = [op.trigger.targetSlot.slot];
25113            if (op.trigger.targetSlotViewSteps !== 0) {
25114              args.push(op.trigger.targetSlotViewSteps);
25115            }
25116            break;
25117          default:
25118            throw new Error(`AssertionError: Unsupported reification of defer trigger kind ${op.trigger.kind}`);
25119        }
25120        OpList.replace(op, deferOn(op.trigger.kind, args, op.prefetch, op.sourceSpan));
25121        break;
25122      case OpKind.ProjectionDef:
25123        OpList.replace(op, projectionDef(op.def));
25124        break;
25125      case OpKind.Projection:
25126        if (op.handle.slot === null) {
25127          throw new Error('No slot was assigned for project instruction');
25128        }
25129        OpList.replace(op, projection(op.handle.slot, op.projectionSlotIndex, op.attributes, op.sourceSpan));
25130        break;
25131      case OpKind.RepeaterCreate:
25132        if (op.handle.slot === null) {
25133          throw new Error('No slot was assigned for repeater instruction');
25134        }
25135        if (!(unit instanceof ViewCompilationUnit)) {
25136          throw new Error(`AssertionError: must be compiling a component`);
25137        }
25138        const repeaterView = unit.job.views.get(op.xref);
25139        if (repeaterView.fnName === null) {
25140          throw new Error(`AssertionError: expected repeater primary view to have been named`);
25141        }
25142        let emptyViewFnName = null;
25143        let emptyDecls = null;
25144        let emptyVars = null;
25145        if (op.emptyView !== null) {
25146          const emptyView = unit.job.views.get(op.emptyView);
25147          if (emptyView === undefined) {
25148            throw new Error('AssertionError: repeater had empty view xref, but empty view was not found');
25149          }
25150          if (emptyView.fnName === null || emptyView.decls === null || emptyView.vars === null) {
25151            throw new Error(`AssertionError: expected repeater empty view to have been named and counted`);
25152          }
25153          emptyViewFnName = emptyView.fnName;
25154          emptyDecls = emptyView.decls;
25155          emptyVars = emptyView.vars;
25156        }
25157        OpList.replace(op, repeaterCreate(op.handle.slot, repeaterView.fnName, op.decls, op.vars, op.tag, op.attributes, op.trackByFn, op.usesComponentInstance, emptyViewFnName, emptyDecls, emptyVars, op.emptyTag, op.emptyAttributes, op.wholeSourceSpan));
25158        break;
25159      case OpKind.Statement:
25160        // Pass statement operations directly through.
25161        break;
25162      default:
25163        throw new Error(`AssertionError: Unsupported reification of create op ${OpKind[op.kind]}`);
25164    }
25165  }
25166}
25167function reifyUpdateOperations(_unit, ops) {
25168  for (const op of ops) {
25169    transformExpressionsInOp(op, reifyIrExpression, VisitorContextFlag.None);
25170    switch (op.kind) {
25171      case OpKind.Advance:
25172        OpList.replace(op, advance(op.delta, op.sourceSpan));
25173        break;
25174      case OpKind.Property:
25175        if (op.expression instanceof Interpolation) {
25176          OpList.replace(op, propertyInterpolate(op.name, op.expression.strings, op.expression.expressions, op.sanitizer, op.sourceSpan));
25177        } else {
25178          OpList.replace(op, property(op.name, op.expression, op.sanitizer, op.sourceSpan));
25179        }
25180        break;
25181      case OpKind.TwoWayProperty:
25182        OpList.replace(op, twoWayProperty(op.name, op.expression, op.sanitizer, op.sourceSpan));
25183        break;
25184      case OpKind.StyleProp:
25185        if (op.expression instanceof Interpolation) {
25186          OpList.replace(op, stylePropInterpolate(op.name, op.expression.strings, op.expression.expressions, op.unit, op.sourceSpan));
25187        } else {
25188          OpList.replace(op, styleProp(op.name, op.expression, op.unit, op.sourceSpan));
25189        }
25190        break;
25191      case OpKind.ClassProp:
25192        OpList.replace(op, classProp(op.name, op.expression, op.sourceSpan));
25193        break;
25194      case OpKind.StyleMap:
25195        if (op.expression instanceof Interpolation) {
25196          OpList.replace(op, styleMapInterpolate(op.expression.strings, op.expression.expressions, op.sourceSpan));
25197        } else {
25198          OpList.replace(op, styleMap(op.expression, op.sourceSpan));
25199        }
25200        break;
25201      case OpKind.ClassMap:
25202        if (op.expression instanceof Interpolation) {
25203          OpList.replace(op, classMapInterpolate(op.expression.strings, op.expression.expressions, op.sourceSpan));
25204        } else {
25205          OpList.replace(op, classMap(op.expression, op.sourceSpan));
25206        }
25207        break;
25208      case OpKind.I18nExpression:
25209        OpList.replace(op, i18nExp(op.expression, op.sourceSpan));
25210        break;
25211      case OpKind.I18nApply:
25212        OpList.replace(op, i18nApply(op.handle.slot, op.sourceSpan));
25213        break;
25214      case OpKind.InterpolateText:
25215        OpList.replace(op, textInterpolate(op.interpolation.strings, op.interpolation.expressions, op.sourceSpan));
25216        break;
25217      case OpKind.Attribute:
25218        if (op.expression instanceof Interpolation) {
25219          OpList.replace(op, attributeInterpolate(op.name, op.expression.strings, op.expression.expressions, op.sanitizer, op.sourceSpan));
25220        } else {
25221          OpList.replace(op, attribute(op.name, op.expression, op.sanitizer, op.namespace));
25222        }
25223        break;
25224      case OpKind.HostProperty:
25225        if (op.expression instanceof Interpolation) {
25226          throw new Error('not yet handled');
25227        } else {
25228          if (op.isAnimationTrigger) {
25229            OpList.replace(op, syntheticHostProperty(op.name, op.expression, op.sourceSpan));
25230          } else {
25231            OpList.replace(op, hostProperty(op.name, op.expression, op.sanitizer, op.sourceSpan));
25232          }
25233        }
25234        break;
25235      case OpKind.Variable:
25236        if (op.variable.name === null) {
25237          throw new Error(`AssertionError: unnamed variable ${op.xref}`);
25238        }
25239        OpList.replace(op, createStatementOp(new DeclareVarStmt(op.variable.name, op.initializer, undefined, StmtModifier.Final)));
25240        break;
25241      case OpKind.Conditional:
25242        if (op.processed === null) {
25243          throw new Error(`Conditional test was not set.`);
25244        }
25245        if (op.targetSlot.slot === null) {
25246          throw new Error(`Conditional slot was not set.`);
25247        }
25248        OpList.replace(op, conditional(op.targetSlot.slot, op.processed, op.contextValue, op.sourceSpan));
25249        break;
25250      case OpKind.Repeater:
25251        OpList.replace(op, repeater(op.collection, op.sourceSpan));
25252        break;
25253      case OpKind.DeferWhen:
25254        OpList.replace(op, deferWhen(op.prefetch, op.expr, op.sourceSpan));
25255        break;
25256      case OpKind.Statement:
25257        // Pass statement operations directly through.
25258        break;
25259      default:
25260        throw new Error(`AssertionError: Unsupported reification of update op ${OpKind[op.kind]}`);
25261    }
25262  }
25263}
25264function reifyIrExpression(expr) {
25265  if (!isIrExpression(expr)) {
25266    return expr;
25267  }
25268  switch (expr.kind) {
25269    case ExpressionKind.NextContext:
25270      return nextContext(expr.steps);
25271    case ExpressionKind.Reference:
25272      return reference(expr.targetSlot.slot + 1 + expr.offset);
25273    case ExpressionKind.LexicalRead:
25274      throw new Error(`AssertionError: unresolved LexicalRead of ${expr.name}`);
25275    case ExpressionKind.TwoWayBindingSet:
25276      throw new Error(`AssertionError: unresolved TwoWayBindingSet`);
25277    case ExpressionKind.RestoreView:
25278      if (typeof expr.view === 'number') {
25279        throw new Error(`AssertionError: unresolved RestoreView`);
25280      }
25281      return restoreView(expr.view);
25282    case ExpressionKind.ResetView:
25283      return resetView(expr.expr);
25284    case ExpressionKind.GetCurrentView:
25285      return getCurrentView();
25286    case ExpressionKind.ReadVariable:
25287      if (expr.name === null) {
25288        throw new Error(`Read of unnamed variable ${expr.xref}`);
25289      }
25290      return variable(expr.name);
25291    case ExpressionKind.ReadTemporaryExpr:
25292      if (expr.name === null) {
25293        throw new Error(`Read of unnamed temporary ${expr.xref}`);
25294      }
25295      return variable(expr.name);
25296    case ExpressionKind.AssignTemporaryExpr:
25297      if (expr.name === null) {
25298        throw new Error(`Assign of unnamed temporary ${expr.xref}`);
25299      }
25300      return variable(expr.name).set(expr.expr);
25301    case ExpressionKind.PureFunctionExpr:
25302      if (expr.fn === null) {
25303        throw new Error(`AssertionError: expected PureFunctions to have been extracted`);
25304      }
25305      return pureFunction(expr.varOffset, expr.fn, expr.args);
25306    case ExpressionKind.PureFunctionParameterExpr:
25307      throw new Error(`AssertionError: expected PureFunctionParameterExpr to have been extracted`);
25308    case ExpressionKind.PipeBinding:
25309      return pipeBind(expr.targetSlot.slot, expr.varOffset, expr.args);
25310    case ExpressionKind.PipeBindingVariadic:
25311      return pipeBindV(expr.targetSlot.slot, expr.varOffset, expr.args);
25312    case ExpressionKind.SlotLiteralExpr:
25313      return literal(expr.slot.slot);
25314    default:
25315      throw new Error(`AssertionError: Unsupported reification of ir.Expression kind: ${ExpressionKind[expr.kind]}`);
25316  }
25317}
25318/**
25319 * Listeners get turned into a function expression, which may or may not have the `$event`
25320 * parameter defined.
25321 */
25322function reifyListenerHandler(unit, name, handlerOps, consumesDollarEvent) {
25323  // First, reify all instruction calls within `handlerOps`.
25324  reifyUpdateOperations(unit, handlerOps);
25325  // Next, extract all the `o.Statement`s from the reified operations. We can expect that at this
25326  // point, all operations have been converted to statements.
25327  const handlerStmts = [];
25328  for (const op of handlerOps) {
25329    if (op.kind !== OpKind.Statement) {
25330      throw new Error(`AssertionError: expected reified statements, but found op ${OpKind[op.kind]}`);
25331    }
25332    handlerStmts.push(op.statement);
25333  }
25334  // If `$event` is referenced, we need to generate it as a parameter.
25335  const params = [];
25336  if (consumesDollarEvent) {
25337    // We need the `$event` parameter.
25338    params.push(new FnParam('$event'));
25339  }
25340  return fn(params, handlerStmts, undefined, undefined, name);
25341}
25342
25343/**
25344 * Binding with no content can be safely deleted.
25345 */
25346function removeEmptyBindings(job) {
25347  for (const unit of job.units) {
25348    for (const op of unit.update) {
25349      switch (op.kind) {
25350        case OpKind.Attribute:
25351        case OpKind.Binding:
25352        case OpKind.ClassProp:
25353        case OpKind.ClassMap:
25354        case OpKind.Property:
25355        case OpKind.StyleProp:
25356        case OpKind.StyleMap:
25357          if (op.expression instanceof EmptyExpr) {
25358            OpList.remove(op);
25359          }
25360          break;
25361      }
25362    }
25363  }
25364}
25365
25366/**
25367 * Remove the i18n context ops after they are no longer needed, and null out references to them to
25368 * be safe.
25369 */
25370function removeI18nContexts(job) {
25371  for (const unit of job.units) {
25372    for (const op of unit.create) {
25373      switch (op.kind) {
25374        case OpKind.I18nContext:
25375          OpList.remove(op);
25376          break;
25377        case OpKind.I18nStart:
25378          op.context = null;
25379          break;
25380      }
25381    }
25382  }
25383}
25384
25385/**
25386 * i18nAttributes ops will be generated for each i18n attribute. However, not all i18n attribues
25387 * will contain dynamic content, and so some of these i18nAttributes ops may be unnecessary.
25388 */
25389function removeUnusedI18nAttributesOps(job) {
25390  for (const unit of job.units) {
25391    const ownersWithI18nExpressions = new Set();
25392    for (const op of unit.update) {
25393      switch (op.kind) {
25394        case OpKind.I18nExpression:
25395          ownersWithI18nExpressions.add(op.i18nOwner);
25396      }
25397    }
25398    for (const op of unit.create) {
25399      switch (op.kind) {
25400        case OpKind.I18nAttributes:
25401          if (ownersWithI18nExpressions.has(op.xref)) {
25402            continue;
25403          }
25404          OpList.remove(op);
25405      }
25406    }
25407  }
25408}
25409
25410/**
25411 * Resolves `ir.ContextExpr` expressions (which represent embedded view or component contexts) to
25412 * either the `ctx` parameter to component functions (for the current view context) or to variables
25413 * that store those contexts (for contexts accessed via the `nextContext()` instruction).
25414 */
25415function resolveContexts(job) {
25416  for (const unit of job.units) {
25417    processLexicalScope$1(unit, unit.create);
25418    processLexicalScope$1(unit, unit.update);
25419  }
25420}
25421function processLexicalScope$1(view, ops) {
25422  // Track the expressions used to access all available contexts within the current view, by the
25423  // view `ir.XrefId`.
25424  const scope = new Map();
25425  // The current view's context is accessible via the `ctx` parameter.
25426  scope.set(view.xref, variable('ctx'));
25427  for (const op of ops) {
25428    switch (op.kind) {
25429      case OpKind.Variable:
25430        switch (op.variable.kind) {
25431          case SemanticVariableKind.Context:
25432            scope.set(op.variable.view, new ReadVariableExpr(op.xref));
25433            break;
25434        }
25435        break;
25436      case OpKind.Listener:
25437      case OpKind.TwoWayListener:
25438        processLexicalScope$1(view, op.handlerOps);
25439        break;
25440    }
25441  }
25442  if (view === view.job.root) {
25443    // Prefer `ctx` of the root view to any variables which happen to contain the root context.
25444    scope.set(view.xref, variable('ctx'));
25445  }
25446  for (const op of ops) {
25447    transformExpressionsInOp(op, expr => {
25448      if (expr instanceof ContextExpr) {
25449        if (!scope.has(expr.view)) {
25450          throw new Error(`No context found for reference to view ${expr.view} from view ${view.xref}`);
25451        }
25452        return scope.get(expr.view);
25453      } else {
25454        return expr;
25455      }
25456    }, VisitorContextFlag.None);
25457  }
25458}
25459
25460/**
25461 * Any variable inside a listener with the name `$event` will be transformed into a output lexical
25462 * read immediately, and does not participate in any of the normal logic for handling variables.
25463 */
25464function resolveDollarEvent(job) {
25465  for (const unit of job.units) {
25466    transformDollarEvent(unit.create);
25467    transformDollarEvent(unit.update);
25468  }
25469}
25470function transformDollarEvent(ops) {
25471  for (const op of ops) {
25472    if (op.kind === OpKind.Listener || op.kind === OpKind.TwoWayListener) {
25473      transformExpressionsInOp(op, expr => {
25474        if (expr instanceof LexicalReadExpr && expr.name === '$event') {
25475          // Two-way listeners always consume `$event` so they omit this field.
25476          if (op.kind === OpKind.Listener) {
25477            op.consumesDollarEvent = true;
25478          }
25479          return new ReadVarExpr(expr.name);
25480        }
25481        return expr;
25482      }, VisitorContextFlag.InChildOperation);
25483    }
25484  }
25485}
25486
25487/**
25488 * Resolve the element placeholders in i18n messages.
25489 */
25490function resolveI18nElementPlaceholders(job) {
25491  // Record all of the element and i18n context ops for use later.
25492  const i18nContexts = new Map();
25493  const elements = new Map();
25494  for (const unit of job.units) {
25495    for (const op of unit.create) {
25496      switch (op.kind) {
25497        case OpKind.I18nContext:
25498          i18nContexts.set(op.xref, op);
25499          break;
25500        case OpKind.ElementStart:
25501          elements.set(op.xref, op);
25502          break;
25503      }
25504    }
25505  }
25506  resolvePlaceholdersForView(job, job.root, i18nContexts, elements);
25507}
25508/**
25509 * Recursively resolves element and template tag placeholders in the given view.
25510 */
25511function resolvePlaceholdersForView(job, unit, i18nContexts, elements, pendingStructuralDirective) {
25512  // Track the current i18n op and corresponding i18n context op as we step through the creation
25513  // IR.
25514  let currentOps = null;
25515  let pendingStructuralDirectiveCloses = new Map();
25516  for (const op of unit.create) {
25517    switch (op.kind) {
25518      case OpKind.I18nStart:
25519        if (!op.context) {
25520          throw Error('Could not find i18n context for i18n op');
25521        }
25522        currentOps = {
25523          i18nBlock: op,
25524          i18nContext: i18nContexts.get(op.context)
25525        };
25526        break;
25527      case OpKind.I18nEnd:
25528        currentOps = null;
25529        break;
25530      case OpKind.ElementStart:
25531        // For elements with i18n placeholders, record its slot value in the params map under the
25532        // corresponding tag start placeholder.
25533        if (op.i18nPlaceholder !== undefined) {
25534          if (currentOps === null) {
25535            throw Error('i18n tag placeholder should only occur inside an i18n block');
25536          }
25537          recordElementStart(op, currentOps.i18nContext, currentOps.i18nBlock, pe
25537ndingStructuralDirective);
25538          // If there is a separate close tag placeholder for this element, save the pending
25539          // structural directive so we can pass it to the closing tag as well.
25540          if (pendingStructuralDirective && op.i18nPlaceholder.closeName) {
25541            pendingStructuralDirectiveCloses.set(op.xref, pendingStructuralDirective);
25542          }
25543          // Clear out the pending structural directive now that its been accounted for.
25544          pendingStructuralDirective = undefined;
25545        }
25546        break;
25547      case OpKind.ElementEnd:
25548        // For elements with i18n placeholders, record its slot value in the params map under the
25549        // corresponding tag close placeholder.
25550        const startOp = elements.get(op.xref);
25551        if (startOp && startOp.i18nPlaceholder !== undefined) {
25552          if (currentOps === null) {
25553            throw Error('AssertionError: i18n tag placeholder should only occur inside an i18n block');
25554          }
25555          recordElementClose(startOp, currentOps.i18nContext, currentOps.i18nBlock, pendingStructuralDirectiveCloses.get(op.xref));
25556          // Clear out the pending structural directive close that was accounted for.
25557          pendingStructuralDirectiveCloses.delete(op.xref);
25558        }
25559        break;
25560      case OpKind.Projection:
25561        // For content projections with i18n placeholders, record its slot value in the params map
25562        // under the corresponding tag start and close placeholders.
25563        if (op.i18nPlaceholder !== undefined) {
25564          if (currentOps === null) {
25565            throw Error('i18n tag placeholder should only occur inside an i18n block');
25566          }
25567          recordElementStart(op, currentOps.i18nContext, currentOps.i18nBlock, pendingStructuralDirective);
25568          recordElementClose(op, currentOps.i18nContext, currentOps.i18nBlock, pendingStructuralDirective);
25569          // Clear out the pending structural directive now that its been accounted for.
25570          pendingStructuralDirective = undefined;
25571        }
25572        break;
25573      case OpKind.Template:
25574        const view = job.views.get(op.xref);
25575        if (op.i18nPlaceholder === undefined) {
25576          // If there is no i18n placeholder, just recurse into the view in case it contains i18n
25577          // blocks.
25578          resolvePlaceholdersForView(job, view, i18nContexts, elements);
25579        } else {
25580          if (currentOps === null) {
25581            throw Error('i18n tag placeholder should only occur inside an i18n block');
25582          }
25583          if (op.templateKind === TemplateKind.Structural) {
25584            // If this is a structural directive template, don't record anything yet. Instead pass
25585            // the current template as a pending structural directive to be recorded when we find
25586            // the element, content, or template it belongs to. This allows us to create combined
25587            // values that represent, e.g. the start of a template and element at the same time.
25588            resolvePlaceholdersForView(job, view, i18nContexts, elements, op);
25589          } else {
25590            // If this is some other kind of template, we can record its start, recurse into its
25591            // view, and then record its end.
25592            recordTemplateStart(job, view, op.handle.slot, op.i18nPlaceholder, currentOps.i18nContext, currentOps.i18nBlock, pendingStructuralDirective);
25593            resolvePlaceholdersForView(job, view, i18nContexts, elements);
25594            recordTemplateClose(job, view, op.handle.slot, op.i18nPlaceholder, currentOps.i18nContext, currentOps.i18nBlock, pendingStructuralDirective);
25595            pendingStructuralDirective = undefined;
25596          }
25597        }
25598        break;
25599      case OpKind.RepeaterCreate:
25600        if (pendingStructuralDirective !== undefined) {
25601          throw Error('AssertionError: Unexpected structural directive associated with @for block');
25602        }
25603        // RepeaterCreate has 3 slots: the first is for the op itself, the second is for the @for
25604        // template and the (optional) third is for the @empty template.
25605        const forSlot = op.handle.slot + 1;
25606        const forView = job.views.get(op.xref);
25607        // First record all of the placeholders for the @for template.
25608        if (op.i18nPlaceholder === undefined) {
25609          // If there is no i18n placeholder, just recurse into the view in case it contains i18n
25610          // blocks.
25611          resolvePlaceholdersForView(job, forView, i18nContexts, elements);
25612        } else {
25613          if (currentOps === null) {
25614            throw Error('i18n tag placeholder should only occur inside an i18n block');
25615          }
25616          recordTemplateStart(job, forView, forSlot, op.i18nPlaceholder, currentOps.i18nContext, currentOps.i18nBlock, pe
25616ndingStructuralDirective);
25617          resolvePlaceholdersForView(job, forView, i18nContexts, elements);
25618          recordTemplateClose(job, forView, forSlot, op.i18nPlaceholder, currentOps.i18nContext, currentOps.i18nBlock, pendingStructuralDirective);
25619          pendingStructuralDirective = undefined;
25620        }
25621        // Then if there's an @empty template, add its placeholders as well.
25622        if (op.emptyView !== null) {
25623          // RepeaterCreate has 3 slots: the first is for the op itself, the second is for the @for
25624          // template and the (optional) third is for the @empty template.
25625          const emptySlot = op.handle.slot + 2;
25626          const emptyView = job.views.get(op.emptyView);
25627          if (op.emptyI18nPlaceholder === undefined) {
25628            // If there is no i18n placeholder, just recurse into the view in case it contains i18n
25629            // blocks.
25630            resolvePlaceholdersForView(job, emptyView, i18nContexts, elements);
25631          } else {
25632            if (currentOps === null) {
25633              throw Error('i18n tag placeholder should only occur inside an i18n block');
25634            }
25635            recordTemplateStart(job, emptyView, emptySlot, op.emptyI18nPlaceholder, currentOps.i18nContext, currentOps.i18nBlock, pendingStructuralDirective);
25636            resolvePlaceholdersForView(job, emptyView, i18nContexts, elements);
25637            recordTemplateClose(job, emptyView, emptySlot, op.emptyI18nPlaceholder, currentOps.i18nContext, currentOps.i18nBlock, pendingStructuralDirective);
25638            pendingStructuralDirective = undefined;
25639          }
25640        }
25641        break;
25642    }
25643  }
25644}
25645/**
25646 * Records an i18n param value for the start of an element.
25647 */
25648function recordElementStart(op, i18nContext, i18nBlock, structuralDirective) {
25649  const {
25650    startName,
25651    closeName
25652  } = op.i18nPlaceholder;
25653  let flags = I18nParamValueFlags.ElementTag | I18nParamValueFlags.OpenTag;
25654  let value = op.handle.slot;
25655  // If the element is associated with a structural directive, start it as well.
25656  if (structuralDirective !== undefined) {
25657    flags |= I18nParamValueFlags.TemplateTag;
25658    value = {
25659      element: value,
25660      template: structuralDirective.handle.slot
25661    };
25662  }
25663  // For self-closing tags, there is no close tag placeholder. Instead, the start tag
25664  // placeholder accounts for the start and close of the element.
25665  if (!closeName) {
25666    flags |= I18nParamValueFlags.CloseTag;
25667  }
25668  addParam(i18nContext.params, startName, value, i18nBlock.subTemplateIndex, flags);
25669}
25670/**
25671 * Records an i18n param value for the closing of an element.
25672 */
25673function recordElementClose(op, i18nContext, i18nBlock, structuralDirective) {
25674  const {
25675    closeName
25676  } = op.i18nPlaceholder;
25677  // Self-closing tags don't have a closing tag placeholder, instead the element closing is
25678  // recorded via an additional flag on the element start value.
25679  if (closeName) {
25680    let flags = I18nParamValueFlags.ElementTag | I18nParamValueFlags.CloseTag;
25681    let value = op.handle.slot;
25682    // If the element is associated with a structural directive, close it as well.
25683    if (structuralDirective !== undefined) {
25684      flags |= I18nParamValueFlags.TemplateTag;
25685      value = {
25686        element: value,
25687        template: structuralDirective.handle.slot
25688      };
25689    }
25690    addParam(i18nContext.params, closeName, value, i18nBlock.subTemplateIndex, flags);
25691  }
25692}
25693/**
25694 * Records an i18n param value for the start of a template.
25695 */
25696function recordTemplateStart(job, view, slot, i18nPlaceholder, i18nContext, i18nBlock, structuralDirective) {
25697  let {
25698    startName,
25699    closeName
25700  } = i18nPlaceholder;
25701  let flags = I18nParamValueFlags.TemplateTag | I18nParamValueFlags.OpenTag;
25702  // For self-closing tags, there is no close tag placeholder. Instead, the start tag
25703  // placeholder accounts for the start and close of the element.
25704  if (!closeName) {
25705    flags |= I18nParamValueFlags.CloseTag;
25706  }
25707  // If the template is associated with a structural directive, record the structural directive's
25708  // start first. Since this template must be in the structural directive's view, we can just
25709  // directly use the current i18n block's sub-template index.
25710  if (structuralDirective !== undefined) {
25711    addParam(i18nContext.params, startName, structuralDirective.handle.slot, i18nBlock.subTemplateIndex, flags);
25712  }
25713  // Record the start of the template. For the sub-template index, pass the index for the template's
25714  // view, rather than the current i18n block's index.
25715  addParam(i18nContext.params, startName, slot, getSubTemplateIndexForTemplateTag(job, i18nBlock, view), flags);
25716}
25717/**
25718 * Records an i18n param value for the closing of a template.
25719 */
25720function recordTemplateClose(job, view, slot, i18nPlaceholder, i18nContext, i18nBlock, structuralDirective) {
25721  const {
25722    closeName
25723  } = i18nPlaceholder;
25724  const flags = I18nParamValueFlags.TemplateTag | I18nParamValueFlags.CloseTag;
25725  // Self-closing tags don't have a closing tag placeholder, instead the template's closing is
25726  // recorded via an additional flag on the template start value.
25727  if (closeName) {
25728    // Record the closing of the template. For the sub-template index, pass the index for the
25729    // template's view, rather than the current i18n block's index.
25730    addParam(i18nContext.params, closeName, slot, getSubTemplateIndexForTemplateTag(job, i18nBlock, view), flags);
25731    // If the template is associated with a structural directive, record the structural directive's
25732    // closing after. Since this template must be in the structural directive's view, we can just
25733    // directly use the current i18n block's sub-template index.
25734    if (structuralDirective !== undefined) {
25735      addParam(i18nContext.params, closeName, structuralDirective.handle.slot, i18nBlock.subTemplateIndex, flags);
25736    }
25737  }
25738}
25739/**
25740 * Get the subTemplateIndex for the given template op. For template ops, use the subTemplateIndex of
25741 * the child i18n block inside the template.
25742 */
25743function getSubTemplateIndexForTemplateTag(job, i18nOp, view) {
25744  for (const childOp of view.create) {
25745    if (childOp.kind === OpKind.I18nStart) {
25746      return childOp.subTemplateIndex;
25747    }
25748  }
25749  return i18nOp.subTemplateIndex;
25750}
25751/**
25752 * Add a param value to the given params map.
25753 */
25754function addParam(params, placeholder, value, subTemplateIndex, flags) {
25755  const values = params.get(placeholder) ?? [];
25756  values.push({
25757    value,
25758    subTemplateIndex,
25759    flags
25760  });
25761  params.set(placeholder, values);
25762}
25763
25764/**
25765 * Resolve the i18n expression placeholders in i18n messages.
25766 */
25767function resolveI18nExpressionPlaceholders(job) {
25768  // Record all of the i18n context ops, and the sub-template index for each i18n op.
25769  const subTemplateIndices = new Map();
25770  const i18nContexts = new Map();
25771  const icuPlaceholders = new Map();
25772  for (const unit of job.units) {
25773    for (const op of unit.create) {
25774      switch (op.kind) {
25775        case OpKind.I18nStart:
25776          subTemplateIndices.set(op.xref, op.subTemplateIndex);
25777          break;
25778        case OpKind.I18nContext:
25779          i18nContexts.set(op.xref, op);
25780          break;
25781        case OpKind.IcuPlaceholder:
25782          icuPlaceholders.set(op.xref, op);
25783          break;
25784      }
25785    }
25786  }
25787  // Keep track of the next available expression index for each i18n message.
25788  const expressionIndices = new Map();
25789  // Keep track of a reference index for each expression.
25790  // We use different references for normal i18n expressio and attribute i18n expressions. This is
25791  // because child i18n blocks in templates don't get their own context, since they're rolled into
25792  // the translated message of the parent, but they may target a different slot.
25793  const referenceIndex = op => op.usage === I18nExpressionFor.I18nText ? op.i18nOwner : op.context;
25794  for (const unit of job.units) {
25795    for (const op of unit.update) {
25796      if (op.kind === OpKind.I18nExpression) {
25797        const index = expressionIndices.get(referenceIndex(op)) || 0;
25798        const subTemplateIndex = subTemplateIndices.get(op.i18nOwner) ?? null;
25799        const value = {
25800          value: index,
25801          subTemplateIndex: subTemplateIndex,
25802          flags: I18nParamValueFlags.ExpressionIndex
25803        };
25804        updatePlaceholder(op, value, i18nContexts, icuPlaceholders);
25805        expressionIndices.set(referenceIndex(op), index + 1);
25806      }
25807    }
25808  }
25809}
25810function updatePlaceholder(op, value, i18nContexts, icuPlaceholders) {
25811  if (op.i18nPlaceholder !== null) {
25812    const i18nContext = i18nContexts.get(op.context);
25813    const params = op.resolutionTime === I18nParamResolutionTime.Creation ? i18nContext.params : i18nContext.postprocessingParams;
25814    const values = params.get(op.i18nPlaceholder) || [];
25815    values.push(value);
25816    params.set(op.i18nPlaceholder, values);
25817  }
25818  if (op.icuPlaceholder !== null) {
25819    const icuPlaceholderOp = icuPlaceholders.get(op.icuPlaceholder);
25820    icuPlaceholderOp?.expressionPlaceholders.push(value);
25821  }
25822}
25823
25824/**
25825 * Resolves lexical references in views (`ir.LexicalReadExpr`) to either a target variable or to
25826 * property reads on the top-level component context.
25827 *
25828 * Also matches `ir.RestoreViewExpr` expressions with the variables of their corresponding saved
25829 * views.
25830 */
25831function resolveNames(job) {
25832  for (const unit of job.units) {
25833    processLexicalScope(unit, unit.create, null);
25834    processLexicalScope(unit, unit.update, null);
25835  }
25836}
25837function processLexicalScope(unit, ops, savedView) {
25838  // Maps names defined in the lexical scope of this template to the `ir.XrefId`s of the variable
25839  // declarations which represent those values.
25840  //
25841  // Since variables are generated in each view for the entire lexical scope (including any
25842  // identifiers from parent templates) only local variables need be considered here.
25843  const scope = new Map();
25844  // First, step through the operations list and:
25845  // 1) build up the `scope` mapping
25846  // 2) recurse into any listener functions
25847  for (const op of ops) {
25848    switch (op.kind) {
25849      case OpKind.Variable:
25850        switch (op.variable.kind) {
25851          case SemanticVariableKind.Identifier:
25852          case SemanticVariableKind.Alias:
25853            // This variable represents some kind of identifier which can be used in the template.
25854            if (scope.has(op.variable.identifier)) {
25855              continue;
25856            }
25857            scope.set(op.variable.identifier, op.xref);
25858            break;
25859          case SemanticVariableKind.SavedView:
25860            // This variable represents a snapshot of the current view context, and can be used to
25861            // restore that context within listener functions.
25862            savedView = {
25863              view: op.variable.view,
25864              variable: op.xref
25865            };
25866            break;
25867        }
25868        break;
25869      case OpKind.Listener:
25870      case OpKind.TwoWayListener:
25871        // Listener functions have separate variable declarations, so process them as a separate
25872        // lexical scope.
25873        processLexicalScope(unit, op.handlerOps, savedView);
25874        break;
25875    }
25876  }
25877  // Next, use the `scope` mapping to match `ir.LexicalReadExpr` with defined names in the lexical
25878  // scope. Also, look for `ir.RestoreViewExpr`s and match them with the snapshotted view context
25879  // variable.
25880  for (const op of ops) {
25881    if (op.kind == OpKind.Listener || op.kind === OpKind.TwoWayListener) {
25882      // Listeners were already processed above with their own scopes.
25883      continue;
25884    }
25885    transformExpressionsInOp(op, expr => {
25886      if (expr instanceof LexicalReadExpr) {
25887        // `expr` is a read of a name within the lexical scope of this view.
25888        // Either that name is defined within the current view, or it represents a property from the
25889        // main component context.
25890        if (scope.has(expr.name)) {
25891          // This was a defined variable in the current scope.
25892          return new ReadVariableExpr(scope.get(expr.name));
25893        } else {
25894          // Reading from the component context.
25895          return new ReadPropExpr(new ContextExpr(unit.job.root.xref), expr.name);
25896        }
25897      } else if (expr instanceof RestoreViewExpr && typeof expr.view === 'number') {
25898        // `ir.RestoreViewExpr` happens in listener functions and restores a saved view from the
25899        // parent creation list. We expect to find that we captured the `savedView` previously, and
25900        // that it matches the expected view to be restored.
25901        if (savedView === null || savedView.view !== expr.view) {
25902          throw new Error(`AssertionError: no saved view ${expr.view} from view ${unit.xref}`);
25903        }
25904        expr.view = new ReadVariableExpr(savedView.variable);
25905        return expr;
25906      } else {
25907        return expr;
25908      }
25909    }, VisitorContextFlag.None);
25910  }
25911  for (const op of ops) {
25912    visitExpressionsInOp(op, expr => {
25913      if (expr instanceof LexicalReadExpr) {
25914        throw new Error(`AssertionError: no lexical reads should remain, but found read of ${expr.name}`);
25915      }
25916    });
25917  }
25918}
25919
25920/**
25921 * Map of security contexts to their sanitizer function.
25922 */
25923const sanitizerFns = new Map([[SecurityContext.HTML, Identifiers.sanitizeHtml], [SecurityContext.RESOURCE_URL, Identifiers.sanitizeResourceUrl], [SecurityContext.SCRIPT, Identifiers.sanitizeScript], [SecurityContext.STYLE, Identifiers.sanitizeStyle], [SecurityContext.URL, Identifiers.sanitizeUrl]]);
25924/**
25925 * Map of security contexts to their trusted value function.
25926 */
25927const trustedValueFns = new Map([[SecurityContext.HTML, Identifiers.trustConstantHtml], [SecurityContext.RESOURCE_URL, Identifiers.trustConstantResourceUrl]]);
25928/**
25929 * Resolves sanitization functions for ops that need them.
25930 */
25931function resolveSanitizers(job) {
25932  for (const unit of job.units) {
25933    const elements = createOpXrefMap(unit);
25934    // For normal element bindings we create trusted values for security sensitive constant
25935    // attributes. However, for host bindings we skip this step (this matches what
25936    // TemplateDefinitionBuilder does).
25937    // TODO: Is the TDB behavior correct here?
25938    if (job.kind !== CompilationJobKind.Host) {
25939      for (const op of unit.create) {
25940        if (op.kind === OpKind.ExtractedAttribute) {
25941          const trustedValueFn = trustedValueFns.get(getOnlySecurityContext(op.securityContext)) ?? null;
25942          op.trustedValueFn = trustedValueFn !== null ? importExpr(trustedValueFn) : null;
25943        }
25944      }
25945    }
25946    for (const op of unit.update) {
25947      switch (op.kind) {
25948        case OpKind.Property:
25949        case OpKind.Attribute:
25950        case OpKind.HostProperty:
25951          let sanitizerFn = null;
25952          if (Array.isArray(op.securityContext) && op.securityContext.length === 2 && op.securityContext.indexOf(SecurityContext.URL) > -1 && op.securityContext.indexOf(SecurityContext.RESOURCE_URL) > -1) {
25953            // When the host element isn't known, some URL attributes (such as "src" and "href") may
25954            // be part of multiple different security contexts. In this case we use special
25955            // sanitization function and select the actual sanitizer at runtime based on a tag name
25956            // that is provided while invoking sanitization function.
25957            sanitizerFn = Identifiers.sanitizeUrlOrResourceUrl;
25958          } else {
25959            sanitizerFn = sanitizerFns.get(getOnlySecurityContext(op.securityContext)) ?? null;
25960          }
25961          op.sanitizer = sanitizerFn !== null ? importExpr(sanitizerFn) : null;
25962          // If there was no sanitization function found based on the security context of an
25963          // attribute/property, check whether this attribute/property is one of the
25964          // security-sensitive <iframe> attributes (and that the current element is actually an
25965          // <iframe>).
25966          if (op.sanitizer === null) {
25967            let isIframe = false;
25968            if (job.kind === CompilationJobKind.Host || op.kind === OpKind.HostProperty) {
25969              // Note: for host bindings defined on a directive, we do not try to find all
25970              // possible places where it can be matched, so we can not determine whether
25971              // the host element is an <iframe>. In this case, we just assume it is and append a
25972              // validation function, which is invoked at runtime and would have access to the
25973              // underlying DOM element to check if it's an <iframe> and if so - run extra checks.
25974              isIframe = true;
25975            } else {
25976              // For a normal binding we can just check if the element its on is an iframe.
25977              const ownerOp = elements.get(op.target);
25978              if (ownerOp === undefined || !isElementOrContainerOp(ownerOp)) {
25979                throw Error('Property should have an element-like owner');
25980              }
25981              isIframe = isIframeElement$1(ownerOp);
25982            }
25983            if (isIframe && isIframeSecuritySensitiveAttr(op.name)) {
25984              op.sanitizer = importExpr(Identifiers.validateIframeAttribute);
25985            }
25986          }
25987          break;
25988      }
25989    }
25990  }
25991}
25992/**
25993 * Checks whether the given op represents an iframe element.
25994 */
25995function isIframeElement$1(op) {
25996  return op.kind === OpKind.ElementStart && op.tag?.toLowerCase() === 'iframe';
25997}
25998/**
25999 * Asserts that there is only a single security context and returns it.
26000 */
26001function getOnlySecurityContext(securityContext) {
26002  if (Array.isArray(securityContext)) {
26003    if (securityContext.length > 1) {
26004      // TODO: What should we do here? TDB just took the first one, but this feels like something we
26005      // would want to know about and create a special case for like we did for Url/ResourceUrl. My
26006      // guess is that, outside of the Url/ResourceUrl case, this never actually happens. If there
26007      // do turn out to be other cases, throwing an error until we can address it feels safer.
26008      throw Error(`AssertionError: Ambiguous security context`);
26009    }
26010    return securityContext[0] || SecurityContext.NONE;
26011  }
26012  return securityContext;
26013}
26014
26015/**
26016 * Transforms a `TwoWayBindingSet` expression into an expression that either
26017 * sets a value through the `twoWayBindingSet` instruction or falls back to setting
26018 * the value directly. E.g. the expression `TwoWayBindingSet(target, value)` becomes:
26019 * `ng.twoWayBindingSet(target, value) || (target = value)`.
26020 */
26021function transformTwoWayBindingSet(job) {
26022  for (const unit of job.units) {
26023    for (const op of unit.create) {
26024      if (op.kind === OpKind.TwoWayListener) {
26025        transformExpressionsInOp(op, expr => {
26026          if (expr instanceof TwoWayBindingSetExpr) {
26027            return wrapAction(expr.target, expr.value);
26028          }
26029          return expr;
26030        }, VisitorContextFlag.InChildOperation);
26031      }
26032    }
26033  }
26034}
26035function wrapSetOperation(target, value) {
26036  // ASSUMPTION: here we're assuming that `ReadVariableExpr` will be a reference
26037  // to a local template variable. This appears to be the case at the time of writing.
26038  // If the expression is targeting a variable read, we only emit the `twoWayBindingSet` since
26039  // the fallback would be attempting to write into a constant. Invalid usages will be flagged
26040  // during template type checking.
26041  if (target instanceof ReadVariableExpr) {
26042    return twoWayBindingSet(target, value);
26043  }
26044  return twoWayBindingSet(target, value).or(target.set(value));
26045}
26046function isReadExpression(value) {
26047  return value instanceof ReadPropExpr || value instanceof ReadKeyExpr || value instanceof ReadVariableExpr;
26048}
26049function wrapAction(target, value) {
26050  // The only officially supported expressions inside of a two-way binding are read expressions.
26051  if (isReadExpression(target)) {
26052    return wrapSetOperation(target, value);
26053  }
26054  // However, historically the expression parser was handling two-way events by appending `=$event`
26055  // to the raw string before attempting to parse it. This has led to bugs over the years (see
26056  // #37809) and to unintentionally supporting unassignable events in the two-way binding. The
26057  // logic below aims to emulate the old behavior while still supporting the new output format
26058  // which uses `twoWayBindingSet`. Note that the generated code doesn't necessarily make sense
26059  // based on what the user wrote, for example the event binding for `[(value)]="a ? b : c"`
26060  // would produce `ctx.a ? ctx.b : ctx.c = $event`. We aim to reproduce what the parser used
26061  // to generate before #54154.
26062  if (target instanceof BinaryOperatorExpr && isReadExpression(target.rhs)) {
26063    // `a && b` -> `ctx.a && twoWayBindingSet(ctx.b, $event) || (ctx.b = $event)`
26064    return new BinaryOperatorExpr(target.operator, target.lhs, wrapSetOperation(target.rhs, value));
26065  }
26066  // Note: this also supports nullish coalescing expressions which
26067  // would've been downleveled to ternary expressions by this point.
26068  if (target instanceof ConditionalExpr && isReadExpression(target.falseCase)) {
26069    // `a ? b : c` -> `ctx.a ? ctx.b : twoWayBindingSet(ctx.c, $event) || (ctx.c = $event)`
26070    return new ConditionalExpr(target.condition, target.trueCase, wrapSetOperation(target.falseCase, value));
26071  }
26072  // `!!a` -> `twoWayBindingSet(ctx.a, $event) || (ctx.a = $event)`
26073  // Note: previously we'd actually produce `!!(ctx.a = $event)`, but the wrapping
26074  // node doesn't affect the result so we don't need to carry it over.
26075  if (target instanceof NotExpr) {
26076    let expr = target.condition;
26077    while (true) {
26078      if (expr instanceof NotExpr) {
26079        expr = expr.condition;
26080      } else {
26081        if (isReadExpression(expr)) {
26082          return wrapSetOperation(expr, value);
26083        }
26084        break;
26085      }
26086    }
26087  }
26088  throw new Error(`Unsupported expression in two-way action binding.`);
26089}
26090
26091/**
26092 * When inside of a listener, we may need access to one or more enclosing views. Therefore, each
26093 * view should save the current view, and each listener must have the ability to restore the
26094 * appropriate view. We eagerly generate all save view variables; they will be optimized away later.
26095 */
26096function saveAndRestoreView(job) {
26097  for (const unit of job.units) {
26098    unit.create.prepend([createVariableOp(unit.job.allocateXrefId(), {
26099      kind: SemanticVariableKind.SavedView,
26100      name: null,
26101      view: unit.xref
26102    }, new GetCurrentViewExpr(), VariableFlags.None)]);
26103    for (const op of unit.create) {
26104      if (op.kind !== OpKind.Listener && op.kind !== OpKind.TwoWayListener) {
26105        continue;
26106      }
26107      // Embedded views always need the save/restore view operation.
26108      let needsRestoreView = unit !== job.root;
26109      if (!needsRestoreView) {
26110        for (const handlerOp of op.handlerOps) {
26111          visitExpressionsInOp(handlerOp, expr => {
26112            if (expr instanceof ReferenceExpr) {
26113              // Listeners that reference() a local ref need the save/restore view operation.
26114              needsRestoreView = true;
26115            }
26116          });
26117        }
26118      }
26119      if (needsRestoreView) {
26120        addSaveRestoreViewOperationToListener(unit, op);
26121      }
26122    }
26123  }
26124}
26125function addSaveRestoreViewOperationToListener(unit, op) {
26126  op.handlerOps.prepend([createVariableOp(unit.job.allocateXrefId(), {
26127    kind: SemanticVariableKind.Context,
26128    name: null,
26129    view: unit.xref
26130  }, new RestoreViewExpr(unit.xref), VariableFlags.None)]);
26131  // The "restore view" operation in listeners requires a call to `resetView` to reset the
26132  // context prior to returning from the listener operation. Find any `return` statements in
26133  // the listener body and wrap them in a call to reset the view.
26134  for (const handlerOp of op.handlerOps) {
26135    if (handlerOp.kind === OpKind.Statement && handlerOp.statement instanceof ReturnStatement) {
26136      handlerOp.statement.value = new ResetViewExpr(handlerOp.statement.value);
26137    }
26138  }
26139}
26140
26141/**
26142 * Assign data slots for all operations which implement `ConsumesSlotOpTrait`, and propagate the
26143 * assigned data slots of those operations to any expressions which reference them via
26144 * `UsesSlotIndexTrait`.
26145 *
26146 * This phase is also responsible for counting the number of slots used for each view (its `decls`)
26147 * and propagating that number into the `Template` operations which declare embedded views.
26148 */
26149function allocateSlots(job) {
26150  // Map of all declarations in all views within the component which require an assigned slot index.
26151  // This map needs to be global (across all views within the component) since it's possible to
26152  // reference a slot from one view from an expression within another (e.g. local references work
26153  // this way).
26154  const slotMap = new Map();
26155  // Process all views in the component and assign slot indexes.
26156  for (const unit of job.units) {
26157    // Slot indices start at 0 for each view (and are not unique between views).
26158    let slotCount = 0;
26159    for (const op of unit.create) {
26160      // Only consider declarations which consume data slots.
26161      if (!hasConsumesSlotTrait(op)) {
26162        continue;
26163      }
26164      // Assign slots to this declaration starting at the current `slotCount`.
26165      op.handle.slot = slotCount;
26166      // And track its assigned slot in the `slotMap`.
26167      slotMap.set(op.xref, op.handle.slot);
26168      // Each declaration may use more than 1 slot, so increment `slotCount` to reserve the number
26169      // of slots required.
26170      slotCount += op.numSlotsUsed;
26171    }
26172    // Record the total number of slots used on the view itself. This will later be propagated into
26173    // `ir.TemplateOp`s which declare those views (except for the root view).
26174    unit.decls = slotCount;
26175  }
26176  // After slot assignment, `slotMap` now contains slot assignments for every declaration in the
26177  // whole template, across all views. Next, look for expressions which implement
26178  // `UsesSlotIndexExprTrait` and propagate the assigned slot indexes into them.
26179  // Additionally, this second scan allows us to find `ir.TemplateOp`s which declare views and
26180  // propagate the number of slots used for each view into the operation which declares it.
26181  for (const unit of job.units) {
26182    for (const op of unit.ops()) {
26183      if (op.kind === OpKind.Template || op.kind === OpKind.RepeaterCreate) {
26184        // Record the number of slots used by the view this `ir.TemplateOp` declares in the
26185        // operation itself, so it can be emitted later.
26186        const childView = job.views.get(op.xref);
26187        op.decls = childView.decls;
26188        // TODO: currently we handle the decls for the RepeaterCreate empty template in the reify
26189        // phase. We should handle that here instead.
26190      }
26191    }
26192  }
26193}
26194
26195/**
26196 * Transforms special-case bindings with 'style' or 'class' in their names. Must run before the
26197 * main binding specialization pass.
26198 */
26199function specializeStyleBindings(job) {
26200  for (const unit of job.units) {
26201    for (const op of unit.update) {
26202      if (op.kind !== OpKind.Binding) {
26203        continue;
26204      }
26205      switch (op.bindingKind) {
26206        case BindingKind.ClassName:
26207          if (op.expression instanceof Interpolation) {
26208            throw new Error(`Unexpected interpolation in ClassName binding`);
26209          }
26210          OpList.replace(op, createClassPropOp(op.target, op.name, op.expression, op.sourceSpan));
26211          break;
26212        case BindingKind.StyleProperty:
26213          OpList.replace(op, createStylePropOp(op.target, op.name, op.expression, op.unit, op.sourceSpan));
26214          break;
26215        case BindingKind.Property:
26216        case BindingKind.Template:
26217          if (op.name === 'style') {
26218            OpList.replace(op, createStyleMapOp(op.target, op.expression, op.sourceSpan));
26219          } else if (op.name === 'class') {
26220            OpList.replace(op, createClassMapOp(op.target, op.expression, op.sourceSpan));
26221          }
26222          break;
26223      }
26224    }
26225  }
26226}
26227
26228/**
26229 * Find all assignments and usages of temporary variables, which are linked to each other with cross
26230 * references. Generate names for each cross-reference, and add a `DeclareVarStmt` to initialize
26231 * them at the beginning of the update block.
26232 *
26233 * TODO: Sometimes, it will be possible to reuse names across different subexpressions. For example,
26234 * in the double keyed read `a?.[f()]?.[f()]`, the two function calls have non-overlapping scopes.
26235 * Implement an algorithm for reuse.
26236 */
26237function generateTemporaryVariables(job) {
26238  for (const unit of job.units) {
26239    unit.create.prepend(generateTemporaries(unit.create));
26240    unit.update.prepend(generateTemporaries(unit.update));
26241  }
26242}
26243function generateTemporaries(ops) {
26244  let opCount = 0;
26245  let generatedStatements = [];
26246  // For each op, search for any variables that are assigned or read. For each variable, generate a
26247  // name and produce a `DeclareVarStmt` to the beginning of the block.
26248  for (const op of ops) {
26249    // Identify the final time each temp var is read.
26250    const finalReads = new Map();
26251    visitExpressionsInOp(op, (expr, flag) => {
26252      if (flag & VisitorContextFlag.InChildOperation) {
26253        return;
26254      }
26255      if (expr instanceof ReadTemporaryExpr) {
26256        finalReads.set(expr.xref, expr);
26257      }
26258    });
26259    // Name the temp vars, accounting for the fact that a name can be reused after it has been
26260    // read for the final time.
26261    let count = 0;
26262    const assigned = new Set();
26263    const released = new Set();
26264    const defs = new Map();
26265    visitExpressionsInOp(op, (expr, flag) => {
26266      if (flag & VisitorContextFlag.InChildOperation) {
26267        return;
26268      }
26269      if (expr instanceof AssignTemporaryExpr) {
26270        if (!assigned.has(expr.xref)) {
26271          assigned.add(expr.xref);
26272          // TODO: Exactly replicate the naming scheme used by `TemplateDefinitionBuilder`.
26273          // It seems to rely on an expression index instead of an op index.
26274          defs.set(expr.xref, `tmp_${opCount}_${count++}`);
26275        }
26276        assignName(defs, expr);
26277      } else if (expr instanceof ReadTemporaryExpr) {
26278        if (finalReads.get(expr.xref) === expr) {
26279          released.add(expr.xref);
26280          count--;
26281        }
26282        assignName(defs, expr);
26283      }
26284    });
26285    // Add declarations for the temp vars.
26286    generatedStatements.push(...Array.from(new Set(defs.values())).map(name => createStatementOp(new DeclareVarStmt(name))));
26287    opCount++;
26288    if (op.kind === OpKind.Listener || op.kind === OpKind.TwoWayListener) {
26289      op.handlerOps.prepend(generateTemporaries(op.handlerOps));
26290    }
26291  }
26292  return generatedStatements;
26293}
26294/**
26295 * Assigns a name to the temporary variable in the given temporary variable expression.
26296 */
26297function assignName(names, expr) {
26298  const name = names.get(expr.xref);
26299  if (name === undefined) {
26300    throw new Error(`Found xref with unassigned name: ${expr.xref}`);
26301  }
26302  expr.name = name;
26303}
26304
26305/**
26306 * Generate track functions that need to be extracted to the constant pool. This entails wrapping
26307 * them in an arrow (or traditional) function, replacing context reads with `this.`, and storing
26308 * them in the constant pool.
26309 *
26310 * Note that, if a track function was previously optimized, it will not need to be extracted, and
26311 * this phase is a no-op.
26312 */
26313function generateTrackFns(job) {
26314  for (const unit of job.units) {
26315    for (const op of unit.create) {
26316      if (op.kind !== OpKind.RepeaterCreate) {
26317        continue;
26318      }
26319      if (op.trackByFn !== null) {
26320        // The final track function was already set, probably because it was optimized.
26321        continue;
26322      }
26323      // Find all component context reads.
26324      let usesComponentContext = false;
26325      op.track = transformExpressionsInExpression(op.track, expr => {
26326        if (expr instanceof PipeBindingExpr || expr instanceof PipeBindingVariadicExpr) {
26327          throw new Error(`Illegal State: Pipes are not allowed in this context`);
26328        }
26329        if (expr instanceof TrackContextExpr) {
26330          usesComponentContext = true;
26331          return variable('this');
26332        }
26333        return expr;
26334      }, VisitorContextFlag.None);
26335      let fn;
26336      const fnParams = [new FnParam('$index'), new FnParam('$item')];
26337      if (usesComponentContext) {
26338        fn = new FunctionExpr(fnParams, [new ReturnStatement(op.track)]);
26339      } else {
26340        fn = arrowFn(fnParams, op.track);
26341      }
26342      op.trackByFn = job.pool.getSharedFunctionReference(fn, '_forTrack');
26343    }
26344  }
26345}
26346
26347/**
26348 * `track` functions in `for` repeaters can sometimes be "optimized," i.e. transformed into inline
26349 * expressions, in lieu of an external function call. For example, tracking by `$index` can be be
26350 * optimized into an inline `trackByIndex` reference. This phase checks track expressions for
26351 * optimizable cases.
26352 */
26353function optimizeTrackFns(job) {
26354  for (const unit of job.units) {
26355    for (const op of unit.create) {
26356      if (op.kind !== OpKind.RepeaterCreate) {
26357        continue;
26358      }
26359      if (op.track instanceof ReadVarExpr && op.track.name === '$index') {
26360        // Top-level access of `$index` uses the built in `repeaterTrackByIndex`.
26361        op.trackByFn = importExpr(Identifiers.repeaterTrackByIndex);
26362      } else if (op.track instanceof ReadVarExpr && op.track.name === '$item') {
26363        // Top-level access of the item uses the built in `repeaterTrackByIdentity`.
26364        op.trackByFn = importExpr(Identifiers.repeaterTrackByIdentity);
26365      } else if (isTrackByFunctionCall(job.root.xref, op.track)) {
26366        // Mark the function as using the component instance to play it safe
26367        // since the method might be using `this` internally (see #53628).
26368        op.usesComponentInstance = true;
26369        // Top-level method calls in the form of `fn($index, item)` can be passed in directly.
26370        if (op.track.receiver.receiver.view === unit.xref) {
26371          // TODO: this may be wrong
26372          op.trackByFn = op.track.receiver;
26373        } else {
26374          // This is a plain method call, but not in the component's root view.
26375          // We need to get the component instance, and then call the method on it.
26376          op.trackByFn = importExpr(Identifiers.componentInstance).callFn([]).prop(op.track.receiver.name);
26377          // Because the context is not avaiable (without a special function), we don't want to
26378          // try to resolve it later. Let's get rid of it by overwriting the original track
26379          // expression (which won't be used anyway).
26380          op.track = op.trackByFn;
26381        }
26382      } else {
26383        // The track function could not be optimized.
26384        // Replace context reads with a special IR expression, since context reads in a track
26385        // function are emitted specially.
26386        op.track = transformExpressionsInExpression(op.track, expr => {
26387          if (expr instanceof ContextExpr) {
26388            op.usesComponentInstance = true;
26389            return new TrackContextExpr(expr.view);
26390          }
26391          return expr;
26392        }, VisitorContextFlag.None);
26393      }
26394    }
26395  }
26396}
26397function isTrackByFunctionCall(rootView, expr) {
26398  if (!(expr instanceof InvokeFunctionExpr) || expr.args.length !== 2) {
26399    return false;
26400  }
26401  if (!(expr.receiver instanceof ReadPropExpr && expr.receiver.receiver instanceof ContextExpr) || expr.receiver.receiver.view !== rootView) {
26402    return false;
26403  }
26404  const [arg0, arg1] = expr.args;
26405  if (!(arg0 instanceof ReadVarExpr) || arg0.name !== '$index') {
26406    return false;
26407  }
26408  if (!(arg1 instanceof ReadVarExpr) || arg1.name !== '$item') {
26409    return false;
26410  }
26411  return true;
26412}
26413
26414/**
26415 * Inside the `track` expression on a `for` repeater, the `$index` and `$item` variables are
26416 * ambiently available. In this phase, we find those variable usages, and replace them with the
26417 * appropriate output read.
26418 */
26419function generateTrackVariables(job) {
26420  for (const unit of job.units) {
26421    for (const op of unit.create) {
26422      if (op.kind !== OpKind.RepeaterCreate) {
26423        continue;
26424      }
26425      op.track = transformExpressionsInExpression(op.track, expr => {
26426        if (expr instanceof LexicalReadExpr) {
26427          if (expr.name === op.varNames.$index) {
26428            return variable('$index');
26429          } else if (expr.name === op.varNames.$implicit) {
26430            return variable('$item');
26431          }
26432          // TODO: handle prohibited context variables (emit as globals?)
26433        }
26434        return expr;
26435      }, VisitorContextFlag.None);
26436    }
26437  }
26438}
26439
26440/**
26441 * Counts the number of variable slots used within each view, and stores that on the view itself, as
26442 * well as propagates it to the `ir.TemplateOp` for embedded views.
26443 */
26444function countVariables(job) {
26445  // First, count the vars used in each view, and update the view-level counter.
26446  for (const unit of job.units) {
26447    let varCount = 0;
26448    // Count variables on top-level ops first. Don't explore nested expressions just yet.
26449    for (const op of unit.ops()) {
26450      if (hasConsumesVarsTrait(op)) {
26451        varCount += varsUsedByOp(op);
26452      }
26453    }
26454    // Count variables on expressions inside ops. We do this later because some of these expressions
26455    // might be conditional (e.g. `pipeBinding` inside of a ternary), and we don't want to interfere
26456    // with indices for top-level binding slots (e.g. `property`).
26457    for (const op of unit.ops()) {
26458      visitExpressionsInOp(op, expr => {
26459        if (!isIrExpression(expr)) {
26460          return;
26461        }
26462        // TemplateDefinitionBuilder assigns variable offsets for everything but pure functions
26463        // first, and then assigns offsets to pure functions lazily. We emulate that behavior b
26463y
26464        // assigning offsets in two passes instead of one, only in compatibility mode.
26465        if (job.compatibility === CompatibilityMode.TemplateDefinitionBuilder && expr instanceof PureFunctionExpr) {
26466          return;
26467        }
26468        // Some expressions require knowledge of the number of variable slots consumed.
26469        if (hasUsesVarOffsetTrait(expr)) {
26470          expr.varOffset = varCount;
26471        }
26472        if (hasConsumesVarsTrait(expr)) {
26473          varCount += varsUsedByIrExpression(expr);
26474        }
26475      });
26476    }
26477    // Compatibility mode pass for pure function offsets (as explained above).
26478    if (job.compatibility === CompatibilityMode.TemplateDefinitionBuilder) {
26479      for (const op of unit.ops()) {
26480        visitExpressionsInOp(op, expr => {
26481          if (!isIrExpression(expr) || !(expr instanceof PureFunctionExpr)) {
26482            return;
26483          }
26484          // Some expressions require knowledge of the number of variable slots consumed.
26485          if (hasUsesVarOffsetTrait(expr)) {
26486            expr.varOffset = varCount;
26487          }
26488          if (hasConsumesVarsTrait(expr)) {
26489            varCount += varsUsedByIrExpression(expr);
26490          }
26491        });
26492      }
26493    }
26494    unit.vars = varCount;
26495  }
26496  if (job instanceof ComponentCompilationJob) {
26497    // Add var counts for each view to the `ir.TemplateOp` which declares that view (if the view is
26498    // an embedded view).
26499    for (const unit of job.units) {
26500      for (const op of unit.create) {
26501        if (op.kind !== OpKind.Template && op.kind !== OpKind.RepeaterCreate) {
26502          continue;
26503        }
26504        const childView = job.views.get(op.xref);
26505        op.vars = childView.vars;
26506        // TODO: currently we handle the vars for the RepeaterCreate empty template in the reify
26507        // phase. We should handle that here instead.
26508      }
26509    }
26510  }
26511}
26512/**
26513 * Different operations that implement `ir.UsesVarsTrait` use different numbers of variables, so
26514 * count the variables used by any particular `op`.
26515 */
26516function varsUsedByOp(op) {
26517  let slots;
26518  switch (op.kind) {
26519    case OpKind.Property:
26520    case OpKind.HostProperty:
26521    case OpKind.Attribute:
26522      // All of these bindings use 1 variable slot, plus 1 slot for every interpolated expression,
26523      // if any.
26524      slots = 1;
26525      if (op.expression instanceof Interpolation && !isSingletonInterpolation(op.expression)) {
26526        slots += op.expression.expressions.length;
26527      }
26528      return slots;
26529    case OpKind.TwoWayProperty:
26530      // Two-way properties can only have expressions so they only need one variable slot.
26531      return 1;
26532    case OpKind.StyleProp:
26533    case OpKind.ClassProp:
26534    case OpKind.StyleMap:
26535    case OpKind.ClassMap:
26536      // Style & class bindings use 2 variable slots, plus 1 slot for every interpolated expression,
26537      // if any.
26538      slots = 2;
26539      if (op.expression instanceof Interpolation) {
26540        slots += op.expression.expressions.length;
26541      }
26542      return slots;
26543    case OpKind.InterpolateText:
26544      // `ir.InterpolateTextOp`s use a variable slot for each dynamic expression.
26545      return op.interpolation.expressions.length;
26546    case OpKind.I18nExpression:
26547    case OpKind.Conditional:
26548    case OpKind.DeferWhen:
26549      return 1;
26550    case OpKind.RepeaterCreate:
26551      // Repeaters may require an extra variable binding slot, if they have an empty view, for the
26552      // empty block tracking.
26553      // TODO: It's a bit odd to have a create mode instruction consume variable slots. Maybe we can
26554      // find a way to use the Repeater update op instead.
26555      return op.emptyView ? 1 : 0;
26556    default:
26557      throw new Error(`Unhandled op: ${OpKind[op.kind]}`);
26558  }
26559}
26560function varsUsedByIrExpression(expr) {
26561  switch (expr.kind) {
26562    case ExpressionKind.PureFunctionExpr:
26563      return 1 + expr.args.length;
26564    case ExpressionKind.PipeBinding:
26565      return 1 + expr.args.length;
26566    case ExpressionKind.PipeBindingVariadic:
26567      return 1 + expr.numArgs;
26568    default:
26569      throw new Error(`AssertionError: unhandled ConsumesVarsTrait expression ${expr.constructor.name}`);
26570  }
26571}
26572function isSingletonInterpolation(expr) {
26573  if (expr.expressions.length !== 1 || expr.strings.length !== 2) {
26574    return false;
26575  }
26576  if (expr.strings[0] !== '' || expr.strings[1] !== '') {
26577    return false;
26578  }
26579  return true;
26580}
26581
26582/**
26583 * Optimize variables declared and used in the IR.
26584 *
26585 * Variables are eagerly generated by pipeline stages for all possible values that could be
26586 * referenced. This stage processes the list of declared variables and all variable usages,
26587 * and optimizes where possible. It performs 3 main optimizations:
26588 *
26589 *   * It transforms variable declarations to side effectful expressions when the
26590 *     variable is not used, but its initializer has global effects which other
26591 *     operations rely upon.
26592 *   * It removes variable declarations if those variables are not referenced and
26593 *     either they do not have global effects, or nothing relies on them.
26594 *   * It inlines variable declarations when those variables are only used once
26595 *     and the inlining is semantically safe.
26596 *
26597 * To guarantee correctness, analysis of "fences" in the instruction lists is used to determine
26598 * which optimizations are safe to perform.
26599 */
26600function optimizeVariables(job) {
26601  for (const unit of job.units) {
26602    inlineAlwaysInlineVariables(unit.create);
26603    inlineAlwaysInlineVariables(unit.update);
26604    for (const op of unit.create) {
26605      if (op.kind === OpKind.Listener || op.kind === OpKind.TwoWayListener) {
26606        inlineAlwaysInlineVariables(op.handlerOps);
26607      }
26608    }
26609    optimizeVariablesInOpList(unit.create, job.compatibility);
26610    optimizeVariablesInOpList(unit.update, job.compatibility);
26611    for (const op of unit.create) {
26612      if (op.kind === OpKind.Listener || op.kind === OpKind.TwoWayListener) {
26613        optimizeVariablesInOpList(op.handlerOps, job.compatibility);
26614      }
26615    }
26616  }
26617}
26618/**
26619 * A [fence](https://en.wikipedia.org/wiki/Memory_barrier) flag for an expression which indicates
26620 * how that expression can be optimized in relation to other expressions or instructions.
26621 *
26622 * `Fence`s are a bitfield, so multiple flags may be set on a single expression.
26623 */
26624var Fence;
26625(function (Fence) {
26626  /**
26627   * Empty flag (no fence exists).
26628   */
26629  Fence[Fence["None"] = 0] = "None";
26630  /**
26631   * A context read fence, meaning that the expression in question reads from the "current view"
26632   * context of the runtime.
26633   */
26634  Fence[Fence["ViewContextRead"] = 1] = "ViewContextRead";
26635  /**
26636   * A context write fence, meaning that the expression in question writes to the "current view"
26637   * context of the runtime.
26638   *
26639   * Note that all `ContextWrite` fences are implicitly `ContextRead` fences as operations which
26640   * change the view context do so based on the current one.
26641   */
26642  Fence[Fence["ViewContextWrite"] = 2] = "ViewContextWrite";
26643  /**
26644   * Indicates that a call is required for its side-effects, even if nothing reads its result.
26645   *
26646   * This is also true of `ViewContextWrite` operations **if** they are followed by a
26647   * `ViewContextRead`.
26648   */
26649  Fence[Fence["SideEffectful"] = 4] = "SideEffectful";
26650})(Fence || (Fence = {}));
26651function inlineAlwaysInlineVariables(ops) {
26652  const vars = new Map();
26653  for (const op of ops) {
26654    if (op.kind === OpKind.Variable && op.flags & VariableFlags.AlwaysInline) {
26655      visitExpressionsInOp(op, expr => {
26656        if (isIrExpression(expr) && fencesForIrExpression(expr) !== Fence.None) {
26657          throw new Error(`AssertionError: A context-sensitive variable was marked AlwaysInline`);
26658        }
26659      });
26660      vars.set(op.xref, op);
26661    }
26662    transformExpressionsInOp(op, expr => {
26663      if (expr instanceof ReadVariableExpr && vars.has(expr.xref)) {
26664        const varOp = vars.get(expr.xref);
26665        // Inline by cloning, because we might inline into multiple places.
26666        return varOp.initializer.clone();
26667      }
26668      return expr;
26669    }, VisitorContextFlag.None);
26670  }
26671  for (const op of vars.values()) {
26672    OpList.remove(op);
26673  }
26674}
26675/**
26676 * Process a list of operations and optimize variables within that list.
26677 */
26678function optimizeVariablesInOpList(ops, compatibility) {
26679  const varDecls = new Map();
26680  const varUsages = new Map();
26681  // Track variables that are used outside of the immediate operation list. For example, within
26682  // `ListenerOp` handler operations of listeners in the current operation list.
26683  const varRemoteUsages = new Set();
26684  const opMap = new Map();
26685  // First, extract information about variables declared or used within the whole list.
26686  for (const op of ops) {
26687    if (op.kind === OpKind.Variable) {
26688      if (varDecls.has(op.xref) || varUsages.has(op.xref)) {
26689        throw new Error(`Should not see two declarations of the same variable: ${op.xref}`);
26690      }
26691      varDecls.set(op.xref, op);
26692      varUsages.set(op.xref, 0);
26693    }
26694    opMap.set(op, collectOpInfo(op));
26695    countVariableUsages(op, varUsages, varRemoteUsages);
26696  }
26697  // The next step is to remove any variable declarations for variables that aren't used. The
26698  // variable initializer expressions may be side-effectful, so they may need to be retained as
26699  // expression statements.
26700  // Track whether we've seen an operation which reads from the view context yet. This is used to
26701  // determine whether a write to the view context in a variable initializer can be observed.
26702  let contextIsUsed = false;
26703  // Note that iteration through the list happens in reverse, which guarantees that we'll process
26704  // all reads of a variable prior to processing its declaration.
26705  for (const op of ops.reversed()) {
26706    const opInfo = opMap.get(op);
26707    if (op.kind === OpKind.Variable && varUsages.get(op.xref) === 0) {
26708      // This variable is unused and can be removed. We might need to keep the initializer around,
26709      // though, if something depends on it running.
26710      if (contextIsUsed && opInfo.fences & Fence.ViewContextWrite || opInfo.fences & Fence.SideEffectful) {
26711        // This variable initializer has a side effect which must be retained. Either:
26712        //  * it writes to the view context, and we know there is a future operation which depends
26713        //    on that write, or
26714        //  * it's an operation which is inherently side-effectful.
26715        // We can't remove the initializer, but we can remove the variable declaration itself and
26716        // replace it with a side-effectful statement.
26717        const stmtOp = createStatementOp(op.initializer.toStmt());
26718        opMap.set(stmtOp, opInfo);
26719        OpList.replace(op, stmtOp);
26720      } else {
26721        // It's safe to delete this entire variable declaration as nothing depends on it, even
26722        // side-effectfully. Note that doing this might make other variables unused. Since we're
26723        // iterating in reverse order, we should always be processing usages before declarations
26724        // and therefore by the time we get to a declaration, all removable usages will have been
26725        // removed.
26726        uncountVariableUsages(op, varUsages);
26727        OpList.remove(op);
26728      }
26729      opMap.delete(op);
26730      varDecls.delete(op.xref);
26731      varUsages.delete(op.xref);
26732      continue;
26733    }
26734    // Does this operation depend on the view context?
26735    if (opInfo.fences & Fence.ViewContextRead) {
26736      contextIsUsed = true;
26737    }
26738  }
26739  // Next, inline any remaining variables with exactly one usage.
26740  const toInline = [];
26741  for (const [id, count] of varUsages) {
26742    const decl = varDecls.get(id);
26743    // We can inline variables that:
26744    //  - are used exactly once, and
26745    //  - are not used remotely
26746    // OR
26747    //  - are marked for always inlining
26748    const isAlwaysInline = !!(decl.flags & VariableFlags.AlwaysInline);
26749    if (count !== 1 || isAlwaysInline) {
26750      // We can't inline this variable as it's used more than once.
26751      continue;
26752    }
26753    if (varRemoteUsages.has(id)) {
26754      // This variable is used once, but across an operation boundary, so it can't be inlined.
26755      continue;
26756    }
26757    toInline.push(id);
26758  }
26759  let candidate;
26760  while (candidate = toInline.pop()) {
26761    // We will attempt to inline this variable. If inlining fails (due to fences for example),
26762    // no future operation will make inlining legal.
26763    const decl = varDecls.get(candidate);
26764    const varInfo = opMap.get(decl);
26765    const isAlwaysInline = !!(decl.flags & VariableFlags.AlwaysInline);
26766    if (isAlwaysInline) {
26767      throw new Error(`AssertionError: Found an 'AlwaysInline' variable after the always inlining pass.`);
26768    }
26769    // Scan operations following the variable declaration and look for the point where that variable
26770    // is used. There should only be one usage given the precondition above.
26771    for (let targetOp = decl.next; targetOp.kind !== OpKind.ListEnd; targetOp = targetOp.next) {
26772      const opInfo = opMap.get(targetOp);
26773      // Is the variable used in this operation?
26774      if (opInfo.variablesUsed.has(candidate)) {
26775        if (compatibility === CompatibilityMode.TemplateDefinitionBuilder && !allowConservativeInlining(decl, targetOp)) {
26776          // We're in conservative mode, and this variable is not eligible for inlining into the
26777          // target operation in this mode.
26778          break;
26779        }
26780        // Yes, try to inline it. Inlining may not be successful if fences in this operation before
26781        // the variable's usage cannot be safely crossed.
26782        if (tryInlineVariableInitializer(candidate, decl.initializer, targetOp, varInfo.fences)) {
26783          // Inlining was successful! Update the tracking structures to reflect the inlined
26784          // variable.
26785          opInfo.variablesUsed.delete(candidate);
26786          // Add all variables used in the variable's initializer to its new usage site.
26787          for (const id of varInfo.variablesUsed) {
26788            opInfo.variablesUsed.add(id);
26789          }
26790          // Merge fences in the variable's initializer into its new usage site.
26791          opInfo.fences |= varInfo.fences;
26792          // Delete tracking info related to the declaration.
26793          varDecls.delete(candidate);
26794          varUsages.delete(candidate);
26795          opMap.delete(decl);
26796          // And finally, delete the original declaration from the operation list.
26797          OpList.remove(decl);
26798        }
26799        // Whether inlining succeeded or failed, we're done processing this variable.
26800        break;
26801      }
26802      // If the variable is not used in this operation, then we'd need to inline across it. Check if
26803      // that's safe to do.
26804      if (!safeToInlinePastFences(opInfo.fences, varInfo.fences)) {
26805        // We can't safely inline this variable beyond this operation, so don't proceed with
26806        // inlining this variable.
26807        break;
26808      }
26809    }
26810  }
26811}
26812/**
26813 * Given an `ir.Expression`, returns the `Fence` flags for that expression type.
26814 */
26815function fencesForIrExpression(expr) {
26816  switch (expr.kind) {
26817    case ExpressionKind.NextContext:
26818      return Fence.ViewContextRead | Fence.ViewContextWrite;
26819    case ExpressionKind.RestoreView:
26820      return Fence.ViewContextRead | Fence.ViewContextWrite | Fence.SideEffectful;
26821    case ExpressionKind.Reference:
26822      return Fence.ViewContextRead;
26823    default:
26824      return Fence.None;
26825  }
26826}
26827/**
26828 * Build the `OpInfo` structure for the given `op`. This performs two operations:
26829 *
26830 *  * It tracks which variables are used in the operation's expressions.
26831 *  * It rolls up fence flags for expressions within the operation.
26832 */
26833function collectOpInfo(op) {
26834  let fences = Fence.None;
26835  const variablesUsed = new Set();
26836  visitExpressionsInOp(op, expr => {
26837    if (!isIrExpression(expr)) {
26838      return;
26839    }
26840    switch (expr.kind) {
26841      case ExpressionKind.ReadVariable:
26842        variablesUsed.add(expr.xref);
26843        break;
26844      default:
26845        fences |= fencesForIrExpression(expr);
26846    }
26847  });
26848  return {
26849    fences,
26850    variablesUsed
26851  };
26852}
26853/**
26854 * Count the number of usages of each variable, being careful to track whether those usages are
26855 * local or remote.
26856 */
26857function countVariableUsages(op, varUsages, varRemoteUsage) {
26858  visitExpressionsInOp(op, (expr, flags) => {
26859    if (!isIrExpression(expr)) {
26860      return;
26861    }
26862    if (expr.kind !== ExpressionKind.ReadVariable) {
26863      return;
26864    }
26865    const count = varUsages.get(expr.xref);
26866    if (count === undefined) {
26867      // This variable is declared outside the current scope of optimization.
26868      return;
26869    }
26870    varUsages.set(expr.xref, count + 1);
26871    if (flags & VisitorContextFlag.InChildOperation) {
26872      varRemoteUsage.add(expr.xref);
26873    }
26874  });
26875}
26876/**
26877 * Remove usages of a variable in `op` from the `varUsages` tracking.
26878 */
26879function uncountVariableUsages(op, varUsages) {
26880  visitExpressionsInOp(op, expr => {
26881    if (!isIrExpression(expr)) {
26882      return;
26883    }
26884    if (expr.kind !== ExpressionKind.ReadVariable) {
26885      return;
26886    }
26887    const count = varUsages.get(expr.xref);
26888    if (count === undefined) {
26889      // This variable is declared outside the current scope of optimization.
26890      return;
26891    } else if (count === 0) {
26892      throw new Error(`Inaccurate variable count: ${expr.xref} - found another read but count is already 0`);
26893    }
26894    varUsages.set(expr.xref, count - 1);
26895  });
26896}
26897/**
26898 * Checks whether it's safe to inline a variable across a particular operation.
26899 *
26900 * @param fences the fences of the operation which the inlining will cross
26901 * @param declFences the fences of the variable being inlined.
26902 */
26903function safeToInlinePastFences(fences, declFences) {
26904  if (fences & Fence.ViewContextWrite) {
26905    // It's not safe to inline context reads across context writes.
26906    if (declFences & Fence.ViewContextRead) {
26907      return false;
26908    }
26909  } else if (fences & Fence.ViewContextRead) {
26910    // It's not safe to inline context writes across context reads.
26911    if (declFences & Fence.ViewContextWrite) {
26912      return false;
26913    }
26914  }
26915  return true;
26916}
26917/**
26918 * Attempt to inline the initializer of a variable into a target operation's expressions.
26919 *
26920 * This may or may not be safe to do. For example, the variable could be read following the
26921 * execution of an expression with fences that don't permit the variable to be inlined across them.
26922 */
26923function tryInlineVariableInitializer(id, initializer, target, declFences) {
26924  // We use `ir.transformExpressionsInOp` to walk the expressions and inline the variable if
26925  // possible. Since this operation is callback-based, once inlining succeeds or fails we can't
26926  // "stop" the expression processing, and have to keep track of whether inlining has succeeded or
26927  // is no longer allowed.
26928  let inlined = false;
26929  let inliningAllowed = true;
26930  transformExpressionsInOp(target, (expr, flags) => {
26931    if (!isIrExpression(expr)) {
26932      return expr;
26933    }
26934    if (inlined || !inliningAllowed) {
26935      // Either the inlining has already succeeded, or we've passed a fence that disallows inlining
26936      // at this point, so don't try.
26937      return expr;
26938    } else if (flags & VisitorContextFlag.InChildOperation && declFences & Fence.ViewContextRead) {
26939      // We cannot inline variables that are sensitive to the current context across operation
26940      // boundaries.
26941      return expr;
26942    }
26943    switch (expr.kind) {
26944      case ExpressionKind.ReadVariable:
26945        if (expr.xref === id) {
26946          // This is the usage site of the variable. Since nothing has disallowed inlining, it's
26947          // safe to inline the initializer here.
26948          inlined = true;
26949          return initializer;
26950        }
26951        break;
26952      default:
26953        // For other types of `ir.Expression`s, whether inlining is allowed depends on their fences.
26954        const exprFences = fencesForIrExpression(expr);
26955        inliningAllowed = inliningAllowed && safeToInlinePastFences(exprFences, declFences);
26956        break;
26957    }
26958    return expr;
26959  }, VisitorContextFlag.None);
26960  return inlined;
26961}
26962/**
26963 * Determines whether inlining of `decl` should be allowed in "conservative" mode.
26964 *
26965 * In conservative mode, inlining behavior is limited to those operations which the
26966 * `TemplateDefinitionBuilder` supported, with the goal of producing equivalent output.
26967 */
26968function allowConservativeInlining(decl, target) {
26969  // TODO(alxhub): understand exactly how TemplateDefinitionBuilder approaches inlining, and record
26970  // that behavior here.
26971  switch (decl.variable.kind) {
26972    case SemanticVariableKind.Identifier:
26973      if (decl.initializer instanceof ReadVarExpr && decl.initializer.name === 'ctx') {
26974        // Although TemplateDefinitionBuilder is cautious about inlining, we still want to do so
26975        // when the variable is the context, to imitate its behavior with aliases in control flow
26976        // blocks. This quirky behavior will become dead code once compatibility mode is no longer
26977        // supported.
26978        return true;
26979      }
26980      return false;
26981    case SemanticVariableKind.Context:
26982      // Context can only be inlined into other variables.
26983      return target.kind === OpKind.Variable;
26984    default:
26985      return true;
26986  }
26987}
26988
26989/**
26990 * Wraps ICUs that do not already belong to an i18n block in a new i18n block.
26991 */
26992function wrapI18nIcus(job) {
26993  for (const unit of job.units) {
26994    let currentI18nOp = null;
26995    let addedI18nId = null;
26996    for (const op of unit.create) {
26997      switch (op.kind) {
26998        case OpKind.I18nStart:
26999          currentI18nOp = op;
27000          break;
27001        case OpKind.I18nEnd:
27002          currentI18nOp = null;
27003          break;
27004        case OpKind.IcuStart:
27005          if (currentI18nOp === null) {
27006            addedI18nId = job.allocateXrefId();
27007            // ICU i18n start/end ops should not recieve source spans.
27008            OpList.insertBefore(createI18nStartOp(addedI18nId, op.message, undefined, null), op);
27009          }
27010          break;
27011        case OpKind.IcuEnd:
27012          if (addedI18nId !== null) {
27013            OpList.insertAfter(createI18nEndOp(addedI18nId, null), op);
27014            addedI18nId = null;
27015          }
27016          break;
27017      }
27018    }
27019  }
27020}
27021
27022/**
27023 *
27024 * @license
27025 * Copyright Google LLC All Rights Reserved.
27026 *
27027 * Use of this source code is governed by an MIT-style license that can be
27028 * found in the LICENSE file at https://angular.io/license
27029 */
27030const phases = [{
27031  kind: CompilationJobKind.Tmpl,
27032  fn: removeContentSelectors
27033}, {
27034  kind: CompilationJobKind.Host,
27035  fn: parseHostStyleProperties
27036}, {
27037  kind: CompilationJobKind.Tmpl,
27038  fn: emitNamespaceChanges
27039}, {
27040  kind: CompilationJobKind.Tmpl,
27041  fn: propagateI18nBlocks
27042}, {
27043  kind: CompilationJobKind.Tmpl,
27044  fn: wrapI18nIcus
27045}, {
27046  kind: CompilationJobKind.Both,
27047  fn: deduplicateTextBindings
27048}, {
27049  kind: CompilationJobKind.Both,
27050  fn: specializeStyleBindings
27051}, {
27052  kind: CompilationJobKind.Both,
27053  fn: specializeBindings
27054}, {
27055  kind: CompilationJobKind.Both,
27056  fn: extractAttributes
27057}, {
27058  kind: CompilationJobKind.Tmpl,
27059  fn: createI18nContexts
27060}, {
27061  kind: CompilationJobKind.Both,
27062  fn: parseExtractedStyles
27063}, {
27064  kind: CompilationJobKind.Tmpl,
27065  fn: removeEmptyBindings
27066}, {
27067  kind: CompilationJobKind.Both,
27068  fn: collapseSingletonInterpolations
27069}, {
27070  kind: CompilationJobKind.Both,
27071  fn: orderOps
27072}, {
27073  kind: CompilationJobKind.Tmpl,
27074  fn: generateConditionalExpressions
27075}, {
27076  kind: CompilationJobKind.Tmpl,
27077  fn: createPipes
27078}, {
27079  kind: CompilationJobKind.Tmpl,
27080  fn: configureDeferInstructions
27081}, {
27082  kind: CompilationJobKind.Tmpl,
27083  fn: convertI18nText
27084}, {
27085  kind: CompilationJobKind.Tmpl,
27086  fn: convertI18nBindings
27087}, {
27088  kind: CompilationJobKind.Tmpl,
27089  fn: removeUnusedI18nAttributesOps
27090}, {
27091  kind: CompilationJobKind.Tmpl,
27092  fn: assignI18nSlotDependencies
27093}, {
27094  kind: CompilationJobKind.Tmpl,
27095  fn: applyI18nExpressions
27096}, {
27097  kind: CompilationJobKind.Tmpl,
27098  fn: createVariadicPipes
27099}, {
27100  kind: CompilationJobKind.Both,
27101  fn: generatePureLiteralStructures
27102}, {
27103  kind: CompilationJobKind.Tmpl,
27104  fn: generateProjectionDefs
27105}, {
27106  kind: CompilationJobKind.Tmpl,
27107  fn: generateVariables
27108}, {
27109  kind: CompilationJobKind.Tmpl,
27110  fn: saveAndRestoreView
27111}, {
27112  kind: CompilationJobKind.Both,
27113  fn: deleteAnyCasts
27114}, {
27115  kind: CompilationJobKind.Both,
27116  fn: resolveDollarEvent
27117}, {
27118  kind: CompilationJobKind.Tmpl,
27119  fn: generateTrackVariables
27120}, {
27121  kind: CompilationJobKind.Both,
27122  fn: resolveNames
27123}, {
27124  kind: CompilationJobKind.Tmpl,
27125  fn: resolveDeferTargetNames
27126}, {
27127  kind: CompilationJobKind.Tmpl,
27128  fn: transformTwoWayBindingSet
27129}, {
27130  kind: CompilationJobKind.Tmpl,
27131  fn: optimizeTrackFns
27132}, {
27133  kind: CompilationJobKind.Both,
27134  fn: resolveContexts
27135}, {
27136  kind: CompilationJobKind.Both,
27137  fn: resolveSanitizers
27138}, {
27139  kind: CompilationJobKind.Tmpl,
27140  fn: liftLocalRefs
27141}, {
27142  kind: CompilationJobKind.Both,
27143  fn: generateNullishCoalesceExpressions
27144}, {
27145  kind: CompilationJobKind.Both,
27146  fn: expandSafeReads
27147}, {
27148  kind: CompilationJobKind.Both,
27149  fn: generateTemporaryVariables
27150}, {
27151  kind: CompilationJobKind.Tmpl,
27152  fn: allocateSlots
27153}, {
27154  kind: CompilationJobKind.Tmpl,
27155  fn: resolveI18nElementPlaceholders
27156}, {
27157  kind: CompilationJobKind.Tmpl,
27158  fn: resolveI18nExpressionPlaceholders
27159}, {
27160  kind: CompilationJobKind.Tmpl,
27161  fn: extractI18nMessages
27162}, {
27163  kind: CompilationJobKind.Tmpl,
27164  fn: generateTrackFns
27165}, {
27166  kind: CompilationJobKind.Tmpl,
27167  fn: collectI18nConsts
27168}, {
27169  kind: CompilationJobKind.Tmpl,
27170  fn: collectConstExpressions
27171}, {
27172  kind: CompilationJobKind.Both,
27173  fn: collectElementConsts
27174}, {
27175  kind: CompilationJobKind.Tmpl,
27176  fn: removeI18nContexts
27177}, {
27178  kind: CompilationJobKind.Both,
27179  fn: countVariables
27180}, {
27181  kind: CompilationJobKind.Tmpl,
27182  fn: generateAdvance
27183}, {
27184  kind: CompilationJobKind.Both,
27185  fn: optimizeVariables
27186}, {
27187  kind: CompilationJobKind.Both,
27188  fn: nameFunctionsAndVariables
27189}, {
27190  kind: CompilationJobKind.Tmpl,
27191  fn: createDeferDepsFns
27192}, {
27193  kind: CompilationJobKind.Tmpl,
27194  fn: mergeNextContextExpressions
27195}, {
27196  kind: CompilationJobKind.Tmpl,
27197  fn: generateNgContainerOps
27198}, {
27199  kind: CompilationJobKind.Tmpl,
27200  fn: collapseEmptyInstructions
27201}, {
27202  kind: CompilationJobKind.Tmpl,
27203  fn: disableBindings$1
27204}, {
27205  kind: CompilationJobKind.Both,
27206  fn: extractPureFunctions
27207}, {
27208  kind: CompilationJobKind.Both,
27209  fn: reify
27210}, {
27211  kind: CompilationJobKind.Both,
27212  fn: chain
27213}];
27214/**
27215 * Run all transformation phases in the correct order against a compilation job. After this
27216 * processing, the compilation should be in a state where it can be emitted.
27217 */
27218function transform(job, kind) {
27219  for (const phase of phases) {
27220    if (phase.kind === kind || phase.kind === CompilationJobKind.Both) {
27221      // The type of `Phase` above ensures it is impossible to call a phase that doesn't support the
27222      // job kind.
27223      phase.fn(job);
27224    }
27225  }
27226}
27227/**
27228 * Compile all views in the given `ComponentCompilation` into the final template function, which may
27229 * reference constants defined in a `ConstantPool`.
27230 */
27231function emitTemplateFn(tpl, pool) {
27232  const rootFn = emitView(tpl.root);
27233  emitChildViews(tpl.root, pool);
27234  return rootFn;
27235}
27236function emitChildViews(parent, pool) {
27237  for (const unit of parent.job.units) {
27238    if (unit.parent !== parent.xref) {
27239      continue;
27240    }
27241    // Child views are emitted depth-first.
27242    emitChildViews(unit, pool);
27243    const viewFn = emitView(unit);
27244    pool.statements.push(viewFn.toDeclStmt(viewFn.name));
27245  }
27246}
27247/**
27248 * Emit a template function for an individual `ViewCompilation` (which may be either the root view
27249 * or an embedded view).
27250 */
27251function emitView(view) {
27252  if (view.fnName === null) {
27253    throw new Error(`AssertionError: view ${view.xref} is unnamed`);
27254  }
27255  const createStatements = [];
27256  for (const op of view.create) {
27257    if (op.kind !== OpKind.Statement) {
27258      throw new Error(`AssertionError: expected all create ops to have been compiled, but got ${OpKind[op.kind]}`);
27259    }
27260    createStatements.push(op.statement);
27261  }
27262  const updateStatements = [];
27263  for (const op of view.update) {
27264    if (op.kind !== OpKind.Statement) {
27265      throw new Error(`AssertionError: expected all update ops to have been compiled, but got ${OpKind[op.kind]}`);
27266    }
27267    updateStatements.push(op.statement);
27268  }
27269  const createCond = maybeGenerateRfBlock(1, createStatements);
27270  const updateCond = maybeGenerateRfBlock(2, updateStatements);
27271  return fn([new FnParam('rf'), new FnParam('ctx')], [...createCond, ...updateCond], /* type */undefined, /* sourceSpan */undefined, view.fnName);
27272}
27273function maybeGenerateRfBlock(flag, statements) {
27274  if (statements.length === 0) {
27275    return [];
27276  }
27277  return [ifStmt(new BinaryOperatorExpr(BinaryOperator.BitwiseAnd, variable('rf'), literal(flag)), statements)];
27278}
27279function emitHostBindingFunction(job) {
27280  if (job.root.fnName === null) {
27281    throw new Error(`AssertionError: host binding function is unnamed`);
27282  }
27283  const createStatements = [];
27284  for (const op of job.root.create) {
27285    if (op.kind !== OpKind.Statement) {
27286      throw new Error(`AssertionError: expected all create ops to have been compiled, but got ${OpKind[op.kind]}`);
27287    }
27288    createStatements.push(op.statement);
27289  }
27290  const updateStatements = [];
27291  for (const op of job.root.update) {
27292    if (op.kind !== OpKind.Statement) {
27293      throw new Error(`AssertionError: expected all update ops to have been compiled, but got ${OpKind[op.kind]}`);
27294    }
27295    updateStatements.push(op.statement);
27296  }
27297  if (createStatements.length === 0 && updateStatements.length === 0) {
27298    return null;
27299  }
27300  const createCond = maybeGenerateRfBlock(1, createStatements);
27301  const updateCond = maybeGenerateRfBlock(2, updateStatements);
27302  return fn([new FnParam('rf'), new FnParam('ctx')], [...createCond, ...updateCond], /* type */undefined, /* sourceSpan */undefined, job.root.fnName);
27303}
27304const compatibilityMode = CompatibilityMode.TemplateDefinitionBuilder;
27305// Schema containing DOM elements and their properties.
27306const domSchema = new DomElementSchemaRegistry();
27307// Tag name of the `ng-template` element.
27308const NG_TEMPLATE_TAG_NAME$1 = 'ng-template';
27309/**
27310 * Process a template AST and convert it into a `ComponentCompilation` in the intermediate
27311 * representation.
27312 * TODO: Refactor more of the ingestion code into phases.
27313 */
27314function ingestComponent(componentName, template, constantPool, relativeContextFilePath, i18nUseExternalIds, deferBlocksMeta, allDeferrableDepsFn) {
27315  const job = new ComponentCompilationJob(componentName, constantPool, compatibilityMode, relativeContextFilePath, i18nUseExternalIds, deferBlocksMeta, allDeferrableDepsFn);
27316  ingestNodes(job.root, template);
27317  return job;
27318}
27319/**
27320 * Process a host binding AST and convert it into a `HostBindingCompilationJob` in the intermediate
27321 * representation.
27322 */
27323function ingestHostBinding(input, bindingParser, constantPool) {
27324  const job = new HostBindingCompilationJob(input.componentName, constantPool, compatibilityMode);
27325  for (const property of input.properties ?? []) {
27326    let bindingKind = BindingKind.Property;
27327    // TODO: this should really be handled in the parser.
27328    if (property.name.startsWith('attr.')) {
27329      property.name = property.name.substring('attr.'.length);
27330      bindingKind = BindingKind.Attribute;
27331    }
27332    if (property.isAnimation) {
27333      bindingKind = BindingKind.Animation;
27334    }
27335    const securityContexts = bindingParser.calcPossibleSecurityContexts(input.componentSelector, property.name, bindingKind === BindingKind.Attribute).filter(context => context !== SecurityContext.NONE);
27336    ingestHostProperty(job, property, bindingKind, securityContexts);
27337  }
27338  for (const [name, expr] of Object.entries(input.attributes) ?? []) {
27339    const securityContexts = bindingParser.calcPossibleSecurityContexts(input.componentSelector, name, true).filter(context => context !== SecurityContext.NONE);
27340    ingestHostAttribute(job, name, expr, securityContexts);
27341  }
27342  for (const event of input.events ?? []) {
27343    ingestHostEvent(job, event);
27344  }
27345  return job;
27346}
27347// TODO: We should refactor the parser to use the same types and structures for host bindings as
27348// with ordinary components. This would allow us to share a lot more ingestion code.
27349function ingestHostProperty(job, property, bindingKind, securityContexts) {
27350  let expression;
27351  const ast = property.expression.ast;
27352  if (ast instanceof Interpolation$1) {
27353    expression = new Interpolation(ast.strings, ast.expressions.map(expr => convertAst(expr, job, property.sourceSpan)), []);
27354  } else {
27355    expression = convertAst(ast, job, property.sourceSpan);
27356  }
27357  job.root.update.push(createBindingOp(job.root.xref, bindingKind, property.name, expression, null, securityContexts, false, false, null, /* TODO: How do Host bindings handle i18n attrs? */null, property.sourceSpan));
27358}
27359function ingestHostAttribute(job, name, value, securityContexts) {
27360  const attrBinding = createBindingOp(job.root.xref, BindingKind.Attribute, name, value, null, securityContexts,
27361  /* Host attributes should always be extracted to const hostAttrs, even if they are not
27362   *strictly* text literals */
27363  true, false, null, /* TODO */null, /** TODO: May be null? */value.sourceSpan);
27364  job.root.update.push(attrBinding);
27365}
27366function ingestHostEvent(job, event) {
27367  const [phase, target] = event.type !== 1 /* e.ParsedEventType.Animation */ ? [null, event.targetOrPhase] : [event.targetOrPhase, null];
27368  const eventBinding = createListenerOp(job.root.xref, new SlotHandle(), event.name, null, makeListenerHandlerOps(job.root, event.handler, event.handlerSpan), phase, target, true, event.sourceSpan);
27369  job.root.create.push(eventBinding);
27370}
27371/**
27372 * Ingest the nodes of a template AST into the given `ViewCompilation`.
27373 */
27374function ingestNodes(unit, template) {
27375  for (const node of template) {
27376    if (node instanceof Element$1) {
27377      ingestElement(unit, node);
27378    } else if (node instanceof Template) {
27379      ingestTemplate(unit, node);
27380    } else if (node instanceof Content) {
27381      ingestContent(unit, node);
27382    } else if (node instanceof Text$3) {
27383      ingestText(unit, node, null);
27384    } else if (node instanceof BoundText) {
27385      ingestBoundText(unit, node, null);
27386    } else if (node instanceof IfBlock) {
27387      ingestIfBlock(unit, node);
27388    } else if (node instanceof SwitchBlock) {
27389      ingestSwitchBlock(unit, node);
27390    } else if (node instanceof DeferredBlock) {
27391      ingestDeferBlock(unit, node);
27392    } else if (node instanceof Icu$1) {
27393      ingestIcu(unit, node);
27394    } else if (node instanceof ForLoopBlock) {
27395      ingestForBlock(unit, node);
27396    } else {
27397      throw new Error(`Unsupported template node: ${node.constructor.name}`);
27398    }
27399  }
27400}
27401/**
27402 * Ingest an element AST from the template into the given `ViewCompilation`.
27403 */
27404function ingestElement(unit, element) {
27405  if (element.i18n !== undefined && !(element.i18n instanceof Message || element.i18n instanceof TagPlaceholder)) {
27406    throw Error(`Unhandled i18n metadata type for element: ${element.i18n.constructor.name}`);
27407  }
27408  const id = unit.job.allocateXrefId();
27409  const [namespaceKey, elementName] = splitNsName(element.name);
27410  const startOp = createElementStartOp(elementName, id, namespaceForKey(namespaceKey), element.i18n instanceof TagPlaceholder ? element.i18n : undefined, element.startSourceSpan, element.sourceSpan);
27411  unit.create.push(startOp);
27412  ingestElementBindings(unit, startOp, element);
27413  ingestReferences(startOp, element);
27414  // Start i18n, if needed, goes after the element create and bindings, but before the nodes
27415  let i18nBlockId = null;
27416  if (element.i18n instanceof Message) {
27417    i18nBlockId = unit.job.allocateXrefId();
27418    unit.create.push(createI18nStartOp(i18nBlockId, element.i18n, undefined, element.startSourceSpan));
27419  }
27420  ingestNodes(unit, element.children);
27421  // The source span for the end op is typically the element closing tag. However, if no closing tag
27422  // exists, such as in `<input>`, we use the start source span instead. Usually the start and end
27423  // instructions will be collapsed into one `element` instruction, negating the purpose of this
27424  // fallback, but in cases when it is not collapsed (such as an input with a binding), we still
27425  // want to map the end instruction to the main element.
27426  const endOp = createElementEndOp(id, element.endSourceSpan ?? element.startSourceSpan);
27427  unit.create.push(endOp);
27428  // If there is an i18n message associated with this element, insert i18n start and end ops.
27429  if (i18nBlockId !== null) {
27430    OpList.insertBefore(createI18nEndOp(i18nBlockId, element.endSourceSpan ?? element.startSourceSpan), endOp);
27431  }
27432}
27433/**
27434 * Ingest an `ng-template` node from the AST into the given `ViewCompilation`.
27435 */
27436function ingestTemplate(unit, tmpl) {
27437  if (tmpl.i18n !== undefined && !(tmpl.i18n instanceof Message || tmpl.i18n instanceof TagPlaceholder)) {
27438    throw Error(`Unhandled i18n metadata type for template: ${tmpl.i18n.constructor.name}`);
27439  }
27440  const childView = unit.job.allocateView(unit.xref);
27441  let tagNameWithoutNamespace = tmpl.tagName;
27442  let namespacePrefix = '';
27443  if (tmpl.tagName) {
27444    [namespacePrefix, tagNameWithoutNamespace] = splitNsName(tmpl.tagName);
27445  }
27446  const i18nPlaceholder = tmpl.i18n instanceof TagPlaceholder ? tmpl.i18n : undefined;
27447  const namespace = namespaceForKey(namespacePrefix);
27448  const functionNameSuffix = tagNameWithoutNamespace === null ? '' : prefixWithNamespace(tagNameWithoutNamespace, namespace);
27449  const templateKind = isPlainTemplate(tmpl) ? TemplateKind.NgTemplate : TemplateKind.Structural;
27450  const templateOp = createTemplateOp(childView.xref, templateKind, tagNameWithoutNamespace, functionNameSuffix, namespace, i18nPlaceholder, tmpl.startSourceSpan, tmpl.sourceSpan);
27451  unit.create.push(templateOp);
27452  ingestTemplateBindings(unit, templateOp, tmpl, templateKind);
27453  ingestReferences(templateOp, tmpl);
27454  ingestNodes(childView, tmpl.children);
27455  for (const {
27456    name,
27457    value
27458  } of tmpl.variables) {
27459    childView.contextVariables.set(name, value !== '' ? value : '$implicit');
27460  }
27461  // If this is a plain template and there is an i18n message associated with it, insert i18n start
27462  // and end ops. For structural directive templates, the i18n ops will be added when ingesting the
27463  // element/template the directive is placed on.
27464  if (templateKind === TemplateKind.NgTemplate && tmpl.i18n instanceof Message) {
27465    const id = unit.job.allocateXrefId();
27466    OpList.insertAfter(createI18nStartOp(id, tmpl.i18n, undefined, tmpl.startSourceSpan), childView.create.head);
27467    OpList.insertBefore(createI18nEndOp(id, tmpl.endSourceSpan ?? tmpl.startSourceSpan), childView.create.tail);
27468  }
27469}
27470/**
27471 * Ingest a content node from the AST into the given `ViewCompilation`.
27472 */
27473function ingestContent(unit, content) {
27474  if (content.i18n !== undefined && !(content.i18n instanceof TagPlaceholder)) {
27475    throw Error(`Unhandled i18n metadata type for element: ${content.i18n.constructor.name}`);
27476  }
27477  const op = createProjectionOp(unit.job.allocateXrefId(), content.selector, content.i18n, content.sourceSpan);
27478  for (const attr of content.attributes) {
27479    const securityContext = domSchema.securityContext(content.name, attr.name, true);
27480    unit.update.push(createBindingOp(op.xref, BindingKind.Attribute, attr.name, literal(attr.value), null, securityContext, true, false, null, asMessage(attr.i18n), attr.sourceSpan));
27481  }
27482  unit.create.push(op);
27483}
27484/**
27485 * Ingest a literal text node from the AST into the given `ViewCompilation`.
27486 */
27487function ingestText(unit, text, icuPlaceholder) {
27488  unit.create.push(createTextOp(unit.job.allocateXrefId(), text.value, icuPlaceholder, text.sourceSpan));
27489}
27490/**
27491 * Ingest an interpolated text node from the AST into the given `ViewCompilation`.
27492 */
27493function ingestBoundText(unit, text, icuPlaceholder) {
27494  let value = text.value;
27495  if (value instanceof ASTWithSource) {
27496    value = value.ast;
27497  }
27498  if (!(value instanceof Interpolation$1)) {
27499    throw new Error(`AssertionError: expected Interpolation for BoundText node, got ${value.constructor.name}`);
27500  }
27501  if (text.i18n !== undefined && !(text.i18n instanceof Container)) {
27502    throw Error(`Unhandled i18n metadata type for text interpolation: ${text.i18n?.constructor.name}`);
27503  }
27504  const i18nPlaceholders = text.i18n instanceof Container ? text.i18n.children.filter(node =>
27504 node instanceof Placeholder).map(placeholder => placeholder.name) : [];
27505  if (i18nPlaceholders.length > 0 && i18nPlaceholders.length !== value.expressions.length) {
27506    throw Error(`Unexpected number of i18n placeholders (${value.expressions.length}) for BoundText with ${value.expressions.length} expressions`);
27507  }
27508  const textXref = unit.job.allocateXrefId();
27509  unit.create.push(createTextOp(textXref, '', icuPlaceholder, text.sourceSpan));
27510  // TemplateDefinitionBuilder does not generate source maps for sub-expressions inside an
27511  // interpolation. We copy that behavior in compatibility mode.
27512  // TODO: is it actually correct to generate these extra maps in modern mode?
27513  const baseSourceSpan = unit.job.compatibility ? null : text.sourceSpan;
27514  unit.update.push(createInterpolateTextOp(textXref, new Interpolation(value.strings, value.expressions.map(expr => convertAst(expr, unit.job, baseSourceSpan)), i18nPlaceholders), text.sourceSpan));
27515}
27516/**
27517 * Ingest an `@if` block into the given `ViewCompilation`.
27518 */
27519function ingestIfBlock(unit, ifBlock) {
27520  let firstXref = null;
27521  let firstSlotHandle = null;
27522  let conditions = [];
27523  for (let i = 0; i < ifBlock.branches.length; i++) {
27524    const ifCase = ifBlock.branches[i];
27525    const cView = unit.job.allocateView(unit.xref);
27526    let tagName = null;
27527    // Only the first branch can be used for projection, because the conditional
27528    // uses the container of the first branch as the insertion point for all branches.
27529    if (i === 0) {
27530      tagName = ingestControlFlowInsertionPoint(unit, cView.xref, ifCase);
27531    }
27532    if (ifCase.expressionAlias !== null) {
27533      cView.contextVariables.set(ifCase.expressionAlias.name, CTX_REF);
27534    }
27535    let ifCaseI18nMeta = undefined;
27536    if (ifCase.i18n !== undefined) {
27537      if (!(ifCase.i18n instanceof BlockPlaceholder)) {
27538        throw Error(`Unhandled i18n metadata type for if block: ${ifCase.i18n?.constructor.name}`);
27539      }
27540      ifCaseI18nMeta = ifCase.i18n;
27541    }
27542    const templateOp = createTemplateOp(cView.xref, TemplateKind.Block, tagName, 'Conditional', Namespace.HTML, ifCaseI18nMeta, ifCase.startSourceSpan, ifCase.sourceSpan);
27543    unit.create.push(templateOp);
27544    if (firstXref === null) {
27545      firstXref = cView.xref;
27546      firstSlotHandle = templateOp.handle;
27547    }
27548    const caseExpr = ifCase.expression ? convertAst(ifCase.expression, unit.job, null) : null;
27549    const conditionalCaseExpr = new ConditionalCaseExpr(caseExpr, templateOp.xref, templateOp.handle, ifCase.expressionAlias);
27550    conditions.push(conditionalCaseExpr);
27551    ingestNodes(cView, ifCase.children);
27552  }
27553  const conditional = createConditionalOp(firstXref, firstSlotHandle, null, conditions, ifBlock.sourceSpan);
27554  unit.update.push(conditional);
27555}
27556/**
27557 * Ingest an `@switch` block into the given `ViewCompilation`.
27558 */
27559function ingestSwitchBlock(unit, switchBlock) {
27560  // Don't ingest empty switches since they won't render anything.
27561  if (switchBlock.cases.length === 0) {
27562    return;
27563  }
27564  let firstXref = null;
27565  let firstSlotHandle = null;
27566  let conditions = [];
27567  for (const switchCase of switchBlock.cases) {
27568    const cView = unit.job.allocateView(unit.xref);
27569    let switchCaseI18nMeta = undefined;
27570    if (switchCase.i18n !== undefined) {
27571      if (!(switchCase.i18n instanceof BlockPlaceholder)) {
27572        throw Error(`Unhandled i18n metadata type for switch block: ${switchCase.i18n?.constructor.name}`);
27573      }
27574      switchCaseI18nMeta = switchCase.i18n;
27575    }
27576    const templateOp = createTemplateOp(cView.xref, TemplateKind.Block, null, 'Case', Namespace.HTML, switchCaseI18nMeta, switchCase.startSourceSpan, switchCase.sourceSpan);
27577    unit.create.push(templateOp);
27578    if (firstXref === null) {
27579      firstXref = cView.xref;
27580      firstSlotHandle = templateOp.handle;
27581    }
27582    const caseExpr = switchCase.expression ? convertAst(switchCase.expression, unit.job, switchBlock.startSourceSpan) : null;
27583    const conditionalCaseExpr = new ConditionalCaseExpr(caseExpr, templateOp.xref, templateOp.handle);
27584    conditions.push(conditionalCaseExpr);
27585    ingestNodes(cView, switchCase.children);
27586  }
27587  const conditional = createConditionalOp(firstXref, firstSlotHandle, convertAst(switchBlock.expression, unit.job, null), conditions, switchBlock.sourceSpan);
27588  unit.update.push(conditional);
27589}
27590function ingestDeferView(unit, suffix, i18nMeta, children, sourceSpan) {
27591  if (i18nMeta !== undefined && !(i18nMeta instanceof BlockPlaceholder)) {
27592    throw Error('Unhandled i18n metadata type for defer block');
27593  }
27594  if (children === undefined) {
27595    return null;
27596  }
27597  const secondaryView = unit.job.allocateView(unit.xref);
27598  ingestNodes(secondaryView, children);
27599  const templateOp = createTemplateOp(secondaryView.xref, TemplateKind.Block, null, `Defer${suffix}`, Namespace.HTML, i18nMeta, sourceSpan, sourceSpan);
27600  unit.create.push(templateOp);
27601  return templateOp;
27602}
27603function ingestDeferBlock(unit, deferBlock) {
27604  const blockMeta = unit.job.deferBlocksMeta.get(deferBlock);
27605  if (blockMeta === undefined) {
27606    throw new Error(`AssertionError: unable to find metadata for deferred block`);
27607  }
27608  // Generate the defer main view and all secondary views.
27609  const main = ingestDeferView(unit, '', deferBlock.i18n, deferBlock.children, deferBlock.sourceSpan);
27610  const loading = ingestDeferView(unit, 'Loading', deferBlock.loading?.i18n, deferBlock.loading?.children, deferBlock.loading?.sourceSpan);
27611  const placeholder = ingestDeferView(unit, 'Placeholder', deferBlock.placeholder?.i18n, deferBlock.placeholder?.children, deferBlock.placeholder?.sourceSpan);
27612  const error = ingestDeferView(unit, 'Error', deferBlock.error?.i18n, deferBlock.error?.children, deferBlock.error?.sourceSpan);
27613  // Create the main defer op, and ops for all secondary views.
27614  const deferXref = unit.job.allocateXrefId();
27615  const deferOp = createDeferOp(deferXref, main.xref, main.handle, blockMeta, unit.job.allDeferrableDepsFn, deferBlock.sourceSpan);
27616  deferOp.placeholderView = placeholder?.xref ?? null;
27617  deferOp.placeholderSlot = placeholder?.handle ?? null;
27618  deferOp.loadingSlot = loading?.handle ?? null;
27619  deferOp.errorSlot = error?.handle ?? null;
27620  deferOp.placeholderMinimumTime = deferBlock.placeholder?.minimumTime ?? null;
27621  deferOp.loadingMinimumTime = deferBlock.loading?.minimumTime ?? null;
27622  deferOp.loadingAfterTime = deferBlock.loading?.afterTime ?? null;
27623  unit.create.push(deferOp);
27624  // Configure all defer `on` conditions.
27625  // TODO: refactor prefetch triggers to use a separate op type, with a shared superclass. This will
27626  // make it easier to refactor prefetch behavior in the future.
27627  let prefetch = false;
27628  let deferOnOps = [];
27629  let deferWhenOps = [];
27630  for (const triggers of [deferBlock.triggers, deferBlock.prefetchTriggers]) {
27631    if (triggers.idle !== undefined) {
27632      const deferOnOp = createDeferOnOp(deferXref, {
27633        kind: DeferTriggerKind.Idle
27634      }, prefetch, triggers.idle.sourceSpan);
27635      deferOnOps.push(deferOnOp);
27636    }
27637    if (triggers.immediate !== undefined) {
27638      const deferOnOp = createDeferOnOp(deferXref, {
27639        kind: DeferTriggerKind.Immediate
27640      }, prefetch, triggers.immediate.sourceSpan);
27641      deferOnOps.push(deferOnOp);
27642    }
27643    if (triggers.timer !== undefined) {
27644      const deferOnOp = createDeferOnOp(deferXref, {
27645        kind: DeferTriggerKind.Timer,
27646        delay: triggers.timer.delay
27647      }, prefetch, triggers.timer.sourceSpan);
27648      deferOnOps.push(deferOnOp);
27649    }
27650    if (triggers.hover !== undefined) {
27651      const deferOnOp = createDeferOnOp(deferXref, {
27652        kind: DeferTriggerKind.Hover,
27653        targetName: triggers.hover.reference,
27654        targetXref: null,
27655        targetSlot: null,
27656        targetView: null,
27657        targetSlotViewSteps: null
27658      }, prefetch, triggers.hover.sourceSpan);
27659      deferOnOps.push(deferOnOp);
27660    }
27661    if (triggers.interaction !== undefined) {
27662      const deferOnOp = createDeferOnOp(deferXref, {
27663        kind: DeferTriggerKind.Interaction,
27664        targetName: triggers.interaction.reference,
27665        targetXref: null,
27666        targetSlot: null,
27667        targetView: null,
27668        targetSlotViewSteps: null
27669      }, prefetch, triggers.interaction.sourceSpan);
27670      deferOnOps.push(deferOnOp);
27671    }
27672    if (triggers.viewport !== undefined) {
27673      const deferOnOp = createDeferOnOp(deferXref, {
27674        kind: DeferTriggerKind.Viewport,
27675        targetName: triggers.viewport.reference,
27676        targetXref: null,
27677        targetSlot: null,
27678        targetView: null,
27679        targetSlotViewSteps: null
27680      }, prefetch, triggers.viewport.sourceSpan);
27681      deferOnOps.push(deferOnOp);
27682    }
27683    if (triggers.when !== undefined) {
27684      if (triggers.when.value instanceof Interpolation$1) {
27685        // TemplateDefinitionBuilder supports this case, but it's very strange to me. What would it
27686        // even mean?
27687        throw new Error(`Unexpected interpolation in defer block when trigger`);
27688      }
27689      const deferOnOp = createDeferWhenOp(deferXref, convertAst(triggers.when.value, unit.job, triggers.when.sourceSpan), prefetch, triggers.when.sourceSpan);
27690      deferWhenOps.push(deferOnOp);
27691    }
27692    // If no (non-prefetching) defer triggers were provided, default to `idle`.
27693    if (deferOnOps.length === 0 && deferWhenOps.length === 0) {
27694      deferOnOps.push(createDeferOnOp(deferXref, {
27695        kind: DeferTriggerKind.Idle
27696      }, false, null));
27697    }
27698    prefetch = true;
27699  }
27700  unit.create.push(deferOnOps);
27701  unit.update.push(deferWhenOps);
27702}
27703function ingestIcu(unit, icu) {
27704  if (icu.i18n instanceof Message && isSingleI18nIcu(icu.i18n)) {
27705    const xref = unit.job.allocateXrefId();
27706    unit.create.push(createIcuStartOp(xref, icu.i18n, icuFromI18nMessage(icu.i18n).name, null));
27707    for (const [placeholder, text] of Object.entries({
27708      ...icu.vars,
27709      ...icu.placeholders
27710    })) {
27711      if (text instanceof BoundText) {
27712        ingestBoundText(unit, text, placeholder);
27713      } else {
27714        ingestText(unit, text, placeholder);
27715      }
27716    }
27717    unit.create.push(createIcuEndOp(xref));
27718  } else {
27719    throw Error(`Unhandled i18n metadata type for ICU: ${icu.i18n?.constructor.name}`);
27720  }
27721}
27722/**
27723 * Ingest an `@for` block into the given `ViewCompilation`.
27724 */
27725function ingestForBlock(unit, forBlock) {
27726  const repeaterView = unit.job.allocateView(unit.xref);
27727  // Set all the context variables and aliases available in the repeater.
27728  repeaterView.contextVariables.set(forBlock.item.name, forBlock.item.value);
27729  repeaterView.contextVariables.set(forBlock.contextVariables.$index.name, forBlock.contextVariables.$index.value);
27730  repeaterView.contextVariables.set(forBlock.contextVariables.$count.name, forBlock.contextVariables.$count.value);
27731  // We copy TemplateDefinitionBuilder's scheme of creating names for `$count` and `$index` that are
27732  // suffixed with special information, to disambiguate which level of nested loop the below aliases
27733  // refer to.
27734  // TODO: We should refactor Template Pipeline's variable phases to gracefully handle shadowing,
27735  // and arbitrarily many levels of variables depending on each other.
27736  const indexName = `ɵ${forBlock.contextVariables.$index.name}_${repeaterView.xref}`;
27737  const countName = `ɵ${forBlock.contextVariables.$count.name}_${repeaterView.xref}`;
27738  repeaterView.contextVariables.set(indexName, forBlock.contextVariables.$index.value);
27739  repeaterView.contextVariables.set(countName, forBlock.contextVariables.$count.value);
27740  repeaterView.aliases.add({
27741    kind: SemanticVariableKind.Alias,
27742    name: null,
27743    identifier: forBlock.contextVariables.$first.name,
27744    expression: new LexicalReadExpr(indexName).identical(literal(0))
27745  });
27746  repeaterView.aliases.add({
27747    kind: SemanticVariableKind.Alias,
27748    name: null,
27749    identifier: forBlock.contextVariables.$last.name,
27750    expression: new LexicalReadExpr(indexName).identical(new LexicalReadExpr(countName).minus(literal(1)))
27751  });
27752  repeaterView.aliases.add({
27753    kind: SemanticVariableKind.Alias,
27754    name: null,
27755    identifier: forBlock.contextVariables.$even.name,
27756    expression: new LexicalReadExpr(indexName).modulo(literal(2)).identical(literal(0))
27757  });
27758  repeaterView.aliases.add({
27759    kind: SemanticVariableKind.Alias,
27760    name: null,
27761    identifier: forBlock.contextVariables.$odd.name,
27762    expression: new LexicalReadExpr(indexName).modulo(literal(2)).notIdentical(literal(0))
27763  });
27764  const sourceSpan = convertSourceSpan(forBlock.trackBy.span, forBlock.sourceSpan);
27765  const track = convertAst(forBlock.trackBy, unit.job, sourceSpan);
27766  ingestNodes(repeaterView, forBlock.children);
27767  let emptyView = null;
27768  let emptyTagName = null;
27769  if (forBlock.empty !== null) {
27770    emptyView = unit.job.allocateView(unit.xref);
27771    ingestNodes(emptyView, forBlock.empty.children);
27772    emptyTagName = ingestControlFlowInsertionPoint(unit, emptyView.xref, forBlock.empty);
27773  }
27774  const varNames = {
27775    $index: forBlock.contextVariables.$index.name,
27776    $count: forBlock.contextVariables.$count.name,
27777    $first: forBlock.contextVariables.$first.name,
27778    $last: forBlock.contextVariables.$last.name,
27779    $even: forBlock.contextVariables.$even.name,
27780    $odd: forBlock.contextVariables.$odd.name,
27781    $implicit: forBlock.item.name
27782  };
27783  if (forBlock.i18n !== undefined && !(forBlock.i18n instanceof BlockPlaceholder)) {
27784    throw Error('AssertionError: Unhandled i18n metadata type or @for');
27785  }
27786  if (forBlock.empty?.i18n !== undefined && !(forBlock.empty.i18n instanceof BlockPlaceholder)) {
27787    throw Error('AssertionError: Unhandled i18n metadata type or @empty');
27788  }
27789  const i18nPlaceholder = forBlock.i18n;
27790  const emptyI18nPlaceholder = forBlock.empty?.i18n;
27791  const tagName = ingestControlFlowInsertionPoint(unit, repeaterView.xref, forBlock);
27792  const repeaterCreate = createRepeaterCreateOp(repeaterView.xref, emptyView?.xref ?? null, tagName, track, varNames, emptyTagName, i18nPlaceholder, emptyI18nPlaceholder, forBlock.startSourceSpan, forBlock.sourceSpan);
27793  unit.create.push(repeaterCreate);
27794  const expression = convertAst(forBlock.expression, unit.job, convertSourceSpan(forBlock.expression.span, forBlock.sourceSpan));
27795  const repeater = createRepeaterOp(repeaterCreate.xref, repeaterCreate.handle, expression, forBlock.sourceSpan);
27796  unit.update.push(repeater);
27797}
27798/**
27799 * Convert a template AST expression into an output AST expression.
27800 */
27801function convertAst(ast, job, baseSourceSpan) {
27802  if (ast instanceof ASTWithSource) {
27803    return convertAst(ast.ast, job, baseSourceSpan);
27804  } else if (ast instanceof PropertyRead) {
27805    const isThisReceiver = ast.receiver instanceof ThisReceiver;
27806    // Whether this is an implicit receiver, *excluding* explicit reads of `this`.
27807    const isImplicitReceiver = ast.receiver instanceof ImplicitReceiver && !(ast.receiver instanceof ThisReceiver);
27808    // Whether the  name of the read is a node that should be never retain its explicit this
27809    // receiver.
27810    const isSpecialNode = ast.name === '$any' || ast.name === '$event';
27811    // TODO: The most sensible condition here would be simply `isImplicitReceiver`, to convert only
27812    // actual implicit `this` reads, and not explicit ones. However, TemplateDefinitionBuilder (and
27813    // the Typecheck block!) both have the same bug, in which they also consider explicit `this`
27814    // reads to be implicit. This causes problems when the explicit `this` read is inside a
27815    // template with a context that also provides the variable name being read:
27816    // ```
27817    // <ng-template let-a>{{this.a}}</ng-template>
27818    // ```
27819    // The whole point of the explicit `this` was to access the class property, but TDB and the
27820    // current TCB treat the read as implicit, and give you the context property instead!
27821    //
27822    // For now, we emulate this old behvaior by aggressively convert
27822ing explicit reads to to
27823    // implicit reads, except for the special cases that TDB and the current TCB protect. However,
27824    // it would be an improvement to fix this.
27825    //
27826    // See also the corresponding comment for the TCB, in `type_check_block.ts`.
27827    if (isImplicitReceiver || isThisReceiver && !isSpecialNode) {
27828      return new LexicalReadExpr(ast.name);
27829    } else {
27830      return new ReadPropExpr(convertAst(ast.receiver, job, baseSourceSpan), ast.name, null, convertSourceSpan(ast.span, baseSourceSpan));
27831    }
27832  } else if (ast instanceof PropertyWrite) {
27833    if (ast.receiver instanceof ImplicitReceiver) {
27834      return new WritePropExpr(
27835      // TODO: Is it correct to always use the root context in place of the implicit receiver?
27836      new ContextExpr(job.root.xref), ast.name, convertAst(ast.value, job, baseSourceSpan), null, convertSourceSpan(ast.span, baseSourceSpan));
27837    }
27838    return new WritePropExpr(convertAst(ast.receiver, job, baseSourceSpan), ast.name, convertAst(ast.value, job, baseSourceSpan), undefined, convertSourceSpan(ast.span, baseSourceSpan));
27839  } else if (ast instanceof KeyedWrite) {
27840    return new WriteKeyExpr(convertAst(ast.receiver, job, baseSourceSpan), convertAst(ast.key, job, baseSourceSpan), convertAst(ast.value, job, baseSourceSpan), undefined, convertSourceSpan(ast.span, baseSourceSpan));
27841  } else if (ast instanceof Call) {
27842    if (ast.receiver instanceof ImplicitReceiver) {
27843      throw new Error(`Unexpected ImplicitReceiver`);
27844    } else {
27845      return new InvokeFunctionExpr(convertAst(ast.receiver, job, baseSourceSpan), ast.args.map(arg => convertAst(arg, job, baseSourceSpan)), undefined, convertSourceSpan(ast.span, baseSourceSpan));
27846    }
27847  } else if (ast instanceof LiteralPrimitive) {
27848    return literal(ast.value, undefined, convertSourceSpan(ast.span, baseSourceSpan));
27849  } else if (ast instanceof Unary) {
27850    switch (ast.operator) {
27851      case '+':
27852        return new UnaryOperatorExpr(UnaryOperator.Plus, convertAst(ast.expr, job, baseSourceSpan), undefined, convertSourceSpan(ast.span, baseSourceSpan));
27853      case '-':
27854        return new UnaryOperatorExpr(UnaryOperator.Minus, convertAst(ast.expr, job, baseSourceSpan), undefined, convertSourceSpan(ast.span, baseSourceSpan));
27855      default:
27856        throw new Error(`AssertionError: unknown unary operator ${ast.operator}`);
27857    }
27858  } else if (ast instanceof Binary) {
27859    const operator = BINARY_OPERATORS.get(ast.operation);
27860    if (operator === undefined) {
27861      throw new Error(`AssertionError: unknown binary operator ${ast.operation}`);
27862    }
27863    return new BinaryOperatorExpr(operator, convertAst(ast.left, job, baseSourceSpan), convertAst(ast.right, job, baseSourceSpan), undefined, convertSourceSpan(ast.span, baseSourceSpan));
27864  } else if (ast instanceof ThisReceiver) {
27865    // TODO: should context expressions have source maps?
27866    return new ContextExpr(job.root.xref);
27867  } else if (ast instanceof KeyedRead) {
27868    return new ReadKeyExpr(convertAst(ast.receiver, job, baseSourceSpan), convertAst(ast.key, job, baseSourceSpan), undefined, convertSourceSpan(ast.span, baseSourceSpan));
27869  } else if (ast instanceof Chain) {
27870    throw new Error(`AssertionError: Chain in unknown context`);
27871  } else if (ast instanceof LiteralMap) {
27872    const entries = ast.keys.map((key, idx) => {
27873      const value = ast.values[idx];
27874      // TODO: should literals have source maps, or do we just map the whole surrounding
27875      // expression?
27876      return new LiteralMapEntry(key.key, convertAst(value, job, baseSourceSpan), key.quoted);
27877    });
27878    return new LiteralMapExpr(entries, undefined, convertSourceSpan(ast.span, baseSourceSpan));
27879  } else if (ast instanceof LiteralArray) {
27880    // TODO: should literals have source maps, or do we just map the whole surrounding expression?
27881    return new LiteralArrayExpr(ast.expressions.map(expr => convertAst(expr, job, baseSourceSpan)));
27882  } else if (ast instanceof Conditional) {
27883    return new ConditionalExpr(convertAst(ast.condition, job, baseSourceSpan), convertAst(ast.trueExp, job, baseSourceSpan), convertAst(ast.falseExp, job, baseSourceSpan), undefined, c
27883onvertSourceSpan(ast.span, baseSourceSpan));
27884  } else if (ast instanceof NonNullAssert) {
27885    // A non-null assertion shouldn't impact generated instructions, so we can just drop it.
27886    return convertAst(ast.expression, job, baseSourceSpan);
27887  } else if (ast instanceof BindingPipe) {
27888    // TODO: pipes should probably have source maps; figure out details.
27889    return new PipeBindingExpr(job.allocateXrefId(), new SlotHandle(), ast.name, [convertAst(ast.exp, job, baseSourceSpan), ...ast.args.map(arg => convertAst(arg, job, baseSourceSpan))]);
27890  } else if (ast instanceof SafeKeyedRead) {
27891    return new SafeKeyedReadExpr(convertAst(ast.receiver, job, baseSourceSpan), convertAst(ast.key, job, baseSourceSpan), convertSourceSpan(ast.span, baseSourceSpan));
27892  } else if (ast instanceof SafePropertyRead) {
27893    // TODO: source span
27894    return new SafePropertyReadExpr(convertAst(ast.receiver, job, baseSourceSpan), ast.name);
27895  } else if (ast instanceof SafeCall) {
27896    // TODO: source span
27897    return new SafeInvokeFunctionExpr(convertAst(ast.receiver, job, baseSourceSpan), ast.args.map(a => convertAst(a, job, baseSourceSpan)));
27898  } else if (ast instanceof EmptyExpr$1) {
27899    return new EmptyExpr(convertSourceSpan(ast.span, baseSourceSpan));
27900  } else if (ast instanceof PrefixNot) {
27901    return not(convertAst(ast.expression, job, baseSourceSpan), convertSourceSpan(ast.span, baseSourceSpan));
27902  } else {
27903    throw new Error(`Unhandled expression type "${ast.constructor.name}" in file "${baseSourceSpan?.start.file.url}"`);
27904  }
27905}
27906function convertAstWithInterpolation(job, value, i18nMeta, sourceSpan) {
27907  let expression;
27908  if (value instanceof Interpolation$1) {
27909    expression = new Interpolation(value.strings, value.expressions.map(e => convertAst(e, job, sourceSpan ?? null)), Object.keys(asMessage(i18nMeta)?.placeholders ?? {}));
27910  } else if (value instanceof AST) {
27911    expression = convertAst(value, job, sourceSpan ?? null);
27912  } else {
27913    expression = literal(value);
27914  }
27915  return expression;
27916}
27917// TODO: Can we populate Template binding kinds in ingest?
27918const BINDING_KINDS = new Map([[0 /* e.BindingType.Property */, BindingKind.Property], [5 /* e.BindingType.TwoWay */, BindingKind.TwoWayProperty], [1 /* e.BindingType.Attribute */, BindingKind.Attribute], [2 /* e.BindingType.Class */, BindingKind.ClassName], [3 /* e.BindingType.Style */, BindingKind.StyleProperty], [4 /* e.BindingType.Animation */, BindingKind.Animation]]);
27919/**
27920 * Checks whether the given template is a plain ng-template (as opposed to another kind of template
27921 * such as a structural directive template or control flow template). This is checked based on the
27922 * tagName. We can expect that only plain ng-templates will come through with a tagName of
27923 * 'ng-template'.
27924 *
27925 * Here are some of the cases we expect:
27926 *
27927 * | Angular HTML                       | Template tagName   |
27928 * | ---------------------------------- | ------------------ |
27929 * | `<ng-template>`                    | 'ng-template'      |
27930 * | `<div *ngIf="true">`               | 'div'              |
27931 * | `<svg><ng-template>`               | 'svg:ng-template'  |
27932 * | `@if (true) {`                     | 'Conditional'      |
27933 * | `<ng-template *ngIf>` (plain)      | 'ng-template'      |
27934 * | `<ng-template *ngIf>` (structural) | null               |
27935 */
27936function isPlainTemplate(tmpl) {
27937  return splitNsName(tmpl.tagName ?? '')[1] === NG_TEMPLATE_TAG_NAME$1;
27938}
27939/**
27940 * Ensures that the i18nMeta, if provided, is an i18n.Message.
27941 */
27942function asMessage(i18nMeta) {
27943  if (i18nMeta == null) {
27944    return null;
27945  }
27946  if (!(i18nMeta instanceof Message)) {
27947    throw Error(`Expected i18n meta to be a Message, but got: ${i18nMeta.constructor.name}`);
27948  }
27949  return i18nMeta;
27950}
27951/**
27952 * Process all of the bindings on an element in the template AST and convert them to their IR
27953 * representation.
27954 */
27955function ingestElementBindings(unit, op, element) {
27956  let bindings = new Array();
27957  let i18nAttributeBindingNames = new Set();
27958  for (const attr of element.attributes) {
27959    // Attribute literal bindings, such as `attr.foo="bar"`.
27960    const securityContext = domSchema.securityContext(element.name, attr.name, true);
27961    bindings.push(createBindingOp(op.xref, BindingKind.Attribute, attr.name, convertAstWithInterpolation(unit.job, attr.value, attr.i18n), null, securityContext, true, false, null, asMessage(attr.i18n), attr.sourceSpan));
27962    if (attr.i18n) {
27963      i18nAttributeBindingNames.add(attr.name);
27964    }
27965  }
27966  for (const input of element.inputs) {
27967    if (i18nAttributeBindingNames.has(input.name)) {
27968      console.error(`On component ${unit.job.componentName}, the binding ${input.name} is both an i18n attribute and a property. You may want to remove the property binding. This will become a compilation error in future versions of Angular.`);
27969    }
27970    // All dynamic bindings (both attribute and property bindings).
27971    bindings.push(createBindingOp(op.xref, BINDING_KINDS.get(input.type), input.name, convertAstWithInterpolation(unit.job, astOf(input.value), input.i18n), input.unit, input.securityContext, false, false, null, asMessage(input.i18n) ?? null, input.sourceSpan));
27972  }
27973  unit.create.push(bindings.filter(b => b?.kind === OpKind.ExtractedAttribute));
27974  unit.update.push(bindings.filter(b => b?.kind === OpKind.Binding));
27975  for (const output of element.outputs) {
27976    if (output.type === 1 /* e.ParsedEventType.Animation */ && output.phase === null) {
27977      throw Error('Animation listener should have a phase');
27978    }
27979    if (output.type === 2 /* e.ParsedEventType.TwoWay */) {
27980      unit.create.push(createTwoWayListenerOp(op.xref, op.handle, output.name, op.tag, makeTwoWayListenerHandlerOps(unit, output.handler, output.handlerSpan), output.sourceSpan));
27981    } else {
27982      unit.create.push(createListenerOp(op.xref, op.handle, output.name, op.tag, makeListenerHandlerOps(unit, output.handler, output.handlerSpan), output.phase, output.target, false, output.sourceSpan));
27983    }
27984  }
27985  // If any of the bindings on this element have an i18n message, then an i18n attrs configuration
27986  // op is also required.
27987  if (bindings.some(b => b?.i18nMessage) !== null) {
27988    unit.create.push(createI18nAttributesOp(unit.job.allocateXrefId(), new SlotHandle(), op.xref));
27989  }
27990}
27991/**
27992 * Process all of the bindings on a template in the template AST and convert them to their IR
27993 * representation.
27994 */
27995function ingestTemplateBindings(unit, op, template, templateKind) {
27996  let bindings = new Array();
27997  for (const attr of template.templateAttrs) {
27998    if (attr instanceof TextAttribute) {
27999      const securityContext = domSchema.securityContext(NG_TEMPLATE_TAG_NAME$1, attr.name, true);
28000      bindings.push(createTemplateBinding(unit, op.xref, 1 /* e.BindingType.Attribute */, attr.name, attr.value, null, securityContext, true, templateKind, asMessage(attr.i18n), attr.sourceSpan));
28001    } else {
28002      bindings.push(createTemplateBinding(unit, op.xref, attr.type, attr.name, astOf(attr.value), attr.unit, attr.securityContext, true, templateKind, asMessage(attr.i18n), attr.sourceSpan));
28003    }
28004  }
28005  for (const attr of template.attributes) {
28006    // Attribute literal bindings, such as `attr.foo="bar"`.
28007    const securityContext = domSchema.securityContext(NG_TEMPLATE_TAG_NAME$1, attr.name, true);
28008    bindings.push(createTemplateBinding(unit, op.xref, 1 /* e.BindingType.Attribute */, attr.name, attr.value, null, securityContext, false, templateKind, asMessage(attr.i18n), attr.sourceSpan));
28009  }
28010  for (const input of template.inputs) {
28011    // Dynamic bindings (both attribute and property bindings).
28012    bindings.push(createTemplateBinding(unit, op.xref, input.type, input.name, astOf(input.value), input.unit, input.securityContext, false, templateKind, asMessage(input.i18n), input.sourceSpan));
28013  }
28014  unit.create.push(bindings.filter(b => b?.kind === OpKind.ExtractedAttribute));
28015  unit.update.push(bindings.filter(b => b?.kind === OpKind.Binding));
28016  for (const output of template.outputs) {
28017    if (output.type === 1 /* e.ParsedEventType.Animation */ && output.phase === null) {
28018      throw Error('Animation listener should have a phase');
28019    }
28020    if (templateKind === TemplateKind.NgTemplate) {
28021      if (output.type === 2 /* e.ParsedEventType.TwoWay */) {
28022        unit.create.push(createTwoWayListenerOp(op.xref, op.handle, output.name, op.tag, makeTwoWayListenerHandlerOps(unit, output.handler, output.handlerSpan), output.sourceSpan));
28023      } else {
28024        unit.create.push(createListenerOp(op.xref, op.handle, output.name, op.tag, makeListenerHandlerOps(unit, output.handler, output.handlerSpan), output.phase, output.target, false, output.sourceSpan));
28025      }
28026    }
28027    if (templateKind === TemplateKind.Structural && output.type !== 1 /* e.ParsedEventType.Animation */) {
28028      // Animation bindings are excluded from the structural template's const array.
28029      const securityContext = domSchema.securityContext(NG_TEMPLATE_TAG_NAME$1, output.name, false);
28030      unit.create.push(createExtractedAttributeOp(op.xref, BindingKind.Property, null, output.name, null, null, null, securityContext));
28031    }
28032  }
28033  // TODO: Perhaps we could do this in a phase? (It likely wouldn't change the slot indices.)
28034  if (bindings.some(b => b?.i18nMessage) !== null) {
28035    unit.create.push(createI18nAttributesOp(unit.job.allocateXrefId(), new SlotHandle(), op.xref));
28036  }
28037}
28038/**
28039 * Helper to ingest an individual binding on a template, either an explicit `ng-template`, or an
28040 * implicit template created via structural directive.
28041 *
28042 * Bindings on templates are *extremely* tricky. I have tried to isolate all of the confusing edge
28043 * cases into this function, and to comment it well to document the behavior.
28044 *
28045 * Some of this behavior is intuitively incorrect, and we should consider changing it in the future.
28046 *
28047 * @param view The compilation unit for the view containing the template.
28048 * @param xref The xref of the template op.
28049 * @param type The binding type, according to the parser. This is fairly reasonable, e.g. both
28050 *     dynamic and static attributes have e.BindingType.Attribute.
28051 * @param name The binding's name.
28052 * @param value The bindings's value, which will either be an input AST expression, or a string
28053 *     literal. Note that the input AST expression may or may not be const -- it will only be a
28054 *     string literal if the parser considered it a text binding.
28055 * @param unit If the binding has a unit (e.g. `px` for style bindings), then this is the unit.
28056 * @param securityContext The security context of the binding.
28057 * @param isStructuralTemplateAttribute Whether this binding actually applies to the structural
28058 *     ng-template. For example, an `ngFor` would actually apply to the structural template. (Most
28059 *     bindings on structural elements target the inner element, not the template.)
28060 * @param templateKind Whether this is an explicit `ng-template` or an implicit template created by
28061 *     a structural directive. This should never be a block template.
28062 * @param i18nMessage The i18n metadata for the binding, if any.
28063 * @param sourceSpan The source span of the binding.
28064 * @returns An IR binding op, or null if the binding should be skipped.
28065 */
28066function createTemplateBinding(view, xref, type, name, value, unit, securityContext, isStructuralTemplateAttribute, templateKind, i18nMessage, sourceSpan) {
28067  const isTextBinding = typeof value === 'string';
28068  // If this is a structural template, then several kinds of bindings should not result in an
28069  // update instruction.
28070  if (templateKind === TemplateKind.Structural) {
28071    if (!isStructuralTemplateAttribute) {
28072      switch (type) {
28073        case 0 /* e.BindingType.Property */:
28074        case 2 /* e.BindingType.Class */:
28075        case 3 /* e.BindingType.Style */:
28076          // Because this binding doesn't really target the ng-template, it must be a binding on an
28077          // inner node of a structural template. We can't skip it entirely, because we still need
28078          // it on the ng-template's consts (e.g. for the purposes of directive matching). However,
28079          // we should not generate an update instruction for it.
28080          return createExtractedAttributeOp(xref, BindingKind.Property, null, name, null, null, i18nMessage, securityContext);
28081        case 5 /* e.BindingType.TwoWay */:
28082          return createExtractedAttributeOp(xref, BindingKind.TwoWayProperty, null, name, null, null, i18nMessage, securityContext);
28083      }
28084    }
28085    if (!isTextBinding && (type === 1 /* e.BindingType.Attribute */ || type === 4 /* e.BindingType.Animation */)) {
28086      // Again, this binding doesn't really target the ng-template; it actually targets the element
28087      // inside the structural template. In the case of non-text attribute or animation bindings,
28088      // the binding doesn't even show up on the ng-template const array, so we just skip it
28089      // entirely.
28090      return null;
28091    }
28092  }
28093  let bindingType = BINDING_KINDS.get(type);
28094  if (templateKind === TemplateKind.NgTemplate) {
28095    // We know we are dealing with bindings directly on an explicit ng-template.
28096    // Static attribute bindings should be collected into the const array as k/v pairs. Property
28097    // bindings should result in a `property` instruction, and `AttributeMarker.Bindings` const
28098    // entries.
28099    //
28100    // The difficulty is with dynamic attribute, style, and class bindings. These don't really make
28101    // sense on an `ng-template` and should probably be parser errors. However,
28102    // TemplateDefinitionBuilder generates `property` instructions for them, and so we do that as
28103    // well.
28104    //
28105    // Note that we do have a slight behavior difference with TemplateDefinitionBuilder: although
28106    // TDB emits `property` instructions for dynamic attributes, styles, and classes, only styles
28107    // and classes also get const collected into the `AttributeMarker.Bindings` field. Dynamic
28108    // attribute bindings are missing from the consts entirely. We choose to emit them into the
28109    // consts field anyway, to avoid creating special cases for something so arcane and nonsensical.
28110    if (type === 2 /* e.BindingType.Class */ || type === 3 /* e.BindingType.Style */ || type === 1 /* e.BindingType.Attribute */ && !isTextBinding) {
28111      // TODO: These cases should be parse errors.
28112      bindingType = BindingKind.Property;
28113    }
28114  }
28115  return createBindingOp(xref, bindingType, name, convertAstWithInterpolation(view.job, value, i18nMessage), unit, securityContext, isTextBinding, isStru
28115cturalTemplateAttribute, templateKind, i18nMessage, sourceSpan);
28116}
28117function makeListenerHandlerOps(unit, handler, handlerSpan) {
28118  handler = astOf(handler);
28119  const handlerOps = new Array();
28120  let handlerExprs = handler instanceof Chain ? handler.expressions : [handler];
28121  if (handlerExprs.length === 0) {
28122    throw new Error('Expected listener to have non-empty expression list.');
28123  }
28124  const expressions = handlerExprs.map(expr => convertAst(expr, unit.job, handlerSpan));
28125  const returnExpr = expressions.pop();
28126  handlerOps.push(...expressions.map(e => createStatementOp(new ExpressionStatement(e, e.sourceSpan))));
28127  handlerOps.push(createStatementOp(new ReturnStatement(returnExpr, returnExpr.sourceSpan)));
28128  return handlerOps;
28129}
28130function makeTwoWayListenerHandlerOps(unit, handler, handlerSpan) {
28131  handler = astOf(handler);
28132  const handlerOps = new Array();
28133  if (handler instanceof Chain) {
28134    if (handler.expressions.length === 1) {
28135      handler = handler.expressions[0];
28136    } else {
28137      // This is validated during parsing already, but we do it here just in case.
28138      throw new Error('Expected two-way listener to have a single expression.');
28139    }
28140  }
28141  const handlerExpr = convertAst(handler, unit.job, handlerSpan);
28142  const eventReference = new LexicalReadExpr('$event');
28143  const twoWaySetExpr = new TwoWayBindingSetExpr(handlerExpr, eventReference);
28144  handlerOps.push(createStatementOp(new ExpressionStatement(twoWaySetExpr)));
28145  handlerOps.push(createStatementOp(new ReturnStatement(eventReference)));
28146  return handlerOps;
28147}
28148function astOf(ast) {
28149  return ast instanceof ASTWithSource ? ast.ast : ast;
28150}
28151/**
28152 * Process all of the local references on an element-like structure in the template AST and
28153 * convert them to their IR representation.
28154 */
28155function ingestReferences(op, element) {
28156  assertIsArray(op.localRefs);
28157  for (const {
28158    name,
28159    value
28160  } of element.references) {
28161    op.localRefs.push({
28162      name,
28163      target: value
28164    });
28165  }
28166}
28167/**
28168 * Assert that the given value is an array.
28169 */
28170function assertIsArray(value) {
28171  if (!Array.isArray(value)) {
28172    throw new Error(`AssertionError: expected an array`);
28173  }
28174}
28175/**
28176 * Creates an absolute `ParseSourceSpan` from the relative `ParseSpan`.
28177 *
28178 * `ParseSpan` objects are relative to the start of the expression.
28179 * This method converts these to full `ParseSourceSpan` objects that
28180 * show where the span is within the overall source file.
28181 *
28182 * @param span the relative span to convert.
28183 * @param baseSourceSpan a span corresponding to the base of the expression tree.
28184 * @returns a `ParseSourceSpan` for the given span or null if no `baseSourceSpan` was provided.
28185 */
28186function convertSourceSpan(span, baseSourceSpan) {
28187  if (baseSourceSpan === null) {
28188    return null;
28189  }
28190  const start = baseSourceSpan.start.moveBy(span.start);
28191  const end = baseSourceSpan.start.moveBy(span.end);
28192  const fullStart = baseSourceSpan.fullStart.moveBy(span.start);
28193  return new ParseSourceSpan(start, end, fullStart);
28194}
28195/**
28196 * With the directive-based control flow users were able to conditionally project content using
28197 * the `*` syntax. E.g. `<div *ngIf="expr" projectMe></div>` will be projected into
28198 * `<ng-content select="[projectMe]"/>`, because the attributes and tag name from the `div` are
28199 * copied to the template via the template creation instruction. With `@if` and `@for` that is
28200 * not the case, because the conditional is placed *around* elements, rather than *on* them.
28201 * The result is that content projection won't work in the same way if a user converts from
28202 * `*ngIf` to `@if`.
28203 *
28204 * This function aims to cover the most common case by doing the same copying when a control flow
28205 * node has *one and only one* root element or template node.
28206 *
28207 * This approach comes with some caveats:
28208 * 1. As soon as any other node is added to the root, the copying behavior won't work anymore.
28209 *    A diagnostic will be added to flag cases like this and to explain how to work around it.
28210 * 2. If `preserveWhitespaces` is enabled, it's very likely that indentation will break this
28211 *    workaround, because it'll include an additional text node as the first child. We can work
28212 *    around it here, but in a discussion it was decided not to, because the user explicitly opted
28213 *    into preserving the whitespace and we would have to drop it from the generated code.
28214 *    The diagnostic mentioned point #1 will flag such cases to users.
28215 *
28216 * @returns Tag name to be used for the control flow template.
28217 */
28218function ingestControlFlowInsertionPoint(unit, xref, node) {
28219  let root = null;
28220  for (const child of node.children) {
28221    // Skip over comment nodes.
28222    if (child instanceof Comment$1) {
28223      continue;
28224    }
28225    // We can only infer the tag name/attributes if there's a single root node.
28226    if (root !== null) {
28227      return null;
28228    }
28229    // Root nodes can only elements or templates with a tag name (e.g. `<div *foo></div>`).
28230    if (child instanceof Element$1 || child instanceof Template && child.tagName !== null) {
28231      root = child;
28232    }
28233  }
28234  // If we've found a single root node, its tag name and attributes can be
28235  // copied to the surrounding template to be used for content projection.
28236  if (root !== null) {
28237    // Collect the static attributes for content projection purposes.
28238    for (const attr of root.attributes) {
28239      const securityContext = domSchema.securityContext(NG_TEMPLATE_TAG_NAME$1, attr.name, true);
28240      unit.update.push(createBindingOp(xref, BindingKind.Attribute, attr.name, literal(attr.value), null, securityContext, true, false, null, asMessage(attr.i18n), attr.sourceSpan));
28241    }
28242    // Also collect the inputs since they participate in content projection as well.
28243    // Note that TDB used to collect the outputs as well, but it wasn't passing them into
28244    // the template instruction. Here we just don't collect them.
28245    for (const attr of root.inputs) {
28246      if (attr.type !== 4 /* e.BindingType.Animation */ && attr.type !== 1 /* e.BindingType.Attribute */) {
28247        const securityContext = domSchema.securityContext(NG_TEMPLATE_TAG_NAME$1, attr.name, true);
28248        unit.create.push(createExtractedAttributeOp(xref, BindingKind.Property, null, attr.name, null, null, null, securityContext));
28249      }
28250    }
28251    const tagName = root instanceof Element$1 ? root.name : root.tagName;
28252    // Don't pass along `ng-template` tag name since it enables directive matching.
28253    return tagName === NG_TEMPLATE_TAG_NAME$1 ? null : tagName;
28254  }
28255  return null;
28256}
28257const USE_TEMPLATE_PIPELINE = false;
28258class HtmlParser extends Parser {
28259  constructor() {
28260    super(getHtmlTagDefinition);
28261  }
28262  parse(source, url, options) {
28263    return super.parse(source, url, options);
28264  }
28265}
28266const PRESERVE_WS_ATTR_NAME = 'ngPreserveWhitespaces';
28267const SKIP_WS_TRIM_TAGS = new Set(['pre', 'template', 'textarea', 'script', 'style']);
28268// Equivalent to \s with \u00a0 (non-breaking space) excluded.
28269// Based on https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp
28270const WS_CHARS = ' \f\n\r\t\v\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff';
28271const NO_WS_REGEXP = new RegExp(`[^${WS_CHARS}]`);
28272const WS_REPLACE_REGEXP = new RegExp(`[${WS_CHARS}]{2,}`, 'g');
28273function hasPreserveWhitespacesAttr(attrs) {
28274  return attrs.some(attr => attr.name === PRESERVE_WS_ATTR_NAME);
28275}
28276/**
28277 * &ngsp; is a placeholder for non-removable space
28278 * &ngsp; is converted to the 0xE500 PUA (Private Use Areas) unicode character
28279 * and later on replaced by a space.
28280 */
28281function replaceNgsp(value) {
28282  // lexer is replacing the &ngsp; pseudo-entity with NGSP_UNICODE
28283  return value.replace(new RegExp(NGSP_UNICODE, 'g'), ' ');
28284}
28285/**
28286 * This visitor can walk HTML parse tree and remove / trim text nodes using the following rules:
28287 * - consider spaces, tabs and new lines as whitespace characters;
28288 * - drop text nodes consisting of whitespace characters only;
28289 * - for all other text nodes replace consecutive whitespace characters with one space;
28290 * - convert &ngsp; pseudo-entity to a single space;
28291 *
28292 * Removal and trimming of whitespaces have positive performance impact (less code to generate
28293 * while compiling templates, faster view creation). At the same time it can be "destructive"
28294 * in some cases (whitespaces can influence layout). Because of the potential of breaking layout
28295 * this visitor is not activated by default in Angular 5 and people need to explicitly opt-in for
28296 * whitespace removal. The default option for whitespace removal will be revisited in Angular 6
28297 * and might be changed to "on" by default.
28298 */
28299class WhitespaceVisitor {
28300  visitElement(element, context) {
28301    if (SKIP_WS_TRIM_TAGS.has(element.name) || hasPreserveWhitespacesAttr(element.attrs)) {
28302      // don't descent into elements where we need to preserve whitespaces
28303      // but still visit all attributes to eliminate one used as a market to preserve WS
28304      return new Element(element.name, visitAll(this, element.attrs), element.children, element.sourceSpan, element.startSourceSpan, element.endSourceSpan, element.i18n);
28305    }
28306    return new Element(element.name, element.attrs, visitAllWithSiblings(this, element.children), element.sourceSpan, element.startSourceSpan, element.endSourceSpan, element.i18n);
28307  }
28308  visitAttribute(attribute, context) {
28309    return attribute.name !== PRESERVE_WS_ATTR_NAME ? attribute : null;
28310  }
28311  visitText(text, context) {
28312    const isNotBlank = text.value.match(NO_WS_REGEXP);
28313    const hasExpansionSibling = context && (context.prev instanceof Expansion || context.next instanceof Expansion);
28314    if (isNotBlank || hasExpansionSibling) {
28315      // Process the whitespace in the tokens of this Text node
28316      const tokens = text.tokens.map(token => token.type === 5 /* TokenType.TEXT */ ? createWhitespaceProcessedTextToken(token) : token);
28317      // Process the whitespace of the value of this Text node
28318      const value = processWhitespace(text.value);
28319      return new Text(value, text.sourceSpan, tokens, text.i18n);
28320    }
28321    return null;
28322  }
28323  visitComment(comment, context) {
28324    return comment;
28325  }
28326  visitExpansion(expansion, context) {
28327    return expansion;
28328  }
28329  visitExpansionCase(expansionCase, context) {
28330    return expansionCase;
28331  }
28332  visitBlock(block, context) {
28333    return new Block(block.name, block.parameters, visitAllWithSiblings(this, block.children), block.sourceSpan, block.nameSpan, block.startSourceSpan, block.endSourceSpan);
28334  }
28335  visitBlockParameter(parameter, context) {
28336    return parameter;
28337  }
28338}
28339function createWhitespaceProcessedTextToken({
28340  type,
28341  parts,
28342  sourceSpan
28343}) {
28344  return {
28345    type,
28346    parts: [processWhitespace(parts[0])],
28347    sourceSpan
28348  };
28349}
28350function processWhitespace(text) {
28351  return replaceNgsp(text).replace(WS_REPLACE_REGEXP, ' ');
28352}
28353function removeWhitespaces(htmlAstWithErrors) {
28354  return new ParseTreeResult(visitAll(new WhitespaceVisitor(), htmlAstWithErrors.rootNodes), htmlAstWithErrors.errors);
28355}
28356function visitAllWithSiblings(visitor, nodes) {
28357  const result = [];
28358  nodes.forEach((ast, i) => {
28359    const context = {
28360      prev: nodes[i - 1],
28361      next: nodes[i + 1]
28362    };
28363    const astResult = ast.visit(visitor, context);
28364    if (astResult) {
28365      result.push(astResult);
28366    }
28367  });
28368  return result;
28369}
28370const PROPERTY_PARTS_SEPARATOR = '.';
28371const ATTRIBUTE_PREFIX = 'attr';
28372const CLASS_PREFIX = 'class';
28373const STYLE_PREFIX = 'style';
28374const TEMPLATE_ATTR_PREFIX$1 = '*';
28375const ANIMATE_PROP_PREFIX = 'animate-';
28376/**
28377 * Parses bindings in templates and in the directive host area.
28378 */
28379class BindingParser {
28380  constructor(_exprParser, _interpolationConfig, _schemaRegistry, errors) {
28381    this._exprParser = _exprParser;
28382    this._interpolationConfig = _interpolationConfig;
28383    this._schemaRegistry = _schemaRegistry;
28384    this.errors = errors;
28385  }
28386  get interpolationConfig() {
28387    return this._interpolationConfig;
28388  }
28389  createBoundHostProperties(properties, sourceSpan) {
28390    const boundProps = [];
28391    for (const propName of Object.keys(properties)) {
28392      const expression = properties[propName];
28393      if (typeof expression === 'string') {
28394        this.parsePropertyBinding(propName, expression, true, false, sourceSpan, sourceSpan.start.offset, undefined, [],
28395        // Use the `sourceSpan` for  `keySpan`. This isn't really accurate, but neither is the
28396        // sourceSpan, as it represents the sourceSpan of the host itself rather than the
28397        // source of the host binding (which doesn't exist in the template). Regardless,
28398        // neither of these values are used in Ivy but are only here to satisfy the function
28399        // signature. This should likely be refactored in the future so that `sourceSpan`
28400        // isn't being used inaccurately.
28401        boundProps, sourceSpan);
28402      } else {
28403        this._reportError(`Value of the host property binding "${propName}" needs to be a string representing an expression but got "${expression}" (${typeof expression})`, sourceSpan);
28404      }
28405    }
28406    return boundProps;
28407  }
28408  createDirectiveHostEventAsts(hostListeners, sourceSpan) {
28409    const targetEvents = [];
28410    for (const propName of Object.keys(hostListeners)) {
28411      const expression = hostListeners[propName];
28412      if (typeof expression === 'string') {
28413        // Use the `sourceSpan` for  `keySpan` and `handlerSpan`. This isn't really accurate, but
28414        // neither is the `sourceSpan`, as it represents the `sourceSpan` of the host itself
28415        // rather than the source of the host binding (which doesn't exist in the template).
28416        // Regardless, neither of these values are used in Ivy but are only here to satisfy the
28417        // function signature. This should likely be refactored in the future so that `sourceSpan`
28418        // isn't being used inaccurately.
28419        this.parseEvent(propName, expression, /* isAssignmentEvent */false, sourceSpan, sourceSpan, [], targetEvents, sourceSpan);
28420      } else {
28421        this._reportError(`Value of the host listener "${propName}" needs to be a string representing an expression but got "${expression}" (${typeof expression})`, sourceSpan);
28422      }
28423    }
28424    return targetEvents;
28425  }
28426  parseInterpolation(value, sourceSpan, interpolatedTokens) {
28427    const sourceInfo = sourceSpan.start.toString();
28428    const absoluteOffset = sourceSpan.fullStart.offset;
28429    try {
28430      const ast = this._exprParser.parseInterpolation(value, sourceInfo, absoluteOffset, interpolatedTokens, this._interpolationConfig);
28431      if (ast) this._reportExpressionParserErrors(ast.errors, sourceSpan);
28432      return ast;
28433    } catch (e) {
28434      this._reportError(`${e}`, sourceSpan);
28435      return this._exprParser.wrapLiteralPrimitive('ERROR', sourceInfo, absoluteOffset);
28436    }
28437  }
28438  /**
28439   * Similar to `parseInterpolation`, but treats the provided string as a single expression
28440   * element that would normally appear within the interpolation prefix and suffix (`{{` and `}}`).
28441   * This is used for parsing the switch expression in ICUs.
28442   */
28443  parseInterpolationExpression(expression, sourceSpan) {
28444    const sourceInfo = sourceSpan.start.toString();
28445    const absoluteOffset = sourceSpan.start.offset;
28446    try {
28447      const ast = this._exprParser.parseInterpolationExpression(expression, sourceInfo, absoluteOffset);
28448      if (ast) this._reportExpressionParserErrors(ast.errors, sourceSpan);
28449      return ast;
28450    } catch (e) {
28451      this._reportError(`${e}`, sourceSpan);
28452      return this._exprParser.wrapLiteralPrimitive('ERROR', sourceInfo, absoluteOffset);
28453    }
28454  }
28455  /**
28456   * Parses the bindings in a microsyntax expression, and converts them to
28457   * `ParsedProperty` or `ParsedVariable`.
28458   *
28459   * @param tplKey template binding name
28460   * @param tplValue template binding value
28461   * @param sourceSpan span of template binding relative to entire the template
28462   * @param absoluteValueOffset start of the tplValue relative to the entire template
28463   * @param targetMatchableAttrs potential attributes to match in the template
28464   * @param targetProps target property bindings in the template
28465   * @param targetVars target variables in the template
28466   */
28467  parseInlineTemplateBinding(tplKey, tplValue, sourceSpan, absoluteValueOffset, targetMatchableAttrs, targetProps, targetVars, isIvyAst) {
28468    const absoluteKeyOffset = sourceSpan.start.offset + TEMPLATE_ATTR_PREFIX$1.length;
28469    const bindings = this._parseTemplateBindings(tplKey, tplValue, sourceSpan, absoluteKeyOffset, absoluteValueOffset);
28470    for (const binding of bindings) {
28471      // sourceSpan is for the entire HTML attribute. bindingSpan is for a particular
28472      // binding within the microsyntax expression so it's more narrow than sourceSpan.
28473      const bindingSpan = moveParseSourceSpan(sourceSpan, binding.sourceSpan);
28474      const key = binding.key.source;
28475      const keySpan = moveParseSourceSpan(sourceSpan, binding.key.span);
28476      if (binding instanceof VariableBinding) {
28477        const value = binding.value ? binding.value.source : '$implicit';
28478        const valueSpan = binding.value ? moveParseSourceSpan(sourceSpan, binding.value.span) : undefined;
28479        targetVars.push(new ParsedVariable(key, value, bindingSpan, keySpan, valueSpan));
28480      } else if (binding.value) {
28481        const srcSpan = isIvyAst ? bindingSpan : sourceSpan;
28482        const valueSpan = moveParseSourceSpan(sourceSpan, binding.value.ast.sourceSpan);
28483        this._parsePropertyAst(key, binding.value, false, srcSpan, keySpan, valueSpan, targetMatchableAttrs, targetProps);
28484      } else {
28485        targetMatchableAttrs.push([key, '' /* value */]);
28486        // Since this is a literal attribute with no RHS, source span should be
28487        // just the key span.
28488        this.parseLiteralAttr(key, null /* value */, keySpan, absoluteValueOffset, undefined /* valueSpan */, targetMatchableAttrs, targetProps, keySpan);
28489      }
28490    }
28491  }
28492  /**
28493   * Parses the bindings in a microsyntax expression, e.g.
28494   * ```
28495   *    <tag *tplKey="let value1 = prop; let value2 = localVar">
28496   * ```
28497   *
28498   * @param tplKey template binding name
28499   * @param tplValue template binding value
28500   * @param sourceSpan span of template binding relative to entire the template
28501   * @param absoluteKeyOffset start of the `tplKey`
28502   * @param absoluteValueOffset start of the `tplValue`
28503   */
28504  _parseTemplateBindings(tplKey, tplValue, sourceSpan, absoluteKeyOffset, absoluteValueOffset) {
28505    const sourceInfo = sourceSpan.start.toString();
28506    try {
28507      const bindingsResult = this._exprParser.parseTemplateBindings(tplKey, tplValue, sourceInfo, absoluteKeyOffset, absoluteValueOffset);
28508      this._reportExpressionParserErrors(bindingsResult.errors, sourceSpan);
28509      bindingsResult.warnings.forEach(warning => {
28510        this._reportError(warning, sourceSpan, ParseErrorLevel.WARNING);
28511      });
28512      return bindingsResult.templateBindings;
28513    } catch (e) {
28514      this._reportError(`${e}`, sourceSpan);
28515      return [];
28516    }
28517  }
28518  parseLiteralAttr(name, value, sourceSpan, absoluteOffset, valueSpan, targetMatchableAttrs, targetProps, keySpan) {
28519    if (isAnimationLabel(name)) {
28520      name = name.substring(1);
28521      if (keySpan !== undefined) {
28522        keySpan = moveParseSourceSpan(keySpan, new AbsoluteSourceSpan(keySpan.start.offset + 1, keySpan.end.offset));
28523      }
28524      if (value) {
28525        this._reportError(`Assigning animation triggers via @prop="exp" attributes with an expression is invalid.` + ` Use property bindings (e.g. [@prop]="exp") or use an attribute without a value (e.g. @prop) instead.`, sourceSpan, ParseErrorLevel.ERROR);
28526      }
28527      this._parseAnimation(name, value, sourceSpan, absoluteOffset, keySpan, valueSpan, targetMatchableAttrs, targetProps);
28528    } else {
28529      targetProps.push(new ParsedProperty(name, this._exprParser.wrapLiteralPrimitive(value, '', absoluteOffset), ParsedPropertyType.LITERAL_ATTR, sourceSpan, keySpan, valueSpan));
28530    }
28531  }
28532  parsePropertyBinding(name, expression, isHost, isPartOfAssignmentBinding, sourceSpan, absoluteOffset, valueSpan, targetMatchableAttrs, targetProps, keySpan) {
28533    if (name.length === 0) {
28534      this._reportError(`Property name is missing in binding`, sourceSpan);
28535    }
28536    let isAnimationProp = false;
28537    if (name.startsWith(ANIMATE_PROP_PREFIX)) {
28538      isAnimationProp = true;
28539      name = name.substring(ANIMATE_PROP_PREFIX.length);
28540      if (keySpan !== undefined) {
28541        keySpan = moveParseSourceSpan(keySpan, new AbsoluteSourceSpan(keySpan.start.offset + ANIMATE_PROP_PREFIX.length, keySpan.end.offset));
28542      }
28543    } else if (isAnimationLabel(name)) {
28544      isAnimationProp = true;
28545      name = name.substring(1);
28546      if (keySpan !== undefined) {
28547        keySpan = moveParseSourceSpan(keySpan, new AbsoluteSourceSpan(keySpan.start.offset + 1, keySpan.end.offset));
28548      }
28549    }
28550    if (isAnimationProp) {
28551      this._parseAnimation(name, expression, sourceSpan, absoluteOffset, keySpan, valueSpan, targetMatchableAttrs, targetProps);
28552    } else {
28553      this._parsePropertyAst(name, this.parseBinding(expression, isHost, valueSpan || sourceSpan, absoluteOffset), isPartOfAssignmentBinding, sourceSpan, keySpan, valueSpan, targetMatchableAttrs, targetProps);
28554    }
28555  }
28556  parsePropertyInterpolation(name, value, sourceSpan, valueSpan, targetMatchableAttrs, targetProps, keySpan, interpolatedTokens) {
28557    const expr = this.parseInterpolation(value, valueSpan || sourceSpan, interpolatedTokens);
28558    if (expr) {
28559      this._parsePropertyAst(name, expr, false, sourceSpan, keySpan, valueSpan, targetMatchableAttrs, targetProps);
28560      return true;
28561    }
28562    return false;
28563  }
28564  _parsePropertyAst(name, ast, isPartOfAssignmentBinding, sourceSpan, keySpan, valueSpan, targetMatchableAttrs, targetProps) {
28565    targetMatchableAttrs.push([name, ast.source]);
28566    targetProps.push(new ParsedProperty(name, ast, isPartOfAssignmentBinding ? ParsedPropertyType.TWO_WAY : ParsedPropertyType.DEFAULT, sourceSpan, keySpan, valueSpan));
28567  }
28568  _parseAnimation(name, expression, sourceSpan, absoluteOffset, keySpan, valueSpan, targetMatchableAttrs, targetProps) {
28569    if (name.length === 0) {
28570      this._reportError('Animation trigger is missing', sourceSpan);
28571    }
28572    // This will occur when a @trigger is not paired with an expression.
28573    // For animations it is valid to not have an expression since */void
28574    // states will be applied by angular when the element is attached/detached
28575    const ast = this.parseBinding(expression || 'undefined', false, valueSpan || sourceSpan, absoluteOffset);
28576    targetMatchableAttrs.push([name, ast.source]);
28577    targetProps.push(new ParsedProperty(name, ast, ParsedPropertyType.ANIMATION, sourceSpan, keySpan, valueSpan));
28578  }
28579  parseBinding(value, isHostBinding, sourceSpan, absoluteOffset) {
28580    const sourceInfo = (sourceSpan && sourceSpan.start || '(unknown)').toString();
28581    try {
28582      const ast = isHostBinding ? this._exprParser.parseSimpleBinding(value, sourceInfo, absoluteOffset, this._interpolationConfig) : this._exprParser.parseBinding(value, sourceInfo, absoluteOffset, this._interpolationConfig);
28583      if (ast) this._reportExpressionParserErrors(ast.errors, sourceSpan);
28584      return ast;
28585    } catch (e) {
28586      this._reportError(`${e}`, sourceSpan);
28587      return this._exprParser.wrapLiteralPrimitive('ERROR', sourceInfo, absoluteOffset);
28588    }
28589  }
28590  createBoundElementProperty(elementSelector, boundProp, skipValidation = false, mapPropertyName = true) {
28591    if (boundProp.isAnimation) {
28592      return new BoundElementProperty(boundProp.name, 4 /* BindingType.Animation */, SecurityContext.NONE, boundProp.expression, null, boundProp.sourceSpan, boundProp.keySpan, boundProp.valueSpan);
28593    }
28594    let unit = null;
28595    let bindingType = undefined;
28596    let boundPropertyName = null;
28597    const parts = boundProp.name.split(PROPERTY_PARTS_SEPARATOR);
28598    let securityContexts = undefined;
28599    // Check for special cases (prefix style, attr, class)
28600    if (parts.length > 1) {
28601      if (parts[0] == ATTRIBUTE_PREFIX) {
28602        boundPropertyName = parts.slice(1).join(PROPERTY_PARTS_SEPARATOR);
28603        if (!skipValidation) {
28604          this._validatePropertyOrAttributeName(boundPropertyName, boundProp.sourceSpan, true);
28605        }
28606        securityContexts = calcPossibleSecurityContexts(this._schemaRegistry, elementSelector, boundPropertyName, true);
28607        const nsSeparatorIdx = boundPropertyName.indexOf(':');
28608        if (nsSeparatorIdx > -1) {
28609          const ns = boundPropertyName.substring(0, nsSeparatorIdx);
28610          const name = boundPropertyName.substring(nsSeparatorIdx + 1);
28611          boundPropertyName = mergeNsAndName(ns, name);
28612        }
28613        bindingType = 1 /* BindingType.Attribute */;
28614      } else if (parts[0] == CLASS_PREFIX) {
28615        boundPropertyName = parts[1];
28616        bindingType = 2 /* BindingType.Class */;
28617        securityContexts = [SecurityContext.NONE];
28618      } else if (parts[0] == STYLE_PREFIX) {
28619        unit = parts.length > 2 ? parts[2] : null;
28620        boundPropertyName = parts[1];
28621        bindingType = 3 /* BindingType.Style */;
28622        securityContexts = [SecurityContext.STYLE];
28623      }
28624    }
28625    // If not a special case, use the full property name
28626    if (boundPropertyName === null) {
28627      const mappedPropName = this._schemaRegistry.getMappedPropName(boundProp.name);
28628      boundPropertyName = mapPropertyName ? mappedPropName : boundProp.name;
28629      securityContexts = calcPossibleSecurityContexts(this._schemaRegistry, elementSelector, mappedPropName, false);
28630      bindingType = boundProp.type === ParsedPropertyType.TWO_WAY ? 5 /* BindingType.TwoWay */ : 0 /* BindingType.Property */;
28631      if (!skipValidation) {
28632        this._validatePropertyOrAttributeName(mappedPropName, boundProp.sourceSpan, false);
28633      }
28634    }
28635    return new BoundElementProperty(boundPropertyName, bindingType, securityContexts[0], boundProp.expression, unit, boundProp.sourceSpan, boundProp.keySpan, boundProp.valueSpan);
28636  }
28637  // TODO: keySpan should be required but was made optional to avoid changing VE parser.
28638  parseEvent(name, expression, isAssignmentEvent, sourceSpan, handlerSpan, targetMatchableAttrs, targetEvents, keySpan) {
28639    if (name.length === 0) {
28640      this._reportError(`Event name is missing in binding`, sourceSpan);
28641    }
28642    if (isAnimationLabel(name)) {
28643      name = name.slice(1);
28644      if (keySpan !== undefined) {
28645        keySpan = moveParseSourceSpan(keySpan, new AbsoluteSourceSpan(keySpan.start.offset + 1, keySpan.end.offset));
28646      }
28647      this._parseAnimationEvent(name, expression, sourceSpan, handlerSpan, targetEvents, keySpan);
28648    } else {
28649      this._parseRegularEvent(name, expression, isAssignmentEvent, sourceSpan, handlerSpan, targetMatchableAttrs, targetEvents, keySpan);
28650    }
28651  }
28652  calcPossibleSecurityContexts(selector, propName, isAttribute) {
28653    const prop = this._schemaRegistry.getMappedPropName(propName);
28654    return calcPossibleSecurityContexts(this._schemaRegistry, selector, prop, isAttribute);
28655  }
28656  _parseAnimationEvent(name, expression, sourceSpan, handlerSpan, targetEvents, keySpan) {
28657    const matches = splitAtPeriod(name, [name, '']);
28658    const eventName = matches[0];
28659    const phase = matches[1].toLowerCase();
28660    const ast = this._parseAction(expression, handlerSpan);
28661    targetEvents.push(new ParsedEvent(eventName, phase, 1 /* ParsedEventType.Animation */, ast, sourceSpan, handlerSpan, keySpan));
28662    if (eventName.length === 0) {
28663      this._reportError(`Animation event name is missing in binding`, sourceSpan);
28664    }
28665    if (phase) {
28666      if (phase !== 'start' && phase !== 'done') {
28667        this._reportError(`The provided animation output phase value "${phase}" for "@${eventName}" is not supported (use start or done)`, sourceSpan);
28668      }
28669    } else {
28670      this._reportError(`The animation trigger output event (@${eventName}) is missing its phase value name (start or done are currently supported)`, sourceSpan);
28671    }
28672  }
28673  _parseRegularEvent(name, expression, isAssignmentEvent, sourceSpan, handlerSpan, targetMatchableAttrs, targetEvents, keySpan) {
28674    // long format: 'target: eventName'
28675    const [target, eventName] = splitAtColon(name, [null, name]);
28676    const prevErrorCount = this.errors.length;
28677    const ast = this._parseAction(expression, handlerSpan);
28678    const isValid = this.errors.length === prevErrorCount;
28679    targetMatchableAttrs.push([name, ast.source]);
28680    // Don't try to validate assignment events if there were other
28681    // parsing errors to avoid adding more noise to the error logs.
28682    if (isAssignmentEvent && isValid && !this._isAllowedAssignmentEvent(ast)) {
28683      this._reportError('Unsupported expression in a two-way binding', sourceSpan);
28684    }
28685    targetEvents.push(new ParsedEvent(eventName, target, isAssignmentEvent ? 2 /* ParsedEventType.TwoWay */ : 0 /* ParsedEventType.Regular */, ast, sourceSpan, handlerSpan, keySpan));
28686    // Don't detect directives for event names for now,
28687    // so don't add the event name to the matchableAttrs
28688  }
28689  _parseAction(value, sourceSpan) {
28690    const sourceInfo = (sourceSpan && sourceSpan.start || '(unknown').toString();
28691    const absoluteOffset = sourceSpan && sourceSpan.start ? sourceSpan.start.offset : 0;
28692    try {
28693      const ast = this._exprParser.parseAction(value, sourceInfo, absoluteOffset, this._interpolationConfig);
28694      if (ast) {
28695        this._reportExpressionParserErrors(ast.errors, sourceSpan);
28696      }
28697      if (!ast || ast.ast instanceof EmptyExpr$1) {
28698        this._reportError(`Empty expressions are not allowed`, sourceSpan);
28699        return this._exprParser.wrapLiteralPrimitive('ERROR', sourceInfo, absoluteOffset);
28700      }
28701      return ast;
28702    } catch (e) {
28703      this._reportError(`${e}`, sourceSpan);
28704      return this._exprParser.wrapLiteralPrimitive('ERROR', sourceInfo, absoluteOffset);
28705    }
28706  }
28707  _reportError(message, sourceSpan, level = ParseErrorLevel.ERROR) {
28708    this.errors.push(new ParseError(sourceSpan, message, level));
28709  }
28710  _reportExpressionParserErrors(errors, sourceSpan) {
28711    for (const error of errors) {
28712      this._reportError(error.message, sourceSpan);
28713    }
28714  }
28715  /**
28716   * @param propName the name of the property / attribute
28717   * @param sourceSpan
28718   * @param isAttr true when binding to an attribute
28719   */
28720  _validatePropertyOrAttributeName(propName, sourceSpan, isAttr) {
28721    const report = isAttr ? this._schemaRegistry.validateAttribute(propName) : this._schemaRegistry.validateProperty(propName);
28722    if (report.error) {
28723      this._reportError(report.msg, sourceSpan, ParseErrorLevel.ERROR);
28724    }
28725  }
28726  /**
28727   * Returns whether a parsed AST is allowed to be used within the event side of a two-way binding.
28728   * @param ast Parsed AST to be checked.
28729   */
28730  _isAllowedAssignmentEvent(ast) {
28731    if (ast instanceof ASTWithSource) {
28732      return this._isAllowedAssignmentEvent(ast.ast);
28733    }
28734    if (ast instanceof NonNullAssert) {
28735      return this._isAllowedAssignmentEvent(ast.expression);
28736    }
28737    if (ast instanceof PropertyRead || ast instanceof KeyedRead) {
28738      return true;
28739    }
28740    if (ast instanceof Binary) {
28741      return (ast.operation === '&&' || ast.operation === '||' || ast.operation === '??') && (ast.right instanceof PropertyRead || ast.right instanceof KeyedRead);
28742    }
28743    return ast instanceof Conditional || ast instanceof PrefixNot;
28744  }
28745}
28746class PipeCollector extends RecursiveAstVisitor {
28747  constructor() {
28748    super(...arguments);
28749    this.pipes = new Map();
28750  }
28751  visitPipe(ast, context) {
28752    this.pipes.set(ast.name, ast);
28753    ast.exp.visit(this);
28754    this.visitAll(ast.args, context);
28755    return null;
28756  }
28757}
28758function isAnimationLabel(name) {
28759  return name[0] == '@';
28760}
28761function calcPossibleSecurityContexts(registry, selector, propName, isAttribute) {
28762  const ctxs = [];
28763  CssSelector.parse(selector).forEach(selector => {
28764    const elementNames = selector.element ? [selector.element] : registry.allKnownElementNames();
28765    const notElementNames = new Set(selector.notSelectors.filter(selector => selector.isElementSelector()).map(selector => selector.element));
28766    const possibleElementNames = elementNames.filter(elementName => !notElementNames.has(elementName));
28767    ctxs.push(...possibleElementNames.map(elementName => registry.securityContext(elementName, propName, isAttribute)));
28768  });
28769  return ctxs.length === 0 ? [SecurityContext.NONE] : Array.from(new Set(ctxs)).sort();
28770}
28771/**
28772 * Compute a new ParseSourceSpan based off an original `sourceSpan` by using
28773 * absolute offsets from the specified `absoluteSpan`.
28774 *
28775 * @param sourceSpan original source span
28776 * @param absoluteSpan absolute source span to move to
28777 */
28778function moveParseSourceSpan(sourceSpan, absoluteSpan) {
28779  // The difference of two absolute offsets provide the relative offset
28780  const startDiff = absoluteSpan.start - sourceSpan.start.offset;
28781  const endDiff = absoluteSpan.end - sourceSpan.end.offset;
28782  return new ParseSourceSpan(sourceSpan.start.moveBy(startDiff), sourceSpan.end.moveBy(endDiff), sourceSpan.fullStart.moveBy(startDiff), sourceSpan.details);
28783}
28784
28785// Some of the code comes from WebComponents.JS
28786// https://github.com/webcomponents/webcomponentsjs/blob/master/src/HTMLImports/path.js
28787function isStyleUrlResolvable(url) {
28788  if (url == null || url.length === 0 || url[0] == '/') return false;
28789  const schemeMatch = url.match(URL_WITH_SCHEMA_REGEXP);
28790  return schemeMatch === null || schemeMatch[1] == 'package' || schemeMatch[1] == 'asset';
28791}
28792const URL_WITH_SCHEMA_REGEXP = /^([^:/?#]+):/;
28793const NG_CONTENT_SELECT_ATTR$1 = 'select';
28794const LINK_ELEMENT = 'link';
28795const LINK_STYLE_REL_ATTR = 'rel';
28796const LINK_STYLE_HREF_ATTR = 'href';
28797const LINK_STYLE_REL_VALUE = 'stylesheet';
28798const STYLE_ELEMENT = 'style';
28799const SCRIPT_ELEMENT = 'script';
28800const NG_NON_BINDABLE_ATTR = 'ngNonBindable';
28801const NG_PROJECT_AS = 'ngProjectAs';
28802function preparseElement(ast) {
28803  let selectAttr = null;
28804  let hrefAttr = null;
28805  let relAttr = null;
28806  let nonBindable = false;
28807  let projectAs = '';
28808  ast.attrs.forEach(attr => {
28809    const lcAttrName = attr.name.toLowerCase();
28810    if (lcAttrName == NG_CONTENT_SELECT_ATTR$1) {
28811      selectAttr = attr.value;
28812    } else if (lcAttrName == LINK_STYLE_HREF_ATTR) {
28813      hrefAttr = attr.value;
28814    } else if (lcAttrName == LINK_STYLE_REL_ATTR) {
28815      relAttr = attr.value;
28816    } else if (attr.name == NG_NON_BINDABLE_ATTR) {
28817      nonBindable = true;
28818    } else if (attr.name == NG_PROJECT_AS) {
28819      if (attr.value.length > 0) {
28820        projectAs = attr.value;
28821      }
28822    }
28823  });
28824  selectAttr = normalizeNgContentSelect(selectAttr);
28825  const nodeName = ast.name.toLowerCase();
28826  let type = PreparsedElementType.OTHER;
28827  if (isNgContent(nodeName)) {
28828    type = PreparsedElementType.NG_CONTENT;
28829  } else if (nodeName == STYLE_ELEMENT) {
28830    type = PreparsedElementType.STYLE;
28831  } else if (nodeName == SCRIPT_ELEMENT) {
28832    type = PreparsedElementType.SCRIPT;
28833  } else if (nodeName == LINK_ELEMENT && relAttr == LINK_STYLE_REL_VALUE) {
28834    type = PreparsedElementType.STYLESHEET;
28835  }
28836  return new PreparsedElement(type, selectAttr, hrefAttr, nonBindable, projectAs);
28837}
28838var PreparsedElementType;
28839(function (PreparsedElementType) {
28840  PreparsedElementType[PreparsedElementType["NG_CONTENT"] = 0] = "NG_CONTENT";
28841  PreparsedElementType[PreparsedElementType["STYLE"] = 1] = "STYLE";
28842  PreparsedElementType[PreparsedElementType["STYLESHEET"] = 2] = "STYLESHEET";
28843  PreparsedElementType[PreparsedElementType["SCRIPT"] = 3] = "SCRIPT";
28844  PreparsedElementType[PreparsedElementType["OTHER"] = 4] = "OTHER";
28845})(PreparsedElementType || (PreparsedElementType = {}));
28846class PreparsedElement {
28847  constructor(type, selectAttr, hrefAttr, nonBindable, projectAs) {
28848    this.type = type;
28849    this.selectAttr = selectAttr;
28850    this.hrefAttr = hrefAttr;
28851    this.nonBindable = nonBindable;
28852    this.projectAs = projectAs;
28853  }
28854}
28855function normalizeNgContentSelect(selectAttr) {
28856  if (selectAttr === null || selectAttr.length === 0) {
28857    return '*';
28858  }
28859  return selectAttr;
28860}
28861
28862/** Pattern for the expression in a for loop block. */
28863const FOR_LOOP_EXPRESSION_PATTERN = /^\s*([0-9A-Za-z_$]*)\s+of\s+([\S\s]*)/;
28864/** Pattern for the tracking expression in a for loop block. */
28865const FOR_LOOP_TRACK_PATTERN = /^track\s+([\S\s]*)/;
28866/** Pattern for the `as` expression in a conditional block. */
28867const CONDITIONAL_ALIAS_PATTERN = /^(as\s)+(.*)/;
28868/** Pattern used to identify an `else if` block. */
28869const ELSE_IF_PATTERN = /^else[^\S\r\n]+if/;
28870/** Pattern used to identify a `let` parameter. */
28871const FOR_LOOP_LET_PATTERN = /^let\s+([\S\s]*)/;
28872/**
28873 * Pattern to group a string into leading whitespace, non whitespace, and trailing whitespace.
28874 * Useful for getting the variable name span when a span can contain leading and trailing space.
28875 */
28876const CHARACTERS_IN_SURROUNDING_WHITESPACE_PATTERN = /(\s*)(\S+)(\s*)/;
28877/** Names of variables that are allowed to be used in the `let` expression of a `for` loop. */
28878const ALLOWED_FOR_LOOP_LET_VARIABLES = new Set(['$index', '$first', '$last', '$even', '$odd', '$count']);
28879/**
28880 * Predicate function that determines if a block with
28881 * a specific name cam be connected to a `for` block.
28882 */
28883function isConnectedForLoopBlock(name) {
28884  return name === 'empty';
28885}
28886/**
28887 * Predicate function that determines if a block with
28888 * a specific name cam be connected to an `if` block.
28889 */
28890function isConnectedIfLoopBlock(name) {
28891  return name === 'else' || ELSE_IF_PATTERN.test(name);
28892}
28893/** Creates an `if` loop block from an HTML AST node. */
28894function createIfBlock(ast, connectedBlocks, visitor, bindingParser) {
28895  const errors = validateIfConnectedBlocks(connectedBlocks);
28896  const branches = [];
28897  const mainBlockParams = parseConditionalBlockParameters(ast, errors, bindingParser);
28898  if (mainBlockParams !== null) {
28899    branches.push(new IfBlockBranch(mainBlockParams.expression, visitAll(visitor, ast.children, ast.children), mainBlockParams.expressionAlias, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan, ast.nameSpan, ast.i18n));
28900  }
28901  for (const block of connectedBlocks) {
28902    if (ELSE_IF_PATTERN.test(block.name)) {
28903      const params = parseConditionalBlockParameters(block, errors, bindingParser);
28904      if (params !== null) {
28905        const children = visitAll(visitor, block.children, block.children);
28906        branches.push(new IfBlockBranch(params.expression, children, params.expressionAlias, block.sourceSpan, block.startSourceSpan, block.endSourceSpan, block.nameSpan, block.i18n));
28907      }
28908    } else if (block.name === 'else') {
28909      const children = visitAll(visitor, block.children, block.children);
28910      branches.push(new IfBlockBranch(null, children, null, block.sourceSpan, block.startSourceSpan, block.endSourceSpan, block.nameSpan, block.i18n));
28911    }
28912  }
28913  // The outer IfBlock should have a span that encapsulates all branches.
28914  const ifBlockStartSourceSpan = branches.length > 0 ? branches[0].startSourceSpan : ast.startSourceSpan;
28915  const ifBlockEndSourceSpan = branches.length > 0 ? branches[branches.length - 1].endSourceSpan : ast.endSourceSpan;
28916  let wholeSourceSpan = ast.sourceSpan;
28917  const lastBranch = branches[branches.length - 1];
28918  if (lastBranch !== undefined) {
28919    wholeSourceSpan = new ParseSourceSpan(ifBlockStartSourceSpan.start, lastBranch.sourceSpan.end);
28920  }
28921  return {
28922    node: new IfBlock(branches, wholeSourceSpan, ast.startSourceSpan, ifBlockEndSourceSpan, ast.nameSpan),
28923    errors
28924  };
28925}
28926/** Creates a `for` loop block from an HTML AST node. */
28927function createForLoop(ast, connectedBlocks, visitor, bindingParser) {
28928  const errors = [];
28929  const params = parseForLoopParameters(ast, errors, bindingParser);
28930  let node = null;
28931  let empty = null;
28932  for (const block of connectedBlocks) {
28933    if (block.name === 'empty') {
28934      if (empty !== null) {
28935        errors.push(new ParseError(block.sourceSpan, '@for loop can only have one @empty block'));
28936      } else if (block.parameters.length > 0) {
28937        errors.push(new ParseError(block.sourceSpan, '@empty block cannot have parameters'));
28938      } else {
28939        empty = new ForLoopBlockEmpty(visitAll(visitor, block.children, block.children), block.sourceSpan, block.startSourceSpan, block.endSourceSpan, block.nameSpan, block.i18n);
28940      }
28941    } else {
28942      errors.push(new ParseError(block.sourceSpan, `Unrecognized @for loop block "${block.name}"`));
28943    }
28944  }
28945  if (params !== null) {
28946    if (params.trackBy === null) {
28947      // TODO: We should not fail here, and instead try to produce some AST for the language
28948      // service.
28949      errors.push(new ParseError(ast.sourceSpan, '@for loop must have a "track" expression'));
28950    } else {
28951      // The `for` block has a main span that includes the `empty` branch. For only the span of the
28952      // main `for` body, use `mainSourceSpan`.
28953      const endSpan = empty?.endSourceSpan ?? ast.endSourceSpan;
28954      const sourceSpan = new ParseSourceSpan(ast.sourceSpan.start, endSpan?.end ?? ast.sourceSpan.end);
28955      node = new ForLoopBlock(params.itemName, params.expression, params.trackBy.expression, params.trackBy.keywordSpan, params.context, visitAll(visitor, ast.children, ast.children), empty, sourceSpan, ast.sourceSpan, ast.startSourceSpan, endSpan, ast.nameSpan, ast.i18n);
28956    }
28957  }
28958  return {
28959    node,
28960    errors
28961  };
28962}
28963/** Creates a switch block from an HTML AST node. */
28964function createSwitchBlock(ast, visitor, bindingParser) {
28965  const errors = validateSwitchBlock(ast);
28966  const primaryExpression = ast.parameters.length > 0 ? parseBlockParameterToBinding(ast.parameters[0], bindingParser) : bindingParser.parseBinding('', false, ast.sourceSpan, 0);
28967  const cases = [];
28968  const unknownBlocks = [];
28969  let defaultCase = null;
28970  // Here we assume that all the blocks are valid given that we validated them above.
28971  for (const node of ast.children) {
28972    if (!(node instanceof Block)) {
28973      continue;
28974    }
28975    if ((node.name !== 'case' || node.parameters.length === 0) && node.name !== 'default') {
28976      unknownBlocks.push(new UnknownBlock(node.name, node.sourceSpan, node.nameSpan));
28977      continue;
28978    }
28979    const expression = node.name === 'case' ? parseBlockParameterToBinding(node.parameters[0], bindingParser) : null;
28980    const ast = new SwitchBlockCase(expression, visitAll(visitor, node.children, node.children), node.sourceSpan, node.startSourceSpan, node.endSourceSpan, node.nameSpan, node.i18n);
28981    if (expression === null) {
28982      defaultCase = ast;
28983    } else {
28984      cases.push(ast);
28985    }
28986  }
28987  // Ensure that the default case is last in the array.
28988  if (defaultCase !== null) {
28989    cases.push(defaultCase);
28990  }
28991  return {
28992    node: new SwitchBlock(primaryExpression, cases, unknownBlocks, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan, ast.nameSpan),
28993    errors
28994  };
28995}
28996/** Parses the parameters of a `for` loop block. */
28997function parseForLoopParameters(block, errors, bindingParser) {
28998  if (block.parameters.length === 0) {
28999    errors.push(new ParseError(block.sourceSpan, '@for loop does not have an expression'));
29000    return null;
29001  }
29002  const [expressionParam, ...secondaryParams] = block.parameters;
29003  const match = stripOptionalParentheses(expressionParam, errors)?.match(FOR_LOOP_EXPRESSION_PATTERN);
29004  if (!match || match[2].trim().length === 0) {
29005    errors.push(new ParseError(expressionParam.sourceSpan, 'Cannot parse expression. @for loop expression must match the pattern "<identifier> of <expression>"'));
29006    return null;
29007  }
29008  const [, itemName, rawExpression] = match;
29009  // `expressionParam.expression` contains the variable declaration and the expression of the
29010  // for...of statement, i.e. 'user of users' The variable of a ForOfStatement is _only_ the "const
29011  // user" part and does not include "of x".
29012  const variableName = expressionParam.expression.split(' ')[0];
29013  const variableSpan = new ParseSourceSpan(expressionParam.sourceSpan.start, expressionParam.sourceSpan.start.moveBy(variableName.length));
29014  const result = {
29015    itemName: new Variable(itemName, '$implicit', variableSpan, variableSpan),
29016    trackBy: null,
29017    expression: parseBlockParameterToBinding(expressionParam, bindingParser, rawExpression),
29018    context: {}
29019  };
29020  for (const param of secondaryParams) {
29021    const letMatch = param.expression.match(FOR_LOOP_LET_PATTERN);
29022    if (letMatch !== null) {
29023      const variablesSpan = new ParseSourceSpan(param.sourceSpan.start.moveBy(letMatch[0].length - letMatch[1].length), param.sourceSpan.end);
29024      parseLetParameter(param.sourceSpan, letMatch[1], variablesSpan, result.context, errors);
29025      continue;
29026    }
29027    const trackMatch = param.expression.match(FOR_LOOP_TRACK_PATTERN);
29028    if (trackMatch !== null) {
29029      if (result.trackBy !== null) {
29030        errors.push(new ParseError(param.sourceSpan, '@for loop can only have one "track" expression'));
29031      } else {
29032        const expression = parseBlockParameterToBinding(param, bindingParser, trackMatch[1]);
29033        if (expression.ast instanceof EmptyExpr$1) {
29034          errors.push(new ParseError(param.sourceSpan, '@for loop must have a "track" expression'));
29035        }
29036        const keywordSpan = new ParseSourceSpan(param.sourceSpan.start, param.sourceSpan.start.moveBy('track'.length));
29037        result.trackBy = {
29038          expression,
29039          keywordSpan
29040        };
29041      }
29042      continue;
29043    }
29044    errors.push(new ParseError(param.sourceSpan, `Unrecognized @for loop paramater "${param.expression}"`));
29045  }
29046  // Fill out any variables that haven't been defined explicitly.
29047  for (const variableName of ALLOWED_FOR_LOOP_LET_VARIABLES) {
29048    if (!result.context.hasOwnProperty(variableName)) {
29049      // Give ambiently-available context variables empty spans at the end of the start of the `for`
29050      // block, since they are not explicitly defined.
29051      const emptySpanAfterForBlockStart = new ParseSourceSpan(block.startSourceSpan.end, block.startSourceSpan.end);
29052      result.context[variableName] = new Variable(variableName, variableName, emptySpanAfterForBlockStart, emptySpanAfterForBlockStart);
29053    }
29054  }
29055  return result;
29056}
29057/** Parses the `let` parameter of a `for` loop block. */
29058function parseLetParameter(sourceSpan, expression, span, context, errors) {
29059  const parts = expression.split(',');
29060  let startSpan = span.start;
29061  for (const part of parts) {
29062    const expressionParts = part.split('=');
29063    const name = expressionParts.length === 2 ? expressionParts[0].trim() : '';
29064    const variableName = expressionParts.length === 2 ? expressionParts[1].trim() : '';
29065    if (name.length === 0 || variableName.length === 0) {
29066      errors.push(new ParseError(sourceSpan, `Invalid @for loop "let" parameter. Parameter should match the pattern "<name> = <variable name>"`));
29067    } else if (!ALLOWED_FOR_LOOP_LET_VARIABLES.has(variableName)) {
29068      errors.push(new ParseError(sourceSpan, `Unknown "let" parameter variable "${variableName}". The allowed variables are: ${Array.from(ALLOWED_FOR_LOOP_LET_VARIABLES).join(', ')}`));
29069    } else if (context.hasOwnProperty(variableName)) {
29070      errors.push(new ParseError(sourceSpan, `Duplicate "let" parameter variable "${variableName}"`));
29071    } else {
29072      const [, keyLeadingWhitespace, keyName] = expressionParts[0].match(CHARACTERS_IN_SURROUNDING_WHITESPACE_PATTERN) ?? [];
29073      const keySpan = keyLeadingWhitespace !== undefined && expressionParts.length === 2 ? new ParseSourceSpan( /* strip leading spaces */
29074      startSpan.moveBy(keyLeadingWhitespace.length), /* advance to end of the variable name */
29075      startSpan.moveBy(keyLeadingWhitespace.length + keyName.length)) : span;
29076      let valueSpan = undefined;
29077      if (expressionParts.length === 2) {
29078        const [, valueLeadingWhitespace, implicit] = expressionParts[1].match(CHARACTERS_IN_SURROUNDING_WHITESPACE_PATTERN) ?? [];
29079        valueSpan = valueLeadingWhitespace !== undefined ? new ParseSourceSpan(startSpan.moveBy(expressionParts[0].length + 1 + valueLeadingWhitespace.length), startSpan.moveBy(expressionParts[0].length + 1 + valueLeadingWhitespace.length + implicit.length)) : undefined;
29080      }
29081      const sourceSpan = new ParseSourceSpan(keySpan.start, valueSpan?.end ?? keySpan.end);
29082      context[variableName] = new Variable(name, variableName, sourceSpan, keySpan, valueSpan);
29083    }
29084    startSpan = startSpan.moveBy(part.length + 1 /* add 1 to move past the comma */);
29085  }
29086}
29087/**
29088 * Checks that the shape of the blocks connected to an
29089 * `@if` block is correct. Returns an array of errors.
29090 */
29091function validateIfConnectedBlocks(connectedBlocks) {
29092  const errors = [];
29093  let hasElse = false;
29094  for (let i = 0; i < connectedBlocks.length; i++) {
29095    const block = connectedBlocks[i];
29096    if (block.name === 'else') {
29097      if (hasElse) {
29098        errors.push(new ParseError(block.sourceSpan, 'Conditional can only have one @else block'));
29099      } else if (connectedBlocks.length > 1 && i < connectedBlocks.length - 1) {
29100        errors.push(new ParseError(block.sourceSpan, '@else block must be last inside the conditional'));
29101      } else if (block.parameters.length > 0) {
29102        errors.push(new ParseError(block.sourceSpan, '@else block cannot have parameters'));
29103      }
29104      hasElse = true;
29105    } else if (!ELSE_IF_PATTERN.test(block.name)) {
29106      errors.push(new ParseError(block.sourceSpan, `Unrecognized conditional block @${block.name}`));
29107    }
29108  }
29109  return errors;
29110}
29111/** Checks that the shape of a `switch` block is valid. Returns an array of errors. */
29112function validateSwitchBlock(ast) {
29113  const errors = [];
29114  let hasDefault = false;
29115  if (ast.parameters.length !== 1) {
29116    errors.push(new ParseError(ast.sourceSpan, '@switch block must have exactly one parameter'));
29117    return errors;
29118  }
29119  for (const node of ast.children) {
29120    // Skip over comments and empty text nodes inside the switch block.
29121    // Empty text nodes can be used for formatting while comments don't affect the runtime.
29122    if (node instanceof Comment || node instanceof Text && node.value.trim().length === 0) {
29123      continue;
29124    }
29125    if (!(node instanceof Block) || node.name !== 'case' && node.name !== 'default') {
29126      errors.push(new ParseError(node.sourceSpan, '@switch block can only contain @case and @default blocks'));
29127      continue;
29128    }
29129    if (node.name === 'default') {
29130      if (hasDefault) {
29131        errors.push(new ParseError(node.sourceSpan, '@switch block can only have one @default block'));
29132      } else if (node.parameters.length > 0) {
29133        errors.push(new ParseError(node.sourceSpan, '@default block cannot have parameters'));
29134      }
29135      hasDefault = true;
29136    } else if (node.name === 'case' && node.parameters.length !== 1) {
29137      errors.push(new ParseError(node.sourceSpan, '@case block must have exactly one parameter'));
29138    }
29139  }
29140  return errors;
29141}
29142/**
29143 * Parses a block parameter into a binding AST.
29144 * @param ast Block parameter that should be parsed.
29145 * @param bindingParser Parser that the expression should be parsed with.
29146 * @param part Specific part of the expression that should be parsed.
29147 */
29148function parseBlockParameterToBinding(ast, bindingParser, part) {
29149  let start;
29150  let end;
29151  if (typeof part === 'string') {
29152    // Note: `lastIndexOf` here should be enough to know the start index of the expression,
29153    // because we know that it'll be at the end of the param. Ideally we could use the `d`
29154    // flag when matching via regex and get the index from `match.indices`, but it's unclear
29155    // if we can use it yet since it's a relatively new feature. See:
29156    // https://github.com/tc39/proposal-regexp-match-indices
29157    start = Math.max(0, ast.expression.lastIndexOf(part));
29158    end = start + part.length;
29159  } else {
29160    start = 0;
29161    end = ast.expression.length;
29162  }
29163  return bindingParser.parseBinding(ast.expression.slice(start, end), false, ast.sourceSpan, ast.sourceSpan.start.offset + start);
29164}
29165/** Parses the parameter of a conditional block (`if` or `else if`). */
29166function parseConditionalBlockParameters(block, errors, bindingParser) {
29167  if (block.parameters.length === 0) {
29168    errors.push(new ParseError(block.sourceSpan, 'Conditional block does not have an expression'));
29169    return null;
29170  }
29171  const expression = parseBlockParameterToBinding(block.parameters[0], bindingParser);
29172  let expressionAlias = null;
29173  // Start from 1 since we processed the first parameter already.
29174  for (let i = 1; i < block.parameters.length; i++) {
29175    const param = block.parameters[i];
29176    const aliasMatch = param.expression.match(CONDITIONAL_ALIAS_PATTERN);
29177    // For now conditionals can only have an `as` parameter.
29178    // We may want to rework this later if we add more.
29179    if (aliasMatch === null) {
29180      errors.push(new ParseError(param.sourceSpan, `Unrecognized conditional paramater "${param.expression}"`));
29181    } else if (block.name !== 'if') {
29182      errors.push(new ParseError(param.sourceSpan, '"as" expression is only allowed on the primary @if block'));
29183    } else if (expressionAlias !== null) {
29184      errors.push(new ParseError(param.sourceSpan, 'Conditional can only have one "as" expression'));
29185    } else {
29186      const name = aliasMatch[2].trim();
29187      const variableStart = param.sourceSpan.start.moveBy(aliasMatch[1].length);
29188      const variableSpan = new ParseSourceSpan(variableStart, variableStart.moveBy(name.length));
29189      expressionAlias = new Variable(name, name, variableSpan, variableSpan);
29190    }
29191  }
29192  return {
29193    expression,
29194    expressionAlias
29195  };
29196}
29197/** Strips optional parentheses around from a control from expression parameter. */
29198function stripOptionalParentheses(param, errors) {
29199  const expression = param.expression;
29200  const spaceRegex = /^\s$/;
29201  let openParens = 0;
29202  let start = 0;
29203  let end = expression.length - 1;
29204  for (let i = 0; i < expression.length; i++) {
29205    const char = expression[i];
29206    if (char === '(') {
29207      start = i + 1;
29208      openParens++;
29209    }
29209 else if (spaceRegex.test(char)) {
29210      continue;
29211    } else {
29212      break;
29213    }
29214  }
29215  if (openParens === 0) {
29216    return expression;
29217  }
29218  for (let i = expression.length - 1; i > -1; i--) {
29219    const char = expression[i];
29220    if (char === ')') {
29221      end = i;
29222      openParens--;
29223      if (openParens === 0) {
29224        break;
29225      }
29226    } else if (spaceRegex.test(char)) {
29227      continue;
29228    } else {
29229      break;
29230    }
29231  }
29232  if (openParens !== 0) {
29233    errors.push(new ParseError(param.sourceSpan, 'Unclosed parentheses in expression'));
29234    return null;
29235  }
29236  return expression.slice(start, end);
29237}
29238
29239/** Pattern for a timing value in a trigger. */
29240const TIME_PATTERN = /^\d+\.?\d*(ms|s)?$/;
29241/** Pattern for a separator between keywords in a trigger expression. */
29242const SEPARATOR_PATTERN = /^\s$/;
29243/** Pairs of characters that form syntax that is comma-delimited. */
29244const COMMA_DELIMITED_SYNTAX = new Map([[$LBRACE, $RBRACE],
29245// Object literals
29246[$LBRACKET, $RBRACKET],
29247// Array literals
29248[$LPAREN, $RPAREN] // Function calls
29249]);
29250/** Possible types of `on` triggers. */
29251var OnTriggerType;
29252(function (OnTriggerType) {
29253  OnTriggerType["IDLE"] = "idle";
29254  OnTriggerType["TIMER"] = "timer";
29255  OnTriggerType["INTERACTION"] = "interaction";
29256  OnTriggerType["IMMEDIATE"] = "immediate";
29257  OnTriggerType["HOVER"] = "hover";
29258  OnTriggerType["VIEWPORT"] = "viewport";
29259})(OnTriggerType || (OnTriggerType = {}));
29260/** Parses a `when` deferred trigger. */
29261function parseWhenTrigger({
29262  expression,
29263  sourceSpan
29264}, bindingParser, triggers, errors) {
29265  const whenIndex = expression.indexOf('when');
29266  const whenSourceSpan = new ParseSourceSpan(sourceSpan.start.moveBy(whenIndex), sourceSpan.start.moveBy(whenIndex + 'when'.length));
29267  const prefetchSpan = getPrefetchSpan(expression, sourceSpan);
29268  // This is here just to be safe, we shouldn't enter this function
29269  // in the first place if a block doesn't have the "when" keyword.
29270  if (whenIndex === -1) {
29271    errors.push(new ParseError(sourceSpan, `Could not find "when" keyword in expression`));
29272  } else {
29273    const start = getTriggerParametersStart(expression, whenIndex + 1);
29274    const parsed = bindingParser.parseBinding(expression.slice(start), false, sourceSpan, sourceSpan.start.offset + start);
29275    trackTrigger('when', triggers, errors, new BoundDeferredTrigger(parsed, sourceSpan, prefetchSpan, whenSourceSpan));
29276  }
29277}
29278/** Parses an `on` trigger */
29279function parseOnTrigger({
29280  expression,
29281  sourceSpan
29282}, triggers, errors, placeholder) {
29283  const onIndex = expression.indexOf('on');
29284  const onSourceSpan = new ParseSourceSpan(sourceSpan.start.moveBy(onIndex), sourceSpan.start.moveBy(onIndex + 'on'.length));
29285  const prefetchSpan = getPrefetchSpan(expression, sourceSpan);
29286  // This is here just to be safe, we shouldn't enter this function
29287  // in the first place if a block doesn't have the "on" keyword.
29288  if (onIndex === -1) {
29289    errors.push(new ParseError(sourceSpan, `Could not find "on" keyword in expression`));
29290  } else {
29291    const start = getTriggerParametersStart(expression, onIndex + 1);
29292    const parser = new OnTriggerParser(expression, start, sourceSpan, triggers, errors, placeholder, prefetchSpan, onSourceSpan);
29293    parser.parse();
29294  }
29295}
29296function getPrefetchSpan(expression, sourceSpan) {
29297  if (!expression.startsWith('prefetch')) {
29298    return null;
29299  }
29300  return new ParseSourceSpan(sourceSpan.start, sourceSpan.start.moveBy('prefetch'.length));
29301}
29302class OnTriggerParser {
29303  constructor(expression, start, span, triggers, errors, placeholder, prefetchSpan, onSourceSpan) {
29304    this.expression = expression;
29305    this.start = start;
29306    this.span = span;
29307    this.triggers = triggers;
29308    this.errors = errors;
29309    this.placeholder = placeholder;
29310    this.prefetchSpan = prefetchSpan;
29311    this.onSourceSpan = onSourceSpan;
29312    this.index = 0;
29313    this.tokens = new Lexer().tokenize(expression.slice(start));
29314  }
29315  parse() {
29316    while (this.tokens.length > 0 && this.index < this.tokens.length) {
29317      const token = this.token();
29318      if (!token.isIdentifier()) {
29319        this.unexpectedToken(token);
29320        break;
29321      }
29322      // An identifier immediately followed by a comma or the end of
29323      // the expression cannot have parameters so we can exit early.
29324      if (this.isFollowedByOrLast($COMMA)) {
29325        this.consumeTrigger(token, []);
29326        this.advance();
29327      } else if (this.isFollowedByOrLast($LPAREN)) {
29328        this.advance(); // Advance to the opening paren.
29329        const prevErrors = this.errors.length;
29330        const parameters = this.consumeParameters();
29331        if (this.errors.length !== prevErrors) {
29332          break;
29333        }
29334        this.consumeTrigger(token, parameters);
29335        this.advance(); // Advance past the closing paren.
29336      } else if (this.index < this.tokens.length - 1) {
29337        this.unexpectedToken(this.tokens[this.index + 1]);
29338      }
29339      this.advance();
29340    }
29341  }
29342  advance() {
29343    this.index++;
29344  }
29345  isFollowedByOrLast(char) {
29346    if (this.index === this.tokens.length - 1) {
29347      return true;
29348    }
29349    return this.tokens[this.index + 1].isCharacter(char);
29350  }
29351  token() {
29352    return this.tokens[Math.min(this.index, this.tokens.length - 1)];
29353  }
29354  consumeTrigger(identifier, parameters) {
29355    const triggerNameStartSpan = this.span.start.moveBy(this.start + identifier.index - this.tokens[0].index);
29356    const nameSpan = new ParseSourceSpan(triggerNameStartSpan, triggerNameStartSpan.moveBy(identifier.strValue.length));
29357    const endSpan = triggerNameStartSpan.moveBy(this.token().end - identifier.index);
29358    // Put the prefetch and on spans with the first trigger
29359    // This should maybe be refactored to have something like an outer OnGroup AST
29360    // Since triggers can be grouped with commas "on hover(x), interaction(y)"
29361    const isFirstTrigger = identifier.index === 0;
29362    const onSourceSpan = isFirstTrigger ? this.onSourceSpan : null;
29363    const prefetchSourceSpan = isFirstTrigger ? this.prefetchSpan : null;
29364    const sourceSpan = new ParseSourceSpan(isFirstTrigger ? this.span.start : triggerNameStartSpan, endSpan);
29365    try {
29366      switch (identifier.toString()) {
29367        case OnTriggerType.IDLE:
29368          this.trackTrigger('idle', createIdleTrigger(parameters, nameSpan, sourceSpan, prefetchSourceSpan, onSourceSpan));
29369          break;
29370        case OnTriggerType.TIMER:
29371          this.trackTrigger('timer', createTimerTrigger(parameters, nameSpan, sourceSpan, this.prefetchSpan, this.onSourceSpan));
29372          break;
29373        case OnTriggerType.INTERACTION:
29374          this.trackTrigger('interaction', createInteractionTrigger(parameters, nameSpan, sourceSpan, this.prefetchSpan, this.onSourceSpan, this.placeholder));
29375          break;
29376        case OnTriggerType.IMMEDIATE:
29377          this.trackTrigger('immediate', createImmediateTrigger(parameters, nameSpan, sourceSpan, this.prefetchSpan, this.onSourceSpan));
29378          break;
29379        case OnTriggerType.HOVER:
29380          this.trackTrigger('hover', createHoverTrigger(parameters, nameSpan, sourceSpan, this.prefetchSpan, this.onSourceSpan, this.placeholder));
29381          break;
29382        case OnTriggerType.VIEWPORT:
29383          this.trackTrigger('viewport', createViewportTrigger(parameters, nameSpan, sourceSpan, this.prefetchSpan, this.onSourceSpan, this.placeholder));
29384          break;
29385        default:
29386          throw new Error(`Unrecognized trigger type "${identifier}"`);
29387      }
29388    } catch (e) {
29389      this.error(identifier, e.message);
29390    }
29391  }
29392  consumeParameters() {
29393    const parameters = [];
29394    if (!this.token().isCharacter($LPAREN)) {
29395      this.unexpectedToken(this.token());
29396      return parameters;
29397    }
29398    this.advance();
29399    const commaDelimStack = [];
29400    let current = '';
29401    while (this.index < this.tokens.length) {
29402      const token = this.token();
29403      // Stop parsing if we've hit the end character and we're outside of a comma-delimited syntax.
29404      // Note that we don't need to account for strings here since the lexer already parsed them
29405      // into string tokens.
29406      if (token.isCharacter($RPAREN) && commaDelimStack.length === 0) {
29407        if (current.length) {
29408          parameters.push(current);
29409        }
29410        break;
29411      }
29412      // In the `on` microsyntax "top-level" commas (e.g. ones outside of an parameters) separate
29413      // the different triggers (e.g. `on idle,timer(500)`). This is problematic, because the
29414      // function-like syntax also implies that multiple parameters can be passed into the
29415      // individual trigger (e.g. `on foo(a, b)`). To avoid tripping up the parser with commas that
29416      // are part of other sorts of syntax (object literals, arrays), we treat anything inside
29417      // a comma-delimited syntax block as plain text.
29418      if (token.type === TokenType.Character && COMMA_DELIMITED_SYNTAX.has(token.numValue)) {
29419        commaDelimStack.push(COMMA_DELIMITED_SYNTAX.get(token.numValue));
29420      }
29421      if (commaDelimStack.length > 0 && token.isCharacter(commaDelimStack[commaDelimStack.length - 1])) {
29422        commaDelimStack.pop();
29423      }
29424      // If we hit a comma outside of a comma-delimited syntax, it means
29425      // that we're at the top level and we're starting a new parameter.
29426      if (commaDelimStack.length === 0 && token.isCharacter($COMMA) && current.length > 0) {
29427        parameters.push(current);
29428        current = '';
29429        this.advance();
29430        continue;
29431      }
29432      // Otherwise treat the token as a plain text character in the current parameter.
29433      current += this.tokenText();
29434      this.advance();
29435    }
29436    if (!this.token().isCharacter($RPAREN) || commaDelimStack.length > 0) {
29437      this.error(this.token(), 'Unexpected end of expression');
29438    }
29439    if (this.index < this.tokens.length - 1 && !this.tokens[this.index + 1].isCharacter($COMMA)) {
29440      this.unexpectedToken(this.tokens[this.index + 1]);
29441    }
29442    return parameters;
29443  }
29444  tokenText() {
29445    // Tokens have a toString already which we could use, but for string tokens it omits the quotes.
29446    // Eventually we could expose this information on the token directly.
29447    return this.expression.slice(this.start + this.token().index, this.start + this.token().end);
29448  }
29449  trackTrigger(name, trigger) {
29450    trackTrigger(name, this.triggers, this.errors, trigger);
29451  }
29452  error(token, message) {
29453    const newStart = this.span.start.moveBy(this.start + token.index);
29454    const newEnd = newStart.moveBy(token.end - token.index);
29455    this.errors.push(new ParseError(new ParseSourceSpan(newStart, newEnd), message));
29456  }
29457  unexpectedToken(token) {
29458    this.error(token, `Unexpected token "${token}"`);
29459  }
29460}
29461/** Adds a trigger to a map of triggers. */
29462function trackTrigger(name, allTriggers, errors, trigger) {
29463  if (allTriggers[name]) {
29464    errors.push(new ParseError(trigger.sourceSpan, `Duplicate "${name}" trigger is not allowed`));
29465  } else {
29466    allTriggers[name] = trigger;
29467  }
29468}
29469function createIdleTrigger(parameters, nameSpan, sourceSpan, prefetchSpan, onSourceSpan) {
29470  if (parameters.length > 0) {
29471    throw new Error(`"${OnTriggerType.IDLE}" trigger cannot have parameters`);
29472  }
29473  return new IdleDeferredTrigger(nameSpan, sourceSpan, prefetchSpan, onSourceSpan);
29474}
29475function createTimerTrigger(parameters, nameSpan, sourceSpan, prefetchSpan, onSourceSpan) {
29476  if (parameters.length !== 1) {
29477    throw new Error(`"${OnTriggerType.TIMER}" trigger must have exactly one parameter`);
29478  }
29479  const delay = parseDeferredTime(parameters[0]);
29480  if (delay === null) {
29481    throw new Error(`Could not parse time value of trigger "${OnTriggerType.TIMER}"`);
29482  }
29483  return new TimerDeferredTrigger(delay, nameSpan, sourceSpan, prefetchSpan, onSourceSpan);
29484}
29485function createImmediateTrigger(parameters, nameSpan, sourceSpan, prefetchSpan, onSourceSpan) {
29486  if (parameters.length > 0) {
29487    throw new Error(`"${OnTriggerType.IMMEDIATE}" trigger cannot have parameters`);
29488  }
29489  return new ImmediateDeferredTrigger(nameSpan, sourceSpan, prefetchSpan, onSourceSpan);
29490}
29491function createHoverTrigger(parameters, nameSpan, sourceSpan, prefetchSpan, onSourceSpan, placeholder) {
29492  validateReferenceBasedTrigger(OnTriggerType.HOVER, parameters, placeholder);
29493  return new HoverDeferredTrigger(parameters[0] ?? null, nameSpan, sourceSpan, prefetchSpan, onSourceSpan);
29494}
29495function createInteractionTrigger(parameters, nameSpan, sourceSpan, prefetchSpan, onSourceSpan, placeholder) {
29496  validateReferenceBasedTrigger(OnTriggerType.INTERACTION, parameters, placeholder);
29497  return new InteractionDeferredTrigger(parameters[0] ?? null, nameSpan, sourceSpan, prefetchSpan, onSourceSpan);
29498}
29499function createViewportTrigger(parameters, nameSpan, sourceSpan, prefetchSpan, onSourceSpan, placeholder) {
29500  validateReferenceBasedTrigger(OnTriggerType.VIEWPORT, parameters, placeholder);
29501  return new ViewportDeferredTrigger(parameters[0] ?? null, nameSpan, sourceSpan, prefetchSpan, onSourceSpan);
29502}
29503function validateReferenceBasedTrigger(type, parameters, placeholder) {
29504  if (parameters.length > 1) {
29505    throw new Error(`"${type}" trigger can only have zero or one parameters`);
29506  }
29507  if (parameters.length === 0) {
29508    if (placeholder === null) {
29509      throw new Error(`"${type}" trigger with no parameters can only be placed on an @defer that has a @placeholder block`);
29510    }
29511    if (placeholder.children.length !== 1 || !(placeholder.children[0] instanceof Element$1)) {
29512      throw new Error(`"${type}" trigger with no parameters can only be placed on an @defer that has a ` + `@placeholder block with exactly one root element node`);
29513    }
29514  }
29515}
29516/** Gets the index within an expression at which the trigger parameters start. */
29517function getTriggerParametersStart(value, startPosition = 0) {
29518  let hasFoundSeparator = false;
29519  for (let i = startPosition; i < value.length; i++) {
29520    if (SEPARATOR_PATTERN.test(value[i])) {
29521      hasFoundSeparator = true;
29522    } else if (hasFoundSeparator) {
29523      return i;
29524    }
29525  }
29526  return -1;
29527}
29528/**
29529 * Parses a time expression from a deferred trigger to
29530 * milliseconds. Returns null if it cannot be parsed.
29531 */
29532function parseDeferredTime(value) {
29533  const match = value.match(TIME_PATTERN);
29534  if (!match) {
29535    return null;
29536  }
29537  const [time, units] = match;
29538  return parseFloat(time) * (units === 's' ? 1000 : 1);
29539}
29540
29541/** Pattern to identify a `prefetch when` trigger. */
29542const PREFETCH_WHEN_PATTERN = /^prefetch\s+when\s/;
29543/** Pattern to identify a `prefetch on` trigger. */
29544const PREFETCH_ON_PATTERN = /^prefetch\s+on\s/;
29545/** Pattern to identify a `minimum` parameter in a block. */
29546const MINIMUM_PARAMETER_PATTERN = /^minimum\s/;
29547/** Pattern to identify a `after` parameter in a block. */
29548const AFTER_PARAMETER_PATTERN = /^after\s/;
29549/** Pattern to identify a `when` parameter in a block. */
29550const WHEN_PARAMETER_PATTERN = /^when\s/;
29551/** Pattern to identify a `on` parameter in a block. */
29552const ON_PARAMETER_PATTERN = /^on\s/;
29553/**
29554 * Predicate function that determines if a block with
29555 * a specific name cam be connected to a `defer` block.
29556 */
29557function isConnectedDeferLoopBlock(name) {
29558  return name === 'placeholder' || name === 'loading' || name === 'error';
29559}
29560/** Creates a deferred block from an HTML AST node. */
29561function createDeferredBlock(ast, connectedBlocks, visitor, bindingParser) {
29562  const errors = [];
29563  const {
29564    placeholder,
29565    loading,
29566    error
29567  } = parseConnectedBlocks(connectedBlocks, errors, visitor);
29568  const {
29569    triggers,
29570    prefetchTriggers
29571  } = parsePrimaryTriggers(ast.parameters, bindingParser, errors, placeholder);
29572  // The `defer` block has a main span encompassing all of the connected branches as well.
29573  let lastEndSourceSpan = ast.endSourceSpan;
29574  let endOfLastSourceSpan = ast.sourceSpan.end;
29575  if (connectedBlocks.length > 0) {
29576    const lastConnectedBlock = connectedBlocks[connectedBlocks.length - 1];
29577    lastEndSourceSpan = lastConnectedBlock.endSourceSpan;
29578    endOfLastSourceSpan = lastConnectedBlock.sourceSpan.end;
29579  }
29580  const sourceSpanWithConnectedBlocks = new ParseSourceSpan(ast.sourceSpan.start, endOfLastSourceSpan);
29581  const node = new DeferredBlock(visitAll(visitor, ast.children, ast.children), triggers, prefetchTriggers, placeholder, loading, error, ast.nameSpan, sourceSpanWithConnectedBlocks, ast.sourceSpan, ast.startSourceSpan, lastEndSourceSpan, ast.i18n);
29582  return {
29583    node,
29584    errors
29585  };
29586}
29587function parseConnectedBlocks(connectedBlocks, errors, visitor) {
29588  let placeholder = null;
29589  let loading = null;
29590  let error = null;
29591  for (const block of connectedBlocks) {
29592    try {
29593      if (!isConnectedDeferLoopBlock(block.name)) {
29594        errors.push(new ParseError(block.startSourceSpan, `Unrecognized block "@${block.name}"`));
29595        break;
29596      }
29597      switch (block.name) {
29598        case 'placeholder':
29599          if (placeholder !== null) {
29600            errors.push(new ParseError(block.startSourceSpan, `@defer block can only have one @placeholder block`));
29601          } else {
29602            placeholder = parsePlaceholderBlock(block, visitor);
29603          }
29604          break;
29605        case 'loading':
29606          if (loading !== null) {
29607            errors.push(new ParseError(block.startSourceSpan, `@defer block can only have one @loading block`));
29608          } else {
29609            loading = parseLoadingBlock(block, visitor);
29610          }
29611          break;
29612        case 'error':
29613          if (error !== null) {
29614            errors.push(new ParseError(block.startSourceSpan, `@defer block can only have one @error block`));
29615          } else {
29616            error = parseErrorBlock(block, visitor);
29617          }
29618          break;
29619      }
29620    } catch (e) {
29621      errors.push(new ParseError(block.startSourceSpan, e.message));
29622    }
29623  }
29624  return {
29625    placeholder,
29626    loading,
29627    error
29628  };
29629}
29630function parsePlaceholderBlock(ast, visitor) {
29631  let minimumTime = null;
29632  for (const param of ast.parameters) {
29633    if (MINIMUM_PARAMETER_PATTERN.test(param.expression)) {
29634      if (minimumTime != null) {
29635        throw new Error(`@placeholder block can only have one "minimum" parameter`);
29636      }
29637      const parsedTime = parseDeferredTime(param.expression.slice(getTriggerParametersStart(param.expression)));
29638      if (parsedTime === null) {
29639        throw new Error(`Could not parse time value of parameter "minimum"`);
29640      }
29641      minimumTime = parsedTime;
29642    } else {
29643      throw new Error(`Unrecognized parameter in @placeholder block: "${param.expression}"`);
29644    }
29645  }
29646  return new DeferredBlockPlaceholder(visitAll(visitor, ast.children, ast.children), minimumTime, ast.nameSpan, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan, ast.i18n);
29647}
29648function parseLoadingBlock(ast, visitor) {
29649  let afterTime = null;
29650  let minimumTime = null;
29651  for (const param of ast.parameters) {
29652    if (AFTER_PARAMETER_PATTERN.test(param.expression)) {
29653      if (afterTime != null) {
29654        throw new Error(`@loading block can only have one "after" parameter`);
29655      }
29656      const parsedTime = parseDeferredTime(param.expression.slice(getTriggerParametersStart(param.expression)));
29657      if (parsedTime === null) {
29658        throw new Error(`Could not parse time value of parameter "after"`);
29659      }
29660      afterTime = parsedTime;
29661    } else if (MINIMUM_PARAMETER_PATTERN.test(param.expression)) {
29662      if (minimumTime != null) {
29663        throw new Error(`@loading block can only have one "minimum" parameter`);
29664      }
29665      const parsedTime = parseDeferredTime(param.expression.slice(getTriggerParametersStart(param.expression)));
29666      if (parsedTime === null) {
29667        throw new Error(`Could not parse time value of parameter "minimum"`);
29668      }
29669      minimumTime = parsedTime;
29670    } else {
29671      throw new Error(`Unrecognized parameter in @loading block: "${param.expression}"`);
29672    }
29673  }
29674  return new DeferredBlockLoading(visitAll(visitor, ast.children, ast.children), afterTime, minimumTime, ast.nameSpan, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan, ast.i18n);
29675}
29676function parseErrorBlock(ast, visitor) {
29677  if (ast.parameters.length > 0) {
29678    throw new Error(`@error block cannot have parameters`);
29679  }
29680  return new DeferredBlockError(visitAll(visitor, ast.children, ast.children), ast.nameSpan, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan, ast.i18n);
29681}
29682function parsePrimaryTriggers(params, bindingParser, errors, placeholder) {
29683  const triggers = {};
29684  const prefetchTriggers = {};
29685  for (const param of params) {
29686    // The lexer ignores the leading spaces so we can assume
29687    // that the expression starts with a keyword.
29688    if (WHEN_PARAMETER_PATTERN.test(param.expression)) {
29689      parseWhenTrigger(param, bindingParser, triggers, errors);
29690    } else if (ON_PARAMETER_PATTERN.test(param.expression)) {
29691      parseOnTrigger(param, triggers, errors, placeholder);
29692    } else if (PREFETCH_WHEN_PATTERN.test(param.expression)) {
29693      parseWhenTrigger(param, bindingParser, prefetchTriggers, errors);
29694    } else if (PREFETCH_ON_PATTERN.test(param.expression)) {
29695      parseOnTrigger(param, prefetchTriggers, errors, placeholder);
29696    } else {
29697      errors.push(new ParseError(param.sourceSpan, 'Unrecognized trigger'));
29698    }
29699  }
29700  return {
29701    triggers,
29702    prefetchTriggers
29703  };
29704}
29705const BIND_NAME_REGEXP = /^(?:(bind-)|(let-)|(ref-|#)|(on-)|(bindon-)|(@))(.*)$/;
29706// Group 1 = "bind-"
29707const KW_BIND_IDX = 1;
29708// Group 2 = "let-"
29709const KW_LET_IDX = 2;
29710// Group 3 = "ref-/#"
29711const KW_REF_IDX = 3;
29712// Group 4 = "on-"
29713const KW_ON_IDX = 4;
29714// Group 5 = "bindon-"
29715const KW_BINDON_IDX = 5;
29716// Group 6 = "@"
29717const KW_AT_IDX = 6;
29718// Group 7 = the identifier after "bind-", "let-", "ref-/#", "on-", "bindon-" or "@"
29719const IDENT_KW_IDX = 7;
29720const BINDING_DELIMS = {
29721  BANANA_BOX: {
29722    start: '[(',
29723    end: ')]'
29724  },
29725  PROPERTY: {
29726    start: '[',
29727    end: ']'
29728  },
29729  EVENT: {
29730    start: '(',
29731    end: ')'
29732  }
29733};
29734const TEMPLATE_ATTR_PREFIX = '*';
29735function htmlAstToRender3Ast(htmlNodes, bindingParser, options) {
29736  const transformer = new HtmlAstToIvyAst(bindingParser, options);
29737  const ivyNodes = visitAll(transformer, htmlNodes, htmlNodes);
29738  // Errors might originate in either the binding parser or the html to ivy transformer
29739  const allErrors = bindingParser.errors.concat(transformer.errors);
29740  const result = {
29741    nodes: ivyNodes,
29742    errors: allErrors,
29743    styleUrls: transformer.styleUrls,
29744    styles: transformer.styles,
29745    ngContentSelectors: transformer.ngContentSelectors
29746  };
29747  if (options.collectCommentNodes) {
29748    result.commentNodes = transformer.commentNodes;
29749  }
29750  return result;
29751}
29752class HtmlAstToIvyAst {
29753  constructor(bindingParser, options) {
29754    this.bindingParser = bindingParser;
29755    this.options = options;
29756    this.errors = [];
29757    this.styles = [];
29758    this.styleUrls = [];
29759    this.ngContentSelectors = [];
29760    // This array will be populated if `Render3ParseOptions['collectCommentNodes']` is true
29761    this.commentNodes = [];
29762    this.inI18nBlock = false;
29763    /**
29764     * Keeps track of the nodes that have been processed already when previous nodes were visited.
29765     * These are typically blocks connected to other blocks or text nodes between connected blocks.
29766     */
29767    this.processedNodes = new Set();
29768  }
29769  // HTML visitor
29770  visitElement(element) {
29771    const isI18nRootElement = isI18nRootNode(element.i18n);
29772    if (isI18nRootElement) {
29773      if (this.inI18nBlock) {
29774        this.reportError('Cannot mark an element as translatable inside of a translatable section. Please remove the nested i18n marker.', element.sourceSpan);
29775      }
29776      this.inI18nBlock = true;
29777    }
29778    const preparsedElement = preparseElement(element);
29779    if (preparsedElement.type === PreparsedElementType.SCRIPT) {
29780      return null;
29781    } else if (preparsedElement.type === PreparsedElementType.STYLE) {
29782      const contents = textContents(element);
29783      if (contents !== null) {
29784        this.styles.push(contents);
29785      }
29786      return null;
29787    } else if (preparsedElement.type === PreparsedElementType.STYLESHEET && isStyleUrlResolvable(preparsedElement.hrefAttr)) {
29788      this.styleUrls.push(preparsedElement.hrefAttr);
29789      return null;
29790    }
29791    // Whether the element is a `<ng-template>`
29792    const isTemplateElement = isNgTemplate(element.name);
29793    const parsedProperties = [];
29794    const boundEvents = [];
29795    const variables = [];
29796    const references = [];
29797    const attributes = [];
29798    const i18nAttrsMeta = {};
29799    const templateParsedProperties = [];
29800    const templateVariables = [];
29801    // Whether the element has any *-attribute
29802    let elementHasInlineTemplate = false;
29803    for (const attribute of element.attrs) {
29804      let hasBinding = false;
29805      const normalizedName = normalizeAttributeName(attribute.name);
29806      // `*attr` defines template bindings
29807      let isTemplateBinding = false;
29808      if (attribute.i18n) {
29809        i18nAttrsMeta[attribute.name] = attribute.i18n;
29810      }
29811      if (normalizedName.startsWith(TEMPLATE_ATTR_PREFIX)) {
29812        // *-attributes
29813        if (elementHasInlineTemplate) {
29814          this.reportError(`Can't have multiple template bindings on one element. Use only one attribute prefixed with *`, attribute.sourceSpan);
29815        }
29816        isTemplateBinding = true;
29817        elementHasInlineTemplate = true;
29818        const templateValue = attribute.value;
29819        const templateKey = normalizedName.substring(TEMPLATE_ATTR_PREFIX.length);
29820        const parsedVariables = [];
29821        const absoluteValueOffset = attribute.valueSpan ? attribute.valueSpan.start.offset :
29822        // If there is no value span the attribute does not have a value, like `attr` in
29823        //`<div attr></div>`. In this case, point to one character beyond the last character of
29824        // the attribute name.
29825        attribute.sourceSpan.start.offset + attribute.name.length;
29826        this.bindingParser.parseInlineTemplateBinding(templateKey, templateValue, attribute.sourceSpan, absoluteValueOffset, [], templateParsedProperties, parsedVariables, true /* isIv
29826yAst */);
29827        templateVariables.push(...parsedVariables.map(v => new Variable(v.name, v.value, v.sourceSpan, v.keySpan, v.valueSpan)));
29828      } else {
29829        // Check for variables, events, property bindings, interpolation
29830        hasBinding = this.parseAttribute(isTemplateElement, attribute, [], parsedProperties, boundEvents, variables, references);
29831      }
29832      if (!hasBinding && !isTemplateBinding) {
29833        // don't include the bindings as attributes as well in the AST
29834        attributes.push(this.visitAttribute(attribute));
29835      }
29836    }
29837    let children;
29838    if (preparsedElement.nonBindable) {
29839      // The `NonBindableVisitor` may need to return an array of nodes for blocks so we need
29840      // to flatten the array here. Avoid doing this for the `HtmlAstToIvyAst` since `flat` creates
29841      // a new array.
29842      children = visitAll(NON_BINDABLE_VISITOR, element.children).flat(Infinity);
29843    } else {
29844      children = visitAll(this, element.children, element.children);
29845    }
29846    let parsedElement;
29847    if (preparsedElement.type === PreparsedElementType.NG_CONTENT) {
29848      // `<ng-content>`
29849      if (element.children && !element.children.every(node => isEmptyTextNode(node) || isCommentNode(node))) {
29850        this.reportError(`<ng-content> element cannot have content.`, element.sourceSpan);
29851      }
29852      const selector = preparsedElement.selectAttr;
29853      const attrs = element.attrs.map(attr => this.visitAttribute(attr));
29854      parsedElement = new Content(selector, attrs, element.sourceSpan, element.i18n);
29855      this.ngContentSelectors.push(selector);
29856    } else if (isTemplateElement) {
29857      // `<ng-template>`
29858      const attrs = this.extractAttributes(element.name, parsedProperties, i18nAttrsMeta);
29859      parsedElement = new Template(element.name, attributes, attrs.bound, boundEvents, [/* no template attributes */], children, references, variables, element.sourceSpan, element.startSourceSpan, element.endSourceSpan, element.i18n);
29860    } else {
29861      const attrs = this.extractAttributes(element.name, parsedProperties, i18nAttrsMeta);
29862      parsedElement = new Element$1(element.name, attributes, attrs.bound, boundEvents, children, references, element.sourceSpan, element.startSourceSpan, element.endSourceSpan, element.i18n);
29863    }
29864    if (elementHasInlineTemplate) {
29865      // If this node is an inline-template (e.g. has *ngFor) then we need to create a template
29866      // node that contains this node.
29867      // Moreover, if the node is an element, then we need to hoist its attributes to the template
29868      // node for matching against content projection selectors.
29869      const attrs = this.extractAttributes('ng-template', templateParsedProperties, i18nAttrsMeta);
29870      const templateAttrs = [];
29871      attrs.literal.forEach(attr => templateAttrs.push(attr));
29872      attrs.bound.forEach(attr => templateAttrs.push(attr));
29873      const hoistedAttrs = parsedElement instanceof Element$1 ? {
29874        attributes: parsedElement.attributes,
29875        inputs: parsedElement.inputs,
29876        outputs: parsedElement.outputs
29877      } : {
29878        attributes: [],
29879        inputs: [],
29880        outputs: []
29881      };
29882      // For <ng-template>s with structural directives on them, avoid passing i18n information to
29883      // the wrapping template to prevent unnecessary i18n instructions from being generated. The
29884      // necessary i18n meta information will be extracted from child elements.
29885      const i18n = isTemplateElement && isI18nRootElement ? undefined : element.i18n;
29886      const name = parsedElement instanceof Template ? null : parsedElement.name;
29887      parsedElement = new Template(name, hoistedAttrs.attributes, hoistedAttrs.inputs, hoistedAttrs.outputs, templateAttrs, [parsedElement], [/* no references */], templateVariables, element.sourceSpan, element.startSourceSpan, element.endSourceSpan, i18n);
29888    }
29889    if (isI18nRootElement) {
29890      this.inI18nBlock = false;
29891    }
29892    return parsedElement;
29893  }
29894  visitAttribute(attribute) {
29895    return new TextAttribute(attribute.name, attribute.value, attribute.sourceSpan, attribute.keySpan, attribute.valueSpan, attribute.i18n);
29896  }
29897  visitText(text) {
29898    return this.processedNodes.has(text) ? null : this._visitTextWithInterpolation(text.value, text.sourceSpan, text.tokens, text.i18n);
29899  }
29900  visitExpansion(expansion) {
29901    if (!expansion.i18n) {
29902      // do not generate Icu in case it was created
29903      // outside of i18n block in a template
29904      return null;
29905    }
29906    if (!isI18nRootNode(expansion.i18n)) {
29907      throw new Error(`Invalid type "${expansion.i18n.constructor}" for "i18n" property of ${expansion.sourceSpan.toString()}. Expected a "Message"`);
29908    }
29909    const message = expansion.i18n;
29910    const vars = {};
29911    const placeholders = {};
29912    // extract VARs from ICUs - we process them separately while
29913    // assembling resulting message via goog.getMsg function, since
29914    // we need to pass them to top-level goog.getMsg call
29915    Object.keys(message.placeholders).forEach(key => {
29916      const value = message.placeholders[key];
29917      if (key.startsWith(I18N_ICU_VAR_PREFIX)) {
29918        // Currently when the `plural` or `select` keywords in an ICU contain trailing spaces (e.g.
29919        // `{count, select , ...}`), these spaces are also included into the key names in ICU vars
29920        // (e.g. "VAR_SELECT "). These trailing spaces are not desirable, since they will later be
29921        // converted into `_` symbols while normalizing placeholder names, which might lead to
29922        // mismatches at runtime (i.e. placeholder will not be replaced with the correct value).
29923        const formattedKey = key.trim();
29924        const ast = this.bindingParser.parseInterpolationExpression(value.text, value.sourceSpan);
29925        vars[formattedKey] = new BoundText(ast, value.sourceSpan);
29926      } else {
29927        placeholders[key] = this._visitTextWithInterpolation(value.text, value.sourceSpan, null);
29928      }
29929    });
29930    return new Icu$1(vars, placeholders, expansion.sourceSpan, message);
29931  }
29932  visitExpansionCase(expansionCase) {
29933    return null;
29934  }
29935  visitComment(comment) {
29936    if (this.options.collectCommentNodes) {
29937      this.commentNodes.push(new Comment$1(comment.value || '', comment.sourceSpan));
29938    }
29939    return null;
29940  }
29941  visitBlockParameter() {
29942    return null;
29943  }
29944  visitBlock(block, context) {
29945    const index = Array.isArray(context) ? context.indexOf(block) : -1;
29946    if (index === -1) {
29947      throw new Error('Visitor invoked incorrectly. Expecting visitBlock to be invoked siblings array as its context');
29948    }
29949    // Connected blocks may have been processed as a part of the previous block.
29950    if (this.processedNodes.has(block)) {
29951      return null;
29952    }
29953    let result = null;
29954    switch (block.name) {
29955      case 'defer':
29956        result = createDeferredBlock(block, this.findConnectedBlocks(index, context, isConnectedDeferLoopBlock), this, this.bindingParser);
29957        break;
29958      case 'switch':
29959        result = createSwitchBlock(block, this, this.bindingParser);
29960        break;
29961      case 'for':
29962        result = createForLoop(block, this.findConnectedBlocks(index, context, isConnectedForLoopBlock), this, this.bindingParser);
29963        break;
29964      case 'if':
29965        result = createIfBlock(block, this.findConnectedBlocks(index, context, isConnectedIfLoopBlock), this, this.bindingParser);
29966        break;
29967      default:
29968        let errorMessage;
29969        if (isConnectedDeferLoopBlock(block.name)) {
29970          errorMessage = `@${block.name} block can only be used after an @defer block.`;
29971          this.processedNodes.add(block);
29972        } else if (isConnectedForLoopBlock(block.name)) {
29973          errorMessage = `@${block.name} block can only be used after an @for block.`;
29974          this.processedNodes.add(block);
29975        } else if (isConnectedIfLoopBlock(block.name)) {
29976          errorMessage = `@${block.name} block can only be used after an @if or @else if block.`;
29977          this.processedNodes.add(block);
29978        } else {
29979          errorMessage = `Unrecognized block @${block.name}.`;
29980        }
29981        result = {
29982          node: new UnknownBlock(block.name, block.sourceSpan, block.nameSpan),
29983          errors: [new ParseError(block.sourceSpan, errorMessage)]
29984        };
29985        break;
29986    }
29987    this.errors.push(...result.errors);
29988    return result.node;
29989  }
29990  findConnectedBlocks(primaryBlockIndex, siblings, predicate) {
29991    const relatedBlocks = [];
29992    for (let i = primaryBlockIndex + 1; i < siblings.length; i++) {
29993      const node = siblings[i];
29994      // Ignore empty text nodes between blocks.
29995      if (node instanceof Text && node.value.trim().length === 0) {
29996        // Add the text node to the processed nodes since we don't want
29997        // it to be generated between the connected nodes.
29998        this.processedNodes.add(node);
29999        continue;
30000      }
30001      // Stop searching as soon as we hit a non-block node or a block that is unrelated.
30002      if (!(node instanceof Block) || !predicate(node.name)) {
30003        break;
30004      }
30005      relatedBlocks.push(node);
30006      this.processedNodes.add(node);
30007    }
30008    return relatedBlocks;
30009  }
30010  // convert view engine `ParsedProperty` to a format suitable for IVY
30011  extractAttributes(elementName, properties, i18nPropsMeta) {
30012    const bound = [];
30013    const literal = [];
30014    properties.forEach(prop => {
30015      const i18n = i18nPropsMeta[prop.name];
30016      if (prop.isLiteral) {
30017        literal.push(new TextAttribute(prop.name, prop.expression.source || '', prop.sourceSpan, prop.keySpan, prop.valueSpan, i18n));
30018      } else {
30019        // Note that validation is skipped and property mapping is disabled
30020        // due to the fact that we need to make sure a given prop is not an
30021        // input of a directive and directive matching happens at runtime.
30022        const bep = this.bindingParser.createBoundElementProperty(elementName, prop, /* skipValidation */true, /* mapPropertyName */false);
30023        bound.push(BoundAttribute.fromBoundElementProperty(bep, i18n));
30024      }
30025    });
30026    return {
30027      bound,
30028      literal
30029    };
30030  }
30031  parseAttribute(isTemplateElement, attribute, matchableAttributes, parsedProperties, boundEvents, variables, references) {
30032    const name = normalizeAttributeName(attribute.name);
30033    const value = attribute.value;
30034    const srcSpan = attribute.sourceSpan;
30035    const absoluteOffset = attribute.valueSpan ? attribute.valueSpan.start.offset : srcSpan.start.offset;
30036    function createKeySpan(srcSpan, prefix, identifier) {
30037      // We need to adjust the start location for the keySpan to account for the removed 'data-'
30038      // prefix from `normalizeAttributeName`.
30039      const normalizationAdjustment = attribute.name.length - name.length;
30040      const keySpanStart = srcSpan.start.moveBy(prefix.length + normalizationAdjustment);
30041      const keySpanEnd = keySpanStart.moveBy(identifier.length);
30042      return new ParseSourceSpan(keySpanStart, keySpanEnd, keySpanStart, identifier);
30043    }
30044    const bindParts = name.match(BIND_NAME_REGEXP);
30045    if (bindParts) {
30046      if (bindParts[KW_BIND_IDX] != null) {
30047        const identifier = bindParts[IDENT_KW_IDX];
30048        const keySpan = createKeySpan(srcSpan, bindParts[KW_BIND_IDX], identifier);
30049        this.bindingParser.parsePropertyBinding(identifier, value, false, false, srcSpan, absoluteOffset, attribute.valueSpan, matchableAttributes, parsedProperties, keySpan);
30050      } else if (bindParts[KW_LET_IDX]) {
30051        if (isTemplateElement) {
30052          const identifier = bindParts[IDENT_KW_IDX];
30053          const keySpan = createKeySpan(srcSpan, bindParts[KW_LET_IDX], identifier);
30054          this.parseVariable(identifier, value, srcSpan, keySpan, attribute.valueSpan, variables);
30055        } else {
30056          this.reportError(`"let-" is only supported on ng-template elements.`, srcSpan);
30057        }
30058      } else if (bindParts[KW_REF_IDX]) {
30059        const identifier = bindParts[IDENT_KW_IDX];
30060        const keySpan = createKeySpan(srcSpan, bindParts[KW_REF_IDX], identifier);
30061        this.parseReference(identifier, value, srcSpan, keySpan, attribute.valueSpan, references);
30062      } else if (bindParts[KW_ON_IDX]) {
30063        const events = [];
30064        const identifier = bindParts[IDENT_KW_IDX];
30065        const keySpan = createKeySpan(srcSpan, bindParts[KW_ON_IDX], identifier);
30066        this.bindingParser.parseEvent(identifier, value, /* isAssignmentEvent */false, srcSpan, attribute.valueSpan || srcSpan, matchableAttributes, events, keySpan);
30067        addEvents(events, boundEvents);
30068      } else if (bindParts[KW_BINDON_IDX]) {
30069        const identifier = bindParts[IDENT_KW_IDX];
30070        const keySpan = createKeySpan(srcSpan, bindParts[KW_BINDON_IDX], identifier);
30071        this.bindingParser.parsePropertyBinding(identifier, value, false, true, srcSpan, absoluteOffset, attribute.valueSpan, matchableAttributes, parsedProperties, keySpan);
30072        this.parseAssignmentEvent(identifier, value, srcSpan, attribute.valueSpan, matchableAttributes, boundEvents, keySpan);
30073      } else if (bindParts[KW_AT_IDX]) {
30074        const keySpan = createKeySpan(srcSpan, '', name);
30075        this.bindingParser.parseLiteralAttr(name, value, srcSpan, absoluteOffset, attribute.valueSpan, matchableAttributes, parsedProperties, keySpan);
30076      }
30077      return true;
30078    }
30079    // We didn't see a kw-prefixed property binding, but we have not yet checked
30080    // for the []/()/[()] syntax.
30081    let delims = null;
30082    if (name.startsWith(BINDING_DELIMS.BANANA_BOX.start)) {
30083      delims = BINDING_DELIMS.BANANA_BOX;
30084    } else if (name.startsWith(BINDING_DELIMS.PROPERTY.start)) {
30085      delims = BINDING_DELIMS.PROPERTY;
30086    } else if (name.startsWith(BINDING_DELIMS.EVENT.start)) {
30087      delims = BINDING_DELIMS.EVENT;
30088    }
30089    if (delims !== null &&
30090    // NOTE: older versions of the parser would match a start/end delimited
30091    // binding iff the property name was terminated by the ending delimiter
30092    // and the identifier in the binding was non-empty.
30093    // TODO(ayazhafiz): update this to handle malformed bindings.
30094    name.endsWith(delims.end) && name.length > delims.start.length + delims.end.length) {
30095      const identifier = name.substring(delims.start.length, name.length - delims.end.length);
30096      const keySpan = createKeySpan(srcSpan, delims.start, identifier);
30097      if (delims.start === BINDING_DELIMS.BANANA_BOX.start) {
30098        this.bindingParser.parsePropertyBinding(identifier, value, false, true, srcSpan, absoluteOffset, attribute.valueSpan, matchableAttributes, parsedProperties, keySpan);
30099        this.parseAssignmentEvent(identifier, value, srcSpan, attribute.valueSpan, matchableAttributes, boundEvents, keySpan);
30100      } else if (delims.start === BINDING_DELIMS.PROPERTY.start) {
30101        this.bindingParser.parsePropertyBinding(identifier, value, false, false, srcSpan, absoluteOffset, attribute.valueSpan, matchableAttributes, parsedProperties, keySpan);
30102      } else {
30103        const events = [];
30104        this.bindingParser.parseEvent(identifier, value, /* isAssignmentEvent */false, srcSpan, attribute.valueSpan || srcSpan, matchableAttributes, events, keySpan);
30105        addEvents(events, boundEvents);
30106      }
30107      return true;
30108    }
30109    // No explicit binding found.
30110    const keySpan = createKeySpan(srcSpan, '' /* prefix */, name);
30111    const hasBinding = this.bindingParser.parsePropertyInterpolation(name, value, srcSpan, attribute.valueSpan, matchableAttributes, parsedProperties, keySpan, attribute.valueTokens ?? null);
30112    return hasBinding;
30113  }
30114  _visitTextWithInterpolation(value, sourceSpan, interpolatedTokens, i18n) {
30115    const valueNoNgsp = replaceNgsp(value);
30116    const expr = this.bindingParser.parseInterpolation(valueNoNgsp, sourceSpan, interpolatedTokens);
30117    return expr ? new BoundText(expr, sourceSpan, i18n) : new Text$3(valueNoNgsp, sourceSpan);
30118  }
30119  parseVariable(identifier, value, sourceSpan, keySpan, valueSpan, variables) {
30120    if (identifier.indexOf('-') > -1) {
30121      this.reportError(`"-" is not allowed in variable names`, sourceSpan);
30122    } else if (identifier.length === 0) {
30123      this.reportError(`Variable does not have a name`, sourceSpan);
30124    }
30125    variables.push(new Variable(identifier, value, sourceSpan, keySpan, valueSpan));
30126  }
30127  parseReference(identifier, value, sourceSpan, keySpan, valueSpan, references) {
30128    if (identifier.indexOf('-') > -1) {
30129      this.reportError(`"-" is not allowed in reference names`, sourceSpan);
30130    } else if (identifier.length === 0) {
30131      this.reportError(`Reference does not have a name`, sourceSpan);
30132    } else if (references.some(reference => reference.name === identifier)) {
30133      this.reportError(`Reference "#${identifier}" is defined more than once`, sourceSpan);
30134    }
30135    references.push(new Reference(identifier, value, sourceSpan, keySpan, valueSpan));
30136  }
30137  parseAssignmentEvent(name, expression, sourceSpan, valueSpan, targetMatchableAttrs, boundEvents, keySpan) {
30138    const events = [];
30139    this.bindingParser.parseEvent(`${name}Change`, expression, /* isAssignmentEvent */true, sourceSpan, valueSpan || sourceSpan, targetMatchableAttrs, events, keySpan);
30140    addEvents(events, boundEvents);
30141  }
30142  reportError(message, sourceSpan, level = ParseErrorLevel.ERROR) {
30143    this.errors.push(new ParseError(sourceSpan, message, level));
30144  }
30145}
30146class NonBindableVisitor {
30147  visitElement(ast) {
30148    const preparsedElement = preparseElement(ast);
30149    if (preparsedElement.type === PreparsedElementType.SCRIPT || preparsedElement.type === PreparsedElementType.STYLE || preparsedElement.type === PreparsedElementType.STYLESHEET) {
30150      // Skipping <script> for security reasons
30151      // Skipping <style> and stylesheets as we already processed them
30152      // in the StyleCompiler
30153      return null;
30154    }
30155    const children = visitAll(this, ast.children, null);
30156    return new Element$1(ast.name, visitAll(this, ast.attrs), /* inputs */[], /* outputs */[], children, /* references */[], ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan);
30157  }
30158  visitComment(comment) {
30159    return null;
30160  }
30161  visitAttribute(attribute) {
30162    return new TextAttribute(attribute.name, attribute.value, attribute.sourceSpan, attribute.keySpan, attribute.valueSpan, attribute.i18n);
30163  }
30164  visitText(text) {
30165    return new Text$3(text.value, text.sourceSpan);
30166  }
30167  visitExpansion(expansion) {
30168    return null;
30169  }
30170  visitExpansionCase(expansionCase) {
30171    return null;
30172  }
30173  visitBlock(block, context) {
30174    const nodes = [
30175    // In an ngNonBindable context we treat the opening/closing tags of block as plain text.
30176    // This is the as if the `tokenizeBlocks` option was disabled.
30177    new Text$3(block.startSourceSpan.toString(), block.startSourceSpan), ...visitAll(this, block.children)];
30178    if (block.endSourceSpan !== null) {
30179      nodes.push(new Text$3(block.endSourceSpan.toString(), block.endSourceSpan));
30180    }
30181    return nodes;
30182  }
30183  visitBlockParameter(parameter, context) {
30184    return null;
30185  }
30186}
30187const NON_BINDABLE_VISITOR = new NonBindableVisitor();
30188function normalizeAttributeName(attrName) {
30189  return /^data-/i.test(attrName) ? attrName.substring(5) : attrName;
30190}
30191function addEvents(events, boundEvents) {
30192  boundEvents.push(...events.map(e => BoundEvent.fromParsedEvent(e)));
30193}
30194function isEmptyTextNode(node) {
30195  return node instanceof Text && node.value.trim().length == 0;
30196}
30197function isCommentNode(node) {
30198  return node instanceof Comment;
30199}
30200function textContents(node) {
30201  if (node.children.length !== 1 || !(node.children[0] instanceof Text)) {
30202    return null;
30203  } else {
30204    return node.children[0].value;
30205  }
30206}
30207var TagType;
30208(function (TagType) {
30209  TagType[TagType["ELEMENT"] = 0] = "ELEMENT";
30210  TagType[TagType["TEMPLATE"] = 1] = "TEMPLATE";
30211})(TagType || (TagType = {}));
30212/**
30213 * Generates an object that is used as a shared state between parent and all child contexts.
30214 */
30215function setupRegistry() {
30216  return {
30217    getUniqueId: getSeqNumberGenerator(),
30218    icus: new Map()
30219  };
30220}
30221/**
30222 * I18nContext is a helper class which keeps track of all i18n-related as
30222pects
30223 * (accumulates placeholders, bindings, etc) between i18nStart and i18nEnd instructions.
30224 *
30225 * When we enter a nested template, the top-level context is being passed down
30226 * to the nested component, which uses this context to generate a child instance
30227 * of I18nContext class (to handle nested template) and at the end, reconciles it back
30228 * with the parent context.
30229 *
30230 * @param index Instruction index of i18nStart, which initiates this context
30231 * @param ref Reference to a translation const that represents the content if thus context
30232 * @param level Nesting level defined for child contexts
30233 * @param templateIndex Instruction index of a template which this context belongs to
30234 * @param meta Meta information (id, meaning, description, etc) associated with this context
30235 */
30236class I18nContext {
30237  constructor(index, ref, level = 0, templateIndex = null, meta, registry) {
30238    this.index = index;
30239    this.ref = ref;
30240    this.level = level;
30241    this.templateIndex = templateIndex;
30242    this.meta = meta;
30243    this.registry = registry;
30244    this.bindings = new Set();
30245    this.placeholders = new Map();
30246    this.isEmitted = false;
30247    this._unresolvedCtxCount = 0;
30248    this._registry = registry || setupRegistry();
30249    this.id = this._registry.getUniqueId();
30250  }
30251  appendTag(type, node, index, closed) {
30252    if (node.isVoid && closed) {
30253      return; // ignore "close" for void tags
30254    }
30255    const ph = node.isVoid || !closed ? node.startName : node.closeName;
30256    const content = {
30257      type,
30258      index,
30259      ctx: this.id,
30260      isVoid: node.isVoid,
30261      closed
30262    };
30263    updatePlaceholderMap(this.placeholders, ph, content);
30264  }
30265  appendBlockPart(node, index, closed) {
30266    const ph = closed ? node.closeName : node.startName;
30267    const content = {
30268      type: TagType.TEMPLATE,
30269      index,
30270      ctx: this.id,
30271      closed
30272    };
30273    updatePlaceholderMap(this.placeholders, ph, content);
30274  }
30275  get icus() {
30276    return this._registry.icus;
30277  }
30278  get isRoot() {
30279    return this.level === 0;
30280  }
30281  get isResolved() {
30282    return this._unresolvedCtxCount === 0;
30283  }
30284  getSerializedPlaceholders() {
30285    const result = new Map();
30286    this.placeholders.forEach((values, key) => result.set(key, values.map(serializePlaceholderValue)));
30287    return result;
30288  }
30289  // public API to accumulate i18n-related content
30290  appendBinding(binding) {
30291    this.bindings.add(binding);
30292  }
30293  appendIcu(name, ref) {
30294    updatePlaceholderMap(this._registry.icus, name, ref);
30295  }
30296  appendBoundText(node) {
30297    const phs = assembleBoundTextPlaceholders(node, this.bindings.size, this.id);
30298    phs.forEach((values, key) => updatePlaceholderMap(this.placeholders, key, ...values));
30299  }
30300  appendTemplate(node, index) {
30301    // add open and close tags at the same time,
30302    // since we process nested templates separately
30303    this.appendTag(TagType.TEMPLATE, node, index, false);
30304    this.appendTag(TagType.TEMPLATE, node, index, true);
30305    this._unresolvedCtxCount++;
30306  }
30307  appendBlock(node, index) {
30308    // add open and close tags at the same time,
30309    // since we process nested templates separately
30310    this.appendBlockPart(node, index, false);
30311    this.appendBlockPart(node, index, true);
30312    this._unresolvedCtxCount++;
30313  }
30314  appendElement(node, index, closed) {
30315    this.appendTag(TagType.ELEMENT, node, index, closed);
30316  }
30317  appendProjection(node, index) {
30318    // Add open and close tags at the same time, since `<ng-content>` has no content,
30319    // so when we come across `<ng-content>` we can register both open and close tags.
30320    // Note: runtime i18n logic doesn't distinguish `<ng-content>` tag placeholders and
30321    // regular element tag placeholders, so we generate element placeholders for both types.
30322    this.appendTag(TagType.ELEMENT, node, index, false);
30323    this.appendTag(TagType.ELEMENT, node, index, true);
30324  }
30325  /**
30326   * Generates an instance of a child context based on the root one,
30327   * when we enter a nested template within I18n section.
30328   *
30329   * @param index Instruction index of corresponding i18nStart, which initiates this context
30330   * @param templateIndex Instruction index of a template which this context belongs to
30331   * @param meta Meta information (id, meaning, description, etc) associated with this context
30332   *
30333   * @returns I18nContext instance
30334   */
30335  forkChildContext(index, templateIndex, meta) {
30336    return new I18nContext(index, this.ref, this.level + 1, templateIndex, meta, this._registry);
30337  }
30338  /**
30339   * Reconciles child context into parent one once the end of the i18n block 
30339is reached (i18nEnd).
30340   *
30341   * @param context Child I18nContext instance to be reconciled with parent context.
30342   */
30343  reconcileChildContext(context) {
30344    // set the right context id for open and close
30345    // template tags, so we can use it as sub-block ids
30346    ['start', 'close'].forEach(op => {
30347      const key = context.meta[`${op}Name`];
30348      const phs = this.placeholders.get(key) || [];
30349      const tag = phs.find(findTemplateFn(this.id, context.templateIndex));
30350      if (tag) {
30351        tag.ctx = context.id;
30352      }
30353    });
30354    // reconcile placeholders
30355    const childPhs = context.placeholders;
30356    childPhs.forEach((values, key) => {
30357      const phs = this.placeholders.get(key);
30358      if (!phs) {
30359        this.placeholders.set(key, values);
30360        return;
30361      }
30362      // try to find matching template...
30363      const tmplIdx = phs.findIndex(findTemplateFn(context.id, context.templateIndex));
30364      if (tmplIdx >= 0) {
30365        // ... if found - replace it with nested template content
30366        const isCloseTag = key.startsWith('CLOSE');
30367        const isTemplateTag = key.endsWith('NG-TEMPLATE');
30368        if (isTemplateTag) {
30369          // current template's content is placed before or after
30370          // parent template tag, depending on the open/close attribute
30371          phs.splice(tmplIdx + (isCloseTag ? 0 : 1), 0, ...values);
30372        } else {
30373          const idx = isCloseTag ? values.length - 1 : 0;
30374          values[idx].tmpl = phs[tmplIdx];
30375          phs.splice(tmplIdx, 1, ...values);
30376        }
30377      } else {
30378        // ... otherwise just append content to placeholder value
30379        phs.push(...values);
30380      }
30381      this.placeholders.set(key, phs);
30382    });
30383    this._unresolvedCtxCount--;
30384  }
30385}
30386//
30387// Helper methods
30388//
30389function wrap(symbol, index, contextId, closed) {
30390  const state = closed ? '/' : '';
30391  return wrapI18nPlaceholder(`${state}${symbol}${index}`, contextId);
30392}
30393function wrapTag(symbol, {
30394  index,
30395  ctx,
30396  isVoid
30397}, closed) {
30398  return isVoid ? wrap(symbol, index, ctx) + wrap(symbol, index, ctx, true) : wrap(symbol, index, ctx, closed);
30399}
30400function findTemplateFn(ctx, templateIndex) {
30401  return token => typeof token === 'object' && token.type === TagType.TEMPLATE && token.index === templateIndex && token.ctx === ctx;
30402}
30403function serializePlaceholderValue(value) {
30404  const element = (data, closed) => wrapTag('#', data, closed);
30405  const template = (data, closed) => wrapTag('*', data, closed);
30406  switch (value.type) {
30407    case TagType.ELEMENT:
30408      // close element tag
30409      if (value.closed) {
30410        return element(value, true) + (value.tmpl ? template(value.tmpl, true) : '');
30411      }
30412      // open element tag that also initiates a template
30413      if (value.tmpl) {
30414        return template(value.tmpl) + element(value) + (value.isVoid ? template(value.tmpl, true) : '');
30415      }
30416      return element(value);
30417    case TagType.TEMPLATE:
30418      return template(value, value.closed);
30419    default:
30420      return value;
30421  }
30422}
30423const IMPORTANT_FLAG = '!important';
30424/**
30425 * Minimum amount of binding slots required in the runtime for style/class bindings.
30426 *
30427 * Styling in Angular uses up two slots in the runtime LView/TData data structures to
30428 * record binding data, property information and metadata.
30429 *
30430 * When a binding is registered it will place the following information in the `LView`:
30431 *
30432 * slot 1) binding value
30433 * slot 2) cached value (all other values collected before it in string form)
30434 *
30435 * When a binding is registered it will place the following information in the `TData`:
30436 *
30437 * slot 1) prop name
30438 * slot 2) binding index that points to the previous style/class binding (and some extra config
30439 * values)
30440 *
30441 * Let's imagine we have a binding that looks like so:
30442 *
30443 * ```
30444 * <div [style.width]="x" [style.height]="y">
30445 * ```
30446 *
30447 * Our `LView` and `TData` data-structures look like so:
30448 *
30449 * ```typescript
30450 * LView = [
30451 *   // ...
30452 *   x, // value of x
30453 *   "width: x",
30454 *
30455 *   y, // value of y
30456 *   "width: x; height: y",
30457 *   // ...
30458 * ];
30459 *
30460 * TData = [
30461 *   // ...
30462 *   "width", // binding slot 20
30463 *   0,
30464 *
30465 *   "height",
30466 *   20,
30467 *   // ...
30468 * ];
30469 * ```
30470 *
30471 * */
30472const MIN_STYLING_BINDING_SLOTS_REQUIRED = 2;
30473/**
30474 * Produces creation/update instructions for all styling bindings (class and style)
30475 *
30476 * It also produces the creation instruction to register all initial styling values
30477 * (which are all the static class="..." and style="..." attribute values that exist
30478 * on an element within a template).
30479 *
30480 * The builder class below handles producing instructions for the following cases:
30481 *
30482 * - Static style/class attributes (style="..." and class="...")
30483 * - Dynamic style/class map bindings ([style]="map" and [class]="map|string")
30484 * - Dynamic style/class property bindings ([style.prop]="exp" and [class.name]="exp")
30485 *
30486 * Due to the complex relationship of all of these cases, the instructions generated
30487 * for these attributes/properties/bindings must be done so in the correct order. The
30488 * order which these must be generated is as follows:
30489 *
30490 * if (createMode) {
30491 *   styling(...)
30492 * }
30493 * if (updateMode) {
30494 *   styleMap(...)
30495 *   classMap(...)
30496 *   styleProp(...)
30497 *   classProp(...)
30498 * }
30499 *
30500 * The creation/update methods within the builder class produce these instructions.
30501 */
30502class StylingBuilder {
30503  constructor(_directiveExpr) {
30504    this._directiveExpr = _directiveExpr;
30505    /** Whether or not there are any static styling values present */
30506    this._hasInitialValues = false;
30507    /**
30508     *  Whether or not there are any styling bindings present
30509     *  (i.e. `[style]`, `[class]`, `[style.prop]` or `[class.name]`)
30510     */
30511    this.hasBindings = false;
30512    this.hasBindingsWithPipes = false;
30513    /** the input for [class] (if it exists) */
30514    this._classMapInput = null;
30515    /** the input for [style] (if it exists) */
30516    this._styleMapInput = null;
30517    /** an array of each [style.prop] input */
30518    this._singleStyleInputs = null;
30519    /** an array of each [class.name] input */
30520    this._singleClassInputs = null;
30521    this._lastStylingInput = null;
30522    this._firstStylingInput = null;
30523    // maps are used instead of hash maps because a Map will
30524    // retain the ordering of the keys
30525    /**
30526     * Represents the location of each style binding in the template
30527     * (e.g. `<div [style.width]="w" [style.height]="h">` implies
30528     * that `width=0` and `height=1`)
30529     */
30530    this._stylesIndex = new Map();
30531    /**
30532     * Represents the location of each class binding in the template
30533     * (e.g. `<div [class.big]="b" [class.hidden]="h">` implies
30534     * that `big=0` and `hidden=1`)
30535     */
30536    this._classesIndex = new Map();
30537    this._initialStyleValues = [];
30538    this._initialClassValues = [];
30539  }
30540  /**
30541   * Registers a given input to the styling builder to be later used when producing AOT code.
30542   *
30543   * The code below will only accept the input if it is somehow tied to styling (whether it be
30544   * style/class bindings or static style/class attributes).
30545   */
30546  registerBoundInput(input) {
30547    // [attr.style] or [attr.class] are skipped in the code below,
30548    // they should not be treated as styling-based bindings since
30549    // they are intended to be written directly to the attr and
30550    // will therefore skip all style/class resolution that is present
30551    // with style="", [style]="" and [style.prop]="", class="",
30552    // [class.prop]="". [class]="" assignments
30553    let binding = null;
30554    let name = input.name;
30555    switch (input.type) {
30556      case 0 /* BindingType.Property */:
30557        binding = this.registerInputBasedOnName(name, input.value, input.sourceSpan);
30558        break;
30559      case 3 /* BindingType.Style */:
30560        binding = this.registerStyleInput(name, false, input.value, input.sourceSpan, input.unit);
30561        break;
30562      case 2 /* BindingType.Class */:
30563        binding = this.registerClassInput(name, false, input.value, input.sourceSpan);
30564        break;
30565    }
30566    return binding ? true : false;
30567  }
30568  registerInputBasedOnName(name, expression, sourceSpan) {
30569    let binding = null;
30570    const prefix = name.substring(0, 6);
30571    const isStyle = name === 'style' || prefix === 'style.' || prefix === 'style!';
30572    const isClass = !isStyle && (name === 'class' || prefix === 'class.' || prefix === 'class!');
30573    if (isStyle || isClass) {
30574      const isMapBased = name.charAt(5) !== '.'; // style.prop or class.prop makes this a no
30575      const property = name.slice(isMapBased ? 5 : 6); // the dot explains why there's a +1
30576      if (isStyle) {
30577        binding = this.registerStyleInput(property, isMapBased, expression, sourceSpan);
30578      } else {
30579        binding = this.registerClassInput(property, isMapBased, expression, sourceSpan);
30580      }
30581    }
30582    return binding;
30583  }
30584  registerStyleInput(name, isMapBased, value, sourceSpan, suffix) {
30585    if (isEmptyExpression(value)) {
30586      return null;
30587    }
30588    // CSS custom properties are case-sensitive so we shouldn't normalize them.
30589    // See: https://www.w3.org/TR/css-variables-1/#defining-variables
30590    if (!isCssCustomProperty(name)) {
30591      name = hyphenate(name);
30592    }
30593    const {
30594      property,
30595      hasOverrideFlag,
30596      suffix: bindingSuffix
30597    } = parseProperty(name);
30598    suffix = typeof suffix === 'string' && suffix.length !== 0 ? suffix : bindingSuffix;
30599    const entry = {
30600      name: property,
30601      suffix: suffix,
30602      value,
30603      sourceSpan,
30604      hasOverrideFlag
30605    };
30606    if (isMapBased) {
30607      this._styleMapInput = entry;
30608    } else {
30609      (this._singleStyleInputs = this._singleStyleInputs || []).push(entry);
30610      registerIntoMap(this._stylesIndex, property);
30611    }
30612    this._lastStylingInput = entry;
30613    this._firstStylingInput = this._firstStylingInput || entry;
30614    this._checkForPipes(value);
30615    this.hasBindings = true;
30616    return entry;
30617  }
30618  registerClassInput(name, isMapBased, value, sourceSpan) {
30619    if (isEmptyExpression(value)) {
30620      return null;
30621    }
30622    const {
30623      property,
30624      hasOverrideFlag
30625    } = parseProperty(name);
30626    const entry = {
30627      name: property,
30628      value,
30629      sourceSpan,
30630      hasOverrideFlag,
30631      suffix: null
30632    };
30633    if (isMapBased) {
30634      this._classMapInput = entry;
30635    } else {
30636      (this._singleClassInputs = this._singleClassInputs || []).push(entry);
30637      registerIntoMap(this._classesIndex, property);
30638    }
30639    this._lastStylingInput = entry;
30640    this._firstStylingInput = this._firstStylingInput || entry;
30641    this._checkForPipes(value);
30642    this.hasBindings = true;
30643    return entry;
30644  }
30645  _checkForPipes(value) {
30646    if (value instanceof ASTWithSource && value.ast instanceof BindingPipe) {
30647      this.hasBindingsWithPipes = true;
30648    }
30649  }
30650  /**
30651   * Registers the element's static style string value to the builder.
30652   *
30653   * @param value the style string (e.g. `width:100px; height:200px;`)
30654   */
30655  registerStyleAttr(value) {
30656    this._initialStyleValues = parse(value);
30657    this._hasInitialValues = true;
30658  }
30659  /**
30660   * Registers the element's static class string value to the builder.
30661   *
30662   * @param value the className string (e.g. `disabled gold zoom`)
30663   */
30664  registerClassAttr(value) {
30665    this._initialClassValues = value.trim().split(/\s+/g);
30666    this._hasInitialValues = true;
30667  }
30668  /**
30669   * Appends all styling-related expressions to the provided attrs array.
30670   *
30671   * @param attrs an existing array where each of the styling expressions
30672   * will be inserted into.
30673   */
30674  populateInitialStylingAttrs(attrs) {
30675    // [CLASS_MARKER, 'foo', 'bar', 'baz' ...]
30676    if (this._initialClassValues.length) {
30677      attrs.push(literal(1 /* AttributeMarker.Classes */));
30678      for (let i = 0; i < this._initialClassValues.length; i++) {
30679        attrs.push(literal(this._initialClassValues[i]));
30680      }
30681    }
30682    // [STYLE_MARKER, 'width', '200px', 'height', '100px', ...]
30683    if (this._initialStyleValues.length) {
30684      attrs.push(literal(2 /* AttributeMarker.Styles */));
30685      for (let i = 0; i < this._initialStyleValues.length; i += 2) {
30686        attrs.push(literal(this._initialStyleValues[i]), literal(this._initialStyleValues[i + 1]));
30687      }
30688    }
30689  }
30690  /**
30691   * Builds an instruction with all the expressions and parameters for `elementHostAttrs`.
30692   *
30693   * The instruction generation code below is used for producing the AOT statement code which is
30694   * responsible for registering initial styles (within a directive hostBindings' creation block),
30695   * as well as any of the provided attribute values, to the directive host element.
30696   */
30697  assignHostAttrs(attrs, definitionMap) {
30698    if (this._directiveExpr && (attrs.length || this._hasInitialValues)) {
30699      this.populateInitialStylingAttrs(attrs);
30700      definitionMap.set('hostAttrs', literalArr(attrs));
30701    }
30702  }
30703  /**
30704   * Builds an instruction with all the expressions and parameters for `classMap`.
30705   *
30706   * The instruction data will contain all expressions for `classMap` to function
30707   * which includes the `[class]` expression params.
30708   */
30709  buildClassMapInstruction(valueConverter) {
30710    if (this._classMapInput) {
30711      return this._buildMapBasedInstruction(valueConverter, true, this._classMapInput);
30712    }
30713    return null;
30714  }
30715  /**
30716   * Builds an instruction with all the expressions and parameters for `styleMap`.
30717   *
30718   * The instruction data will contain all expressions for `styleMap` to function
30719   * which includes the `[style]` expression params.
30720   */
30721  buildStyleMapInstruction(valueConverter) {
30722    if (this._styleMapInput) {
30723      return this._buildMapBasedInstruction(valueConverter, false, this._styleMapInput);
30724    }
30725    return null;
30726  }
30727  _buildMapBasedInstruction(valueConverter, isClassBased, stylingInput) {
30728    // each styling binding value is stored in the LView
30729    // map-based bindings allocate two slots: one for the
30730    // previous binding value and another for the previous
30731    // className or style attribute value.
30732    let totalBindingSlotsRequired = MIN_STYLING_BINDING_SLOTS_REQUIRED;
30733    // these values must be outside of the update block so that they can
30734    // be evaluated (the AST visit call) during creation time so that any
30735    // pipes can be picked up in time before the template is built
30736    const mapValue = stylingInput.value.visit(valueConverter);
30737    let reference;
30738    if (mapValue instanceof Interpolation$1) {
30739      totalBindingSlotsRequired += mapValue.expressions.length;
30740      reference = isClassBased ? getClassMapInterpolationExpression(mapValue) : getStyleMapInterpolationExpression(mapValue);
30741    } else {
30742      reference = isClassBased ? Identifiers.classMap : Identifiers.styleMap;
30743    }
30744    return {
30745      reference,
30746      calls: [{
30747        supportsInterpolation: true,
30748        sourceSpan: stylingInput.sourceSpan,
30749        allocateBindingSlots: totalBindingSlotsRequired,
30750        params: convertFn => {
30751          const convertResult = convertFn(mapValue);
30752          const params = Array.isArray(convertResult) ? convertResult : [convertResult];
30753          return params;
30754        }
30755      }]
30756    };
30757  }
30758  _buildSingleInputs(reference, inputs, valueConverter, getInterpolationExpressionFn, isClassBased) {
30759    const instructions = [];
30760    inputs.forEach(input => {
30761      const previousInstruction = instructions[instructions.length - 1];
30762      const value = input.value.visit(valueConverter);
30763      let referenceForCall = reference;
30764      // each styling binding value is stored in the LView
30765      // but there are two values stored for each binding:
30766      //   1) the value itself
30767      //   2) an intermediate value (concatenation of style up to this point).
30768      //      We need to store the intermediate value so that we don't allocate
30769      //      the strings on each CD.
30770      let totalBindingSlotsRequired = MIN_STYLING_BINDING_SLOTS_REQUIRED;
30771      if (value instanceof Interpolation$1) {
30772        totalBindingSlotsRequired += value.expressions.length;
30773        if (getInterpolationExpressionFn) {
30774          referenceForCall = getInterpolationExpressionFn(value);
30775        }
30776      }
30777      const call = {
30778        sourceSpan: input.sourceSpan,
30779        allocateBindingSlots: totalBindingSlotsRequired,
30780        supportsInterpolation: !!getInterpolationExpressionFn,
30781        params: convertFn => {
30782          // params => stylingProp(propName, value, suffix)
30783          const params = [];
30784          params.push(literal(input.name));
30785          const convertResult = convertFn(value);
30786          if (Array.isArray(convertResult)) {
30787            params.push(...convertResult);
30788          } else {
30789            params.push(convertResult);
30790          }
30791          // [style.prop] bindings may use suffix values (e.g. px, em, etc...), therefore,
30792          // if that is detected then we need to pass that in as an optional param.
30793          if (!isClassBased && input.suffix !== null) {
30794            params.push(literal(input.suffix));
30795          }
30796          return params;
30797        }
30798      };
30799      // If we ended up generating a call to the same instruction as the previous styling property
30800      // we can chain the calls together safely to save some bytes, otherwise we have to generate
30801      // a separate instruction call. This is primarily a concern with interpolation instructions
30802      // where we may start off with one `reference`, but end up using another based on the
30803      // number of interpolations.
30804      if (previousInstruction && previousInstruction.reference === referenceForCall) {
30805        previousInstruction.calls.push(call);
30806      } else {
30807        instructions.push({
30808          reference: referenceForCall,
30809          calls: [call]
30810        });
30811      }
30812    });
30813    return instructions;
30814  }
30815  _buildClassInputs(valueConverter) {
30816    if (this._singleClassInputs) {
30817      return this._buildSingleInputs(Identifiers.classProp, this._singleClassInputs, valueConverter, null, true);
30818    }
30819    return [];
30820  }
30821  _buildStyleInputs(valueConverter) {
30822    if (this._singleStyleInputs) {
30823      return this._buildSingleInputs(Identifiers.styleProp, this._singleStyleInputs, valueConverter, getStylePropInterpolationExpression, false);
30824    }
30825    return [];
30826  }
30827  /**
30828   * Constructs all instructions which contain the expressions that will be placed
30829   * into the update block of a template function or a directive hostBindings function.
30830   */
30831  buildUpdateLevelInstructions(valueConverter) {
30832    const instructions = [];
30833    if (this.hasBindings) {
30834      const styleMapInstruction = this.buildStyleMapInstruction(valueConverter);
30835      if (styleMapInstruction) {
30836        instructions.push(styleMapInstruction);
30837      }
30838      const classMapInstruction = this.buildClassMapInstruction(valueConverter);
30839      if (classMapInstruction) {
30840        instructions.push(classMapInstruction);
30841      }
30842      instructions.push(...this._buildStyleInputs(valueConverter));
30843      instructions.push(...this._buildClassInputs(valueConverter));
30844    }
30845    return instructions;
30846  }
30847}
30848function registerIntoMap(map, key) {
30849  if (!map.has(key)) {
30850    map.set(key, map.size);
30851  }
30852}
30853function parseProperty(name) {
30854  let hasOverrideFlag = false;
30855  const overrideIndex = name.indexOf(IMPORTANT_FLAG);
30856  if (overrideIndex !== -1) {
30857    name = overrideIndex > 0 ? name.substring(0, overrideIndex) : '';
30858    hasOverrideFlag = true;
30859  }
30860  let suffix = null;
30861  let property = name;
30862  const unitIndex = name.lastIndexOf('.');
30863  if (unitIndex > 0) {
30864    suffix = name.slice(unitIndex + 1);
30865    property = name.substring(0, unitIndex);
30866  }
30867  return {
30868    property,
30869    suffix,
30870    hasOverrideFlag
30871  };
30872}
30873/**
30874 * Gets the instruction to generate for an interpolated class map.
30875 * @param interpolation An Interpolation AST
30876 */
30877function getClassMapInterpolationExpression(interpolation) {
30878  switch (getInterpolationArgsLength(interpolation)) {
30879    case 1:
30880      return Identifiers.classMap;
30881    case 3:
30882      return Identifiers.classMapInterpolate1;
30883    case 5:
30884      return Identifiers.classMapInterpolate2;
30885    case 7:
30886      return Identifiers.classMapInterpolate3;
30887    case 9:
30888      return Identifiers.classMapInterpolate4;
30889    case 11:
30890      return Identifiers.classMapInterpolate5;
30891    case 13:
30892      return Identifiers.classMapInterpolate6;
30893    case 15:
30894      return Identifiers.classMapInterpolate7;
30895    case 17:
30896      return Identifiers.classMapInterpolate8;
30897    default:
30898      return Identifiers.classMapInterpolateV;
30899  }
30900}
30901/**
30902 * Gets the instruction to generate for an interpolated style map.
30903 * @param interpolation An Interpolation AST
30904 */
30905function getStyleMapInterpolationExpression(interpolation) {
30906  switch (getInterpolationArgsLength(interpolation)) {
30907    case 1:
30908      return Identifiers.styleMap;
30909    case 3:
30910      return Identifiers.styleMapInterpolate1;
30911    case 5:
30912      return Identifiers.styleMapInterpolate2;
30913    case 7:
30914      return Identifiers.styleMapInterpolate3;
30915    case 9:
30916      return Identifiers.styleMapInterpolate4;
30917    case 11:
30918      return Identifiers.styleMapInterpolate5;
30919    case 13:
30920      return Identifiers.styleMapInterpolate6;
30921    case 15:
30922      return Identifiers.styleMapInterpolate7;
30923    case 17:
30924      return Identifiers.styleMapInterpolate8;
30925    default:
30926      return Identifiers.styleMapInterpolateV;
30927  }
30928}
30929/**
30930 * Gets the instruction to generate for an interpolated style prop.
30931 * @param interpolation An Interpolation AST
30932 */
30933function getStylePropInterpolationExpression(interpolation) {
30934  switch (getInterpolationArgsLength(interpolation)) {
30935    case 1:
30936      return Identifiers.styleProp;
30937    case 3:
30938      return Identifiers.stylePropInterpolate1;
30939    case 5:
30940      return Identifiers.stylePropInterpolate2;
30941    case 7:
30942      return Identifiers.stylePropInterpolate3;
30943    case 9:
30944      return Identifiers.stylePropInterpolate4;
30945    case 11:
30946      return Identifiers.stylePropInterpolate5;
30947    case 13:
30948      return Identifiers.stylePropInterpolate6;
30949    case 15:
30950      return Identifiers.stylePropInterpolate7;
30951    case 17:
30952      return Identifiers.stylePropInterpolate8;
30953    default:
30954      return Identifiers.stylePropInterpolateV;
30955  }
30956}
30957/**
30958 * Checks whether property name is a custom CSS property.
30959 * See: https://www.w3.org/TR/css-variables-1
30960 */
30961function isCssCustomProperty(name) {
30962  return name.startsWith('--');
30963}
30964function isEmptyExpression(ast) {
30965  if (ast instanceof ASTWithSource) {
30966    ast = ast.ast;
30967  }
30968  return ast instanceof EmptyExpr$1;
30969}
30970
30971// Selector attribute name of `<ng-content>`
30972const NG_CONTENT_SELECT_ATTR = 'select';
30973// Attribute name of `ngProjectAs`.
30974const NG_PROJECT_AS_ATTR_NAME = 'ngProjectAs';
30975// Global symbols available only inside event bindings.
30976const EVENT_BINDING_SCOPE_GLOBALS = new Set(['$event']);
30977// Tag name of the `ng-template` element.
30978const NG_TEMPLATE_TAG_NAME = 'ng-template';
30979// List of supported global targets for event listeners
30980const GLOBAL_TARGET_RESOLVERS = new Map([['window', Identifiers.resolveWindow], ['document', Identifiers.resolveDocument], ['body', Identifiers.resolveBody]]);
30981const LEADING_TRIVIA_CHARS = [' ', '\n', '\r', '\t'];
30982//  if (rf & flags) { .. }
30983function renderFlagCheckIfStmt(flags, statements) {
30984  return ifStmt(variable(RENDER_FLAGS).bitwiseAnd(literal(flags), null, false), statements);
30985}
30986function prepareEventListenerParameters(eventAst, handlerName = null, scope = null) {
30987  const {
30988    type,
30989    name,
30990    target,
30991    phase,
30992    handler
30993  } = eventAst;
30994  if (target && !GLOBAL_TARGET_RESOLVERS.has(target)) {
30995    throw new Error(`Unexpected global target '${target}' defined for '${name}' event.
30996        Supported list of global targets: ${Array.from(GLOBAL_TARGET_RESOLVERS.keys())}.`);
30997  }
30998  const eventArgumentName = '$event';
30999  const implicitReceiverAccesses = new Set();
31000  const implicitReceiverExpr = scope === null || scope.bindingLevel === 0 ? variable(CONTEXT_NAME) : scope.getOrCreateSharedContextVar(0);
31001  const bindingStatements = eventAst.type === 2 /* ParsedEventType.TwoWay */ ? convertAssignmentActionBinding(scope, implicitReceiverExpr, handler, 'b', eventAst.handlerSpan, implicitReceiverAccesses, EVENT_BINDING_SCOPE_GLOBALS) : convertActionBinding(scope, implicitReceiverExpr, handler, 'b', eventAst.handlerSpan, implicitReceiverAccesses, EVENT_BINDING_SCOPE_GLOBALS);
31002  const statements = [];
31003  const variableDeclarations = scope?.variableDeclarations();
31004  const restoreViewStatement = scope?.restoreViewStatement();
31005  if (variableDeclarations) {
31006    // `variableDeclarations` needs to run first, because
31007    // `restoreViewStatement` depends on the result.
31008    statements.push(...variableDeclarations);
31009  }
31010  statements.push(...bindingStatements);
31011  if (restoreViewStatement) {
31012    statements.unshift(restoreViewStatement);
31013    // If there's a `restoreView` call, we need to reset the view at the end of the listener
31014    // in order to avoid a leak. If there's a `return` statement already, we wrap it in the
31015    // call, e.g. `return resetView(ctx.foo())`. Otherwise we add the call as the last statement.
31016    const lastStatement = statements[statements.length - 1];
31017    if (lastStatement instanceof ReturnStatement) {
31018      statements[statements.length - 1] = new ReturnStatement(invokeInstruction(lastStatement.value.sourceSpan, Identifiers.resetView, [lastStatement.value]));
31019    } else {
31020      statements.push(new ExpressionStatement(invokeInstruction(null, Identifiers.resetView, [])));
31021    }
31022  }
31023  const eventName = type === 1 /* ParsedEventType.Animation */ ? prepareSyntheticListenerName(name, phase) : name;
31024  const fnName = handlerName && sanitizeIdentifier(handlerName);
31025  const fnArgs = [];
31026  if (implicitReceiverAccesses.has(eventArgumentName)) {
31027    fnArgs.push(new FnParam(eventArgumentName, DYNAMIC_TYPE));
31028  }
31029  const handlerFn = fn(fnArgs, statements, INFERRED_TYPE, null, fnName);
31030  const params = [literal(eventName), handlerFn];
31031  if (target) {
31032    params.push(literal(false),
31033    // `useCapture` flag, defaults to `false`
31034    importExpr(GLOBAL_TARGET_RESOLVERS.get(target)));
31035  }
31036  return params;
31037}
31038function createComponentDefConsts() {
31039  return {
31040    prepareStatements: [],
31041    constExpressions: [],
31042    i18nVarRefsCache: new Map()
31043  };
31044}
31045class TemplateData {
31046  constructor(name, index, scope, visitor) {
31047    this.name = name;
31048    this.index = index;
31049    this.scope = scope;
31050    this.visitor = visitor;
31051  }
31052  getConstCount() {
31053    return this.visitor.getConstCount();
31054  }
31055  getVarCount() {
31056    return this.visitor.getVarCount();
31057  }
31058}
31059class TemplateDefinitionBuilder {
31060  constructor(constantPool, parentBindingScope, level = 0, contextName, i18nContext, templateIndex, templateName, _namespace, relativeContextFilePath, i18nUseExternalIds, deferBlocks, elementLocations, allDeferrableDepsFn, _constants = createComponentDefConsts()) {
31061    this.constantPool = constantPool;
31062    this.level = level;
31063    this.contextName = contextName;
31064    this.i18nContext = i18nContext;
31065    this.templateIndex = templateIndex;
31066    this.templateName = templateName;
31067    this._namespace = _namespace;
31068    this.i18nUseExternalIds = i18nUseExternalIds;
31069    this.deferBlocks = deferBlocks;
31070    this.elementLocations = elementLocations;
31071    this.allDeferrableDepsFn = allDeferrableDepsFn;
31072    this._constants = _constants;
31073    this._dataIndex = 0;
31074    this._bindingContext = 0;
31075    this._prefixCode = [];
31076    /**
31077     * List of callbacks to generate creation mode instructions. We store them here as we process
31078     * the template so bindings in listeners are resolved only once all nodes have been visited.
31079     * This ensures all local refs and context variables are available for matching.
31080     */
31081    this._creationCodeFns = [];
31082    /**
31083     * List of callbacks to generate update mode instructions. We store them here as we process
31084     * the template so bindings are resolved only once all nodes have been visited. This ensures
31085     * all local refs and context variables are available for matching.
31086     */
31087    this._updateCodeFns = [];
31088    /** Index of the currently-selected node. */
31089    this._currentIndex = 0;
31090    /** Temporary variable declarations generated from visiting pipes, literals, etc. */
31091    this._tempVariables = [];
31092    /**
31093     * Temporary variable used to store state between control flow instructions.
31094     * Should be accessed via the `allocateControlFlowTempVariable` method.
31095     */
31096    this._controlFlowTempVariable = null;
31097    /**
31098     * List of callbacks to build nested templates. Nested templates must not be visited until
31099     * after the parent template has finished visiting all of its nodes. This ensures that all
31100     * local ref bindings in nested templates are able to find local ref values if the refs
31101     * are defined after the template declaration.
31102     */
31103    this._nestedTemplateFns = [];
31104    // i18n context local to this template
31105    this.i18n = null;
31106    // Number of slots to reserve for pureFunctions
31107    this._pureFunctionSlots = 0;
31108    // Number of binding slots
31109    this._bindingSlots = 0;
31110    // Projection slots found in the template. Projection slots can distribute projected
31111    // nodes based on a selector, or can just use the wildcard selector to match
31112    // all nodes which aren't matching any selector.
31113    this._ngContentReservedSlots = [];
31114    // Number of non-default selectors found in all parent templates of this template. We need to
31115    // track it to properly adjust projection slot index in the `projection` instruction.
31116    this._ngContentSelectorsOffset = 0;
31117    // Expression that should be used as implicit receiver when convert
31117ing template
31118    // expressions to output AST.
31119    this._implicitReceiverExpr = null;
31120    // These should be handled in the template or element directly.
31121    this.visitReference = invalid;
31122    this.visitVariable = invalid;
31123    this.visitTextAttribute = invalid;
31124    this.visitBoundAttribute = invalid;
31125    this.visitBoundEvent = invalid;
31126    this.visitDeferredTrigger = invalid;
31127    this.visitDeferredBlockError = invalid;
31128    this.visitDeferredBlockLoading = invalid;
31129    this.visitDeferredBlockPlaceholder = invalid;
31130    this.visitIfBlockBranch = invalid;
31131    this.visitSwitchBlockCase = invalid;
31132    this.visitForLoopBlockEmpty = invalid;
31133    this.visitUnknownBlock = invalid;
31134    this._bindingScope = parentBindingScope.nestedScope(level);
31135    // Turn the relative context file path into an identifier by replacing non-alphanumeric
31136    // characters with underscores.
31137    this.fileBasedI18nSuffix = relativeContextFilePath.replace(/[^A-Za-z0-9]/g, '_') + '_';
31138    this._valueConverter = new ValueConverter(constantPool, () => this.allocateDataSlot(), numSlots => this.allocatePureFunctionSlots(numSlots), (name, localName, slot, value) => {
31139      this._bindingScope.set(this.level, localName, value);
31140      this.creationInstruction(null, Identifiers.pipe, [literal(slot), literal(name)]);
31141    });
31142  }
31143  buildTemplateFunction(nodes, variables, ngContentSelectorsOffset = 0, i18n, variableAliases) {
31144    this._ngContentSelectorsOffset = ngContentSelectorsOffset;
31145    if (this._namespace !== Identifiers.namespaceHTML) {
31146      this.creationInstruction(null, this._namespace);
31147    }
31148    // Create variable bindings
31149    variables.forEach(v => {
31150      const alias = variableAliases?.[v.name];
31151      this.registerContextVariables(v.name, v.value);
31152      if (alias) {
31153        this.registerContextVariables(alias, v.value);
31154      }
31155    });
31156    // Initiate i18n context in case:
31157    // - this template has parent i18n context
31158    // - or the template has i18n meta associated with it,
31159    //   but it's not initiated by the Element (e.g. <ng-template i18n>)
31160    const initI18nContext = this.i18nContext || isI18nRootNode(i18n) && !isSingleI18nIcu(i18n) && !(isSingleElementTemplate(nodes) && nodes[0].i18n === i18n);
31161    const selfClosingI18nInstruction = hasTextChildrenOnly(nodes);
31162    if (initI18nContext) {
31163      this.i18nStart(null, i18n, selfClosingI18nInstruction);
31164    }
31165    // This is the initial pass through the nodes of this template. In this pass, we
31166    // queue all creation mode and update mode instructions for generation in the second
31167    // pass. It's necessary to separate the passes to ensure local refs are defined before
31168    // resolving bindings. We also count bindings in this pass as we walk bound expressions.
31169    visitAll$1(this, nodes);
31170    // Add total binding count to pure function count so pure function instructions are
31171    // generated with the correct slot offset when update instructions are processed.
31172    this._pureFunctionSlots += this._bindingSlots;
31173    // Pipes are walked in the first pass (to enqueue `pipe()` creation instructions and
31174    // `pipeBind` update instructions), so we have to update the slot offsets manually
31175    // to account for bindings.
31176    this._valueConverter.updatePipeSlotOffsets(this._bindingSlots);
31177    // Nested templates must be processed before creation instructions so template()
31178    // instructions can be generated with the correct internal const count.
31179    this._nestedTemplateFns.forEach(buildTemplateFn => buildTemplateFn());
31180    // Output the `projectionDef` instruction when some `<ng-content>` tags are present.
31181    // The `projectionDef` instruction is only emitted for the component template and
31182    // is skipped for nested templates (<ng-template> tags).
31183    if (this.level === 0 && this._ngContentReservedSlots.length) {
31184      const parameters = [];
31185      // By default the `projectionDef` instructions creates one slot for the wildcard
31186      // selector if no parameters are passed. Therefore we only want to allocate a new
31187      // array for the projection slots if the default projection slot is not sufficient.
31188      if (this._ngContentReservedSlots.length > 1 || this._ngContentReservedSlots[0] !== '*') {
31189        const r3ReservedSlots = this._ngContentReservedSlots.map(s => s !== '*' ? parseSelectorToR3Selector(s) : s);
31190        parameters.push(this.constantPool.getConstLiteral(asLiteral(r3ReservedSlots), true));
31191      }
31192      // Since we accumulate ngContent selectors while processing template elements,
31193      // we *prepend* `projectionDef` to creation instructions block, to put it before
31194      // any `projection` instructions
31195      this.creationInstruction(null, Identifiers.projectionDef, parameters, /* prepend */true);
31196    }
31197    if (initI18nContext) {
31198      this.i18nEnd(null, selfClosingI18nInstruction);
31199    }
31200    // Generate all the creation mode instructions (e.g. resolve bindings in listeners)
31201    const creationStatements = getInstructionStatements(this._creationCodeFns);
31202    // Generate all the update mode instructions (e.g. resolve property or text bindings)
31203    const updateStatements = getInstructionStatements(this._updateCodeFns);
31204    //  Variable declaration must occur after binding resolution so we can generate context
31205    //  instructions that build on each other.
31206    // e.g. const b = nextContext().$implicit(); const b = nextContext();
31207    const creationVariables = this._bindingScope.viewSnapshotStatements();
31208    const updateVariables = this._bindingScope.variableDeclarations().concat(this._tempVariables);
31209    const creationBlock = creationStatements.length > 0 ? [renderFlagCheckIfStmt(1 /* core.RenderFlags.Create */, creationVariables.concat(creationStatements))] : [];
31210    const updateBlock = updateStatements.length > 0 ? [renderFlagCheckIfStmt(2 /* core.RenderFlags.Update */, updateV
31210ariables.concat(updateStatements))] : [];
31211    return fn(
31212    // i.e. (rf: RenderFlags, ctx: any)
31213    [new FnParam(RENDER_FLAGS, NUMBER_TYPE), new FnParam(CONTEXT_NAME, null)], [
31214    // Temporary variable declarations for query refresh (i.e. let _t: any;)
31215    ...this._prefixCode,
31216    // Creating mode (i.e. if (rf & RenderFlags.Create) { ... })
31217    ...creationBlock,
31218    // Binding and refresh mode (i.e. if (rf & RenderFlags.Update) {...})
31219    ...updateBlock], INFERRED_TYPE, null, this.templateName);
31220  }
31221  // LocalResolver
31222  getLocal(name) {
31223    return this._bindingScope.get(name);
31224  }
31225  // LocalResolver
31226  notifyImplicitReceiverUse() {
31227    this._bindingScope.notifyImplicitReceiverUse();
31228  }
31229  // LocalResolver
31230  maybeRestoreView() {
31231    this._bindingScope.maybeRestoreView();
31232  }
31233  i18nTranslate(message, params = {}, ref, transformFn) {
31234    const _ref = ref || this.i18nGenerateMainBlockVar();
31235    // Closure Compiler requires const names to start with `MSG_` but disallows any other const to
31236    // start with `MSG_`. We define a variable starting with `MSG_` just for the `goog.getMsg` call
31237    const closureVar = this.i18nGenerateClosureVar(message.id);
31238    const statements = getTranslationDeclStmts(message, _ref, closureVar, params, transformFn);
31239    this._constants.prepareStatements.push(...statements);
31240    return _ref;
31241  }
31242  registerContextVariables(name, value) {
31243    const scopedName = this._bindingScope.freshReferenceName();
31244    const retrievalLevel = this.level;
31245    const isDirect = value === DIRECT_CONTEXT_REFERENCE;
31246    const lhs = variable(name + scopedName);
31247    this._bindingScope.set(retrievalLevel, name, scope => {
31248      // If we're at the top level and we're referring to the context variable directly, we
31249      // can do so through the implicit receiver, instead of renaming it. Note that this does
31250      // not apply to listeners, because they need to restore the context.
31251      return isDirect && scope.bindingLevel === retrievalLevel && !scope.isListenerScope() ? variable(CONTEXT_NAME) : lhs;
31252    }, 1 /* DeclarationPriority.CONTEXT */, (scope, relativeLevel) => {
31253      let rhs;
31254      if (scope.bindingLevel === retrievalLevel) {
31255        if (scope.isListenerScope() && scope.hasRestoreViewVariable()) {
31256          // e.g. restoredCtx.
31257          // We have to get the context from a view reference, if one is available, because
31258          // the context that was passed in during creation may not be correct anymore.
31259          // For more information see: https://github.com/angular/angular/pull/40360.
31260          rhs = variable(RESTORED_VIEW_CONTEXT_NAME);
31261          scope.notifyRestoredViewContextUse();
31262        } else if (isDirect) {
31263          // If we have a direct read of the context at the top level we don't need to
31264          // declare any variables and we can refer to it directly.
31265          return [];
31266        } else {
31267          // e.g. ctx
31268          rhs = variable(CONTEXT_NAME);
31269        }
31270      } else {
31271        const sharedCtxVar = scope.getSharedContextName(retrievalLevel);
31272        // e.g. ctx_r0   OR  x(2);
31273        rhs = sharedCtxVar ? sharedCtxVar : generateNextContextExpr(relativeLevel);
31274      }
31275      return [
31276      // e.g. const $items$ = x(2) for direct context references and
31277      // const $item$ = x(2).$implicit for indirect ones.
31278      lhs.set(isDirect ? rhs : rhs.prop(value || IMPLICIT_REFERENCE)).toConstDecl()];
31279    });
31280  }
31281  i18nAppendBindings(expressions) {
31282    if (expressions.length > 0) {
31283      expressions.forEach(expression => this.i18n.appendBinding(expression));
31284    }
31285  }
31286  i18nBindProps(props) {
31287    const bound = {};
31288    Object.keys(props).forEach(key => {
31289      const prop = props[key];
31290      if (prop instanceof Text$3) {
31291        bound[key] = literal(prop.value);
31292      } else {
31293        const value = prop.value.visit(this._valueConverter);
31294        this.allocateBindingSlots(value);
31295        if (value instanceof Interpolation$1) {
31296          const {
31297            strings,
31298            expressions
31299          } = value;
31300          const {
31301            id,
31302            bindings
31303          } = this.i18n;
31304          const label = assembleI18nBoundString(strings, bindings.size, id);
31305          this.i18nAppendBindings(expressions);
31306          bound[key] = literal(label);
31307        }
31308      }
31309    });
31310    return bound;
31311  }
31312  // Generates top level vars for i18n blocks (i.e. `i18n_N`).
31313  i18nGenerateMainBlockVar() {
31314    return variable(this.constantPool.uniqueName(TRANSLATION_VAR_PREFIX$1));
31315  }
31316  // Generates vars with Closure-specific names for i18n blocks (i.e. `MSG_XXX`).
31317  i18nGenerateClosureVar(messageId) {
31318    let name;
31319    const suffix = this.fileBasedI18nSuffix.toUpperCase();
31320    if (this.i18nUseExternalIds) {
31321      const prefix = getTranslationConstPrefix(`EXTERNAL_`);
31322      const uniqueSuffix = this.constantPool.uniqueName(suffix);
31323      name = `${prefix}${sanitizeIdentifier(messageId)}$$${uniqueSuffix}`;
31324    } else {
31325      const prefix = getTranslationConstPrefix(suffix);
31326      name = this.constantPool.uniqueName(prefix);
31327    }
31328    return variable(name);
31329  }
31330  i18nUpdateRef(context) {
31331    const {
31332      icus,
31333      meta,
31334      isRoot,
31335      isResolved,
31336      isEmitted
31337    } = context;
31338    if (isRoot && isResolved && !isEmitted && !isSingleI18nIcu(meta)) {
31339      context.isEmitted = true;
31340      const placeholders = context.getSerializedPlaceholders();
31341      let icuMapping = {};
31342      let params = placeholders.size ? placeholdersToParams(placeholders) : {};
31343      if (icus.size) {
31344        icus.forEach((refs, key) => {
31345          if (refs.length === 1) {
31346            // if we have one ICU defined for a given
31347            // placeholder - just output its reference
31348            params[key] = refs[0];
31349          } else {
31350            // ... otherwise we need to activate post-processing
31351            // to replace ICU placeholders with proper values
31352            const placeholder = wrapI18nPlaceholder(`${I18N_ICU_MAPPING_PREFIX$1}${key}`);
31353            params[key] = literal(placeholder);
31354            icuMapping[key] = literalArr(refs);
31355          }
31356        });
31357      }
31358      // translation requires post processing in 2 cases:
31359      // - if we have placeholders with multiple values (ex. `START_DIV`: [�#1�, �#2�, ...])
31360      // - if we have multiple ICUs that refer to the same placeholder name
31361      const needsPostprocessing = Array.from(placeholders.values()).some(value => value.length > 1) || Object.keys(icuMapping).length;
31362      let transformFn;
31363      if (needsPostprocessing) {
31364        transformFn = raw => {
31365          const args = [raw];
31366          if (Object.keys(icuMapping).length) {
31367            args.push(mapLiteral(icuMapping, true));
31368          }
31369          return invokeInstruction(null, Identifiers.i18nPostprocess, args);
31370        };
31371      }
31372      this.i18nTranslate(meta, params, context.ref, transformFn);
31373    }
31374  }
31375  i18nStart(span = null, meta, selfClosing) {
31376    const index = this.allocateDataSlot();
31377    this.i18n = this.i18nContext ? this.i18nContext.forkChildContext(index, this.templateIndex, meta) : new I18nContext(index, this.i18nGenerateMainBlockVar(), 0, this.templateIndex, meta);
31378    // generate i18nStart instruction
31379    const {
31380      id,
31381      ref
31382    } = this.i18n;
31383    const params = [literal(index), this.addToConsts(ref)];
31384    if (id > 0) {
31385      // do not push 3rd argument (sub-block id)
31386      // into i18nStart call for top level i18n context
31387      params.push(literal(id));
31388    }
31389    this.creationInstruction(span, selfClosing ? Identifiers.i18n : Identifiers.i18nStart, params);
31390  }
31391  i18nEnd(span = null, selfClosing) {
31392    if (!this.i18n) {
31393      throw new Error('i18nEnd is executed with no i18n context present');
31394    }
31395    if (this.i18nContext) {
31396      this.i18nContext.reconcileChildContext(this.i18n);
31397      this.i18nUpdateRef(this.i18nContext);
31398    } else {
31399      this.i18nUpdateRef(this.i18n);
31400    }
31401    // setup accumulated bindings
31402    const {
31403      index,
31404      bindings
31405    } = this.i18n;
31406    if (bindings.size) {
31407      for (const binding of bindings) {
31408        // for i18n block, advance to the most recent element index (by taking the current number of
31409        // elements and subtracting one) before invoking `i18nExp` instructions, to make sure the
31410        // necessary lifecycle hooks of components/directives are properly flushed.
31411        this.updateInstructionWithAdvance(this.getConstCount() - 1, span, Identifiers.i18nExp, () => this.convertPropertyBinding(binding));
31412      }
31413      this.updateInstruction(span, Identifiers.i18nApply, [literal(index)]);
31414    }
31415    if (!selfClosing) {
31416      this.creationInstruction(span, Identifiers.i18nEnd);
31417    }
31418    this.i18n = null; // reset local i18n context
31419  }
31420  i18nAttributesInstruction(nodeIndex, attrs, sourceSpan) {
31421    let hasBindings = false;
31422    const i18nAttrArgs = [];
31423    attrs.forEach(attr => {
31424      const message = attr.i18n;
31425      const converted = attr.value.visit(this._valueConverter);
31426      this.allocateBindingSlots(converted);
31427      if (converted instanceof Interpolation$1) {
31428        const placeholders = assembleBoundTextPlaceholders(message);
31429        const params = placeholdersToParams(placeholders);
31430        i18nAttrArgs.push(literal(attr.name), this.i18nTranslate(message, params));
31431        converted.expressions.forEach(expression => {
31432          hasBindings = true;
31433          this.updateInstructionWithAdvance(nodeIndex, sourceSpan, Identifiers.i18nExp, () => this.convertPropertyBinding(expression));
31434        });
31435      }
31436    });
31437    if (i18nAttrArgs.length > 0) {
31438      const index = literal(this.allocateDataSlot());
31439      const constIndex = this.addToConsts(literalArr(i18nAttrArgs));
31440      this.creationInstruction(sourceSpan, Identifiers.i18nAttributes, [index, constIndex]);
31441      if (hasBindings) {
31442        this.updateInstruction(sourceSpan, Identifiers.i18nApply, [index]);
31443      }
31444    }
31445  }
31446  getNamespaceInstruction(namespaceKey) {
31447    switch (namespaceKey) {
31448      case 'math':
31449        return Identifiers.namespaceMathML;
31450      case 'svg':
31451        return Identifiers.namespaceSVG;
31452      default:
31453        return Identifiers.namespaceHTML;
31454    }
31455  }
31456  addNamespaceInstruction(nsInstruction, element) {
31457    this._namespace = nsInstruction;
31458    this.creationInstruction(element.startSourceSpan, nsInstruction);
31459  }
31460  /**
31461   * Adds an update instruction for an interpolated property or attribute, such as
31462   * `prop="{{value}}"` or `attr.title="{{value}}"`
31463   */
31464  interpolatedUpdateInstruction(instruction, elementIndex, attrName, input, value, params) {
31465    this.updateInstructionWithAdvance(elementIndex, input.sourceSpan, instruction, () => [literal(attrName), ...this.getUpdateInstructionArguments(value), ...params]);
31466  }
31467  visitContent(ngContent) {
31468    const slot = this.allocateDataSlot();
31469    const projectionSlotIdx = this._ngContentSelectorsOffset + this._ngContentReservedSlots.length;
31470    const parameters = [literal(slot)];
31471    this._ngContentReservedSlots.push(ngContent.selector);
31472    const nonContentSelectAttributes = ngContent.attributes.filter(attr => attr.name.toLowerCase() !== NG_CONTENT_SELECT_ATTR);
31473    const attributes = this.getAttributeExpressions(ngContent.name, nonContentSelectAttributes, [], []);
31474    if (attributes.length > 0) {
31475      parameters.push(literal(projectionSlotIdx), literalArr(attributes));
31476    } else if (projectionSlotIdx !== 0) {
31477      parameters.push(literal(projectionSlotIdx));
31478    }
31479    this.creationInstruction(ngContent.sourceSpan, Identifiers.projection, parameters);
31480    if (this.i18n) {
31481      this.i18n.appendProjection(ngContent.i18n, slot);
31482    }
31483  }
31484  visitElement(element) {
31485    const elementIndex = this.allocateDataSlot();
31486    const stylingBuilder = new StylingBuilder(null);
31487    this.elementLocations.set(element, {
31488      index: elementIndex,
31489      level: this.level
31490    });
31491    let isNonBindableMode = false;
31492    const isI18nRootElement = isI18nRootNode(element.i18n) && !isSingleI18nIcu(element.i18n);
31493    const outputAttrs = [];
31494    const [namespaceKey, elementName] = splitNsName(element.name);
31495    const isNgContainer$1 = isNgContainer(element.name);
31496    // Handle styling, i18n, ngNonBindable attributes
31497    for (const attr of element.attributes) {
31498      const {
31499        name,
31500        value
31501      } = attr;
31502      if (name === NON_BINDABLE_ATTR) {
31503        isNonBindableMode = true;
31504      } else if (name === 'style') {
31505        stylingBuilder.registerStyleAttr(value);
31506      } else if (name === 'class') {
31507        stylingBuilder.registerClassAttr(value);
31508      } else {
31509        outputAttrs.push(attr);
31510      }
31511    }
31512    // Regular element or ng-container creation mode
31513    const parameters = [literal(elementIndex)];
31514    if (!isNgContainer$1) {
31515      parameters.push(literal(elementName));
31516    }
31517    // Add the attributes
31518    const allOtherInputs = [];
31519    const boundI18nAttrs = [];
31520    element.inputs.forEach(input => {
31521      const stylingInputWasSet = stylingBuilder.registerBoundInput(input);
31522      if (!stylingInputWasSet) {
31523        if ((input.type === 0 /* BindingType.Property */ || input.type === 5 /* BindingType.TwoWay */) && input.i18n) {
31524          boundI18nAttrs.push(input);
31525        } else {
31526          allOtherInputs.push(input);
31527        }
31528      }
31529    });
31530    // add attributes for directive and projection matching purposes
31531    const attributes = this.getAttributeExpressions(element.name, outputAttrs, allOtherInputs, element.outputs, stylingBuilder, [], boundI18nAttrs);
31532    parameters.push(this.addAttrsToConsts(attributes));
31533    // local refs (ex.: <div #foo #bar="baz">)
31534    const refs = this.prepareRefsArray(element.references);
31535    parameters.push(this.addToConsts(refs));
31536    const wasInNamespace = this._namespace;
31537    const currentNamespace = this.getNamespaceInstruction(namespaceKey);
31538    // If the namespace is changing now, include an instruction to change it
31539    // during element creation.
31540    if (currentNamespace !== wasInNamespace) {
31541      this.addNamespaceInstruction(currentNamespace, element);
31542    }
31543    if (this.i18n) {
31544      this.i18n.appendElement(element.i18n, elementIndex);
31545    }
31546    // Note that we do not append text node instructions and ICUs inside i18n section,
31547    // so we exclude them while calculating whether current element has children
31548    const hasChildren = !isI18nRootElement && this.i18n ? !hasTextChildrenOnly(element.children) : element.children.length > 0;
31549    const createSelfClosingInstruction = !stylingBuilder.hasBindingsWithPipes && element.outputs.length === 0 && boundI18nAttrs.length === 0 && !hasChildren;
31550    const createSelfClosingI18nInstruction = !createSelfClosingInstruction && hasTextChildrenOnly(element.children);
31551    if (createSelfClosingInstruction) {
31552      this.creationInstruction(element.sourceSpan, isNgContainer$1 ? Identifiers.elementContainer : Identifiers.element, trimTrailingNulls(parameters));
31553    } else {
31554      this.creationInstruction(element.startSourceSpan, isNgContainer$1 ? Identifiers.elementContainerStart : Identifiers.elementStart, trimTrailingNulls(parameters));
31555      if (isNonBindableMode) {
31556        this.creationInstruction(element.startSourceSpan, Identifiers.disableBindings);
31557      }
31558      if (boundI18nAttrs.length > 0) {
31559        this.i18nAttributesInstruction(elementIndex, boundI18nAttrs, element.startSourceSpan ?? element.sourceSpan);
31560      }
31561      // Generate Listeners (outputs)
31562      if (element.outputs.length > 0) {
31563        for (const outputAst of element.outputs) {
31564          this.creationInstruction(outputAst.sourceSpan, outputAst.type === 2 /* ParsedEventType.TwoWay */ ? Identifiers.twoWayListener : Identifiers.listener, this.prepareListenerParameter(element.name, outputAst, elementIndex));
31565        }
31566      }
31567      // Note: it's important to keep i18n/i18nStart instructions after i18nAttributes and
31568      // listeners, to make sure i18nAttributes instruction targets current element at runtime.
31569      if (isI18nRootElement) {
31570        this.i18nStart(element.startSourceSpan, element.i18n, createSelfClosingI18nInstruction);
31571      }
31572    }
31573    // the code here will collect all update-level styling instructions and add them to the
31574    // update block of the template function AOT code. Instructions like `styleProp`,
31575    // `styleMap`, `classMap`, `classProp`
31576    // are all generated and assigned in the code below.
31577    const stylingInstructions = stylingBuilder.buildUpdateLevelInstructions(this._valueConverter);
31578    const limit = stylingInstructions.length - 1;
31579    for (let i = 0; i <= limit; i++) {
31580      const instruction = stylingInstructions[i];
31581      this._bindingSlots += this.processStylingUpdateInstruction(elementIndex, instruction);
31582    }
31583    // the reason why `undefined` is used is because the renderer understands this as a
31584    // special value to symbolize that there is no RHS to this binding
31585    // TODO (matsko): revisit this once FW-959 is approached
31586    const emptyValueBindInstruction = literal(undefined);
31587    const propertyBindings = [];
31588    const attributeBindings = [];
31589    // Generate element input bindings
31590    allOtherInputs.forEach(input => {
31591      const inputType = input.type;
31592      if (inputType === 4 /* BindingType.Animation */) {
31593        const value = input.value.visit(this._valueConverter);
31594        // animation bindings can be presented in the following formats:
31595        // 1. [@binding]="fooExp"
31596        // 2. [@binding]="{value:fooExp, params:{...}}"
31597        // 3. [@binding]
31598        // 4. @binding
31599        // All formats will be valid for when a synthetic binding is created.
31600        // The reasoning for this is because the renderer should get each
31601        // synthetic binding value in the order of the array that they are
31602        // defined in...
31603        const hasValue = value instanceof LiteralPrimitive ? !!value.value : true;
31604        this.allocateBindingSlots(value);
31605        propertyBindings.push({
31606          span: input.sourceSpan,
31607          reference: Identifiers.property,
31608          paramsOrFn: getBindingFunctionParams(() => hasValue ? this.convertPropertyBinding(value) : emptyValueBindInstruction, prepareSyntheticPropertyName(input.name))
31609        });
31610      } else {
31611        // we must skip attributes with associated i18n context, since these attributes are handled
31612        // separately and corresponding `i18nExp` and `i18nApply` instructions will be generated
31613        if (input.i18n) return;
31614        const value = input.value.visit(this._valueConverter);
31615        if (value !== undefined) {
31616          const params = [];
31617          const [attrNamespace, attrName] = splitNsName(input.name);
31618          const isAttributeBinding = inputType === 1 /* BindingType.Attribute */;
31619          let sanitizationRef = resolveSanitizationFn(input.securityContext, isAttributeBinding);
31620          if (!sanitizationRef) {
31621            // If there was no sanitization function found based on the security context
31622            // of an attribute/property - check whether this attribute/property is
31623            // one of the security-sensitive <iframe> attributes (and that the current
31624            // element is actually an <iframe>).
31625            if (isIframeElement(element.name) && isIframeSecuritySensitiveAttr(input.name)) {
31626              sanitizationRef = importExpr(Identifiers.validateIframeAttribute);
31627            }
31628          }
31629          if (sanitizationRef) {
31630            params.push(sanitizationRef);
31631          }
31632          if (attrNamespace) {
31633            const namespaceLiteral = literal(attrNamespace);
31634            if (sanitizationRef) {
31635              params.push(namespaceLiteral);
31636            } else {
31637              // If there wasn't a sanitization ref, we need to add
31638              // an extra param so that we can pass in the namespace.
31639              params.push(literal(null), namespaceLiteral);
31640            }
31641          }
31642          this.allocateBindingSlots(value);
31643          // Note: we don't separate two-way property bindings and regular ones,
31644          // because their assignment order needs to be maintained.
31645          if (inputType === 0 /* BindingType.Property */ || inputType === 5 /* BindingType.TwoWay */) {
31646            if (value instanceof Interpolation$1) {
31647              // prop="{{value}}" and friends
31648              this.interpolatedUpdateInstruction(getPropertyInterpolationExpression(value), elementIndex, attrName, input, value, params);
31649            } else {
31650              // [prop]="value"
31651              // Collect all the properties so that we can chain into a single function at the end.
31652              propertyBindings.push({
31653                span: input.sourceSpan,
31654                reference: inputType === 5 /* BindingType.TwoWay */ ? Identifiers.twoWayProperty : Identifiers.property,
31655                paramsOrFn: getBindingFunctionParams(() => this.convertPropertyBinding(value), attrName, params)
31656              });
31657            }
31658          } else if (inputType === 1 /* BindingType.Attribute */) {
31659            if (value instanceof Interpolation$1 && getInterpolationArgsLength(value) > 1) {
31660              // attr.name="text{{value}}" and friends
31661              this.interpolatedUpdateInstruction(getAttributeInterpolationExpression(value), elementIndex, attrName, input, value, params);
31662            } else {
31663              const boundValue = value instanceof Interpolation$1 ? value.expressions[0] : value;
31664              // [attr.name]="value" or attr.name="{{value}}"
31665              // Collect the attribute bindings so that they can be chained at the end.
31666              attributeBindings.push({
31667                span: input.sourceSpan,
31668                paramsOrFn: getBindingFunctionParams(() => this.convertPropertyBinding(boundValue), attrName, params)
31669              });
31670            }
31671          } else {
31672            // class prop
31673            this.updateInstructionWithAdvance(elementIndex, input.sourceSpan, Identifiers.classProp, () => {
31674              return [literal(elementIndex), literal(attrName), this.convertPropertyBinding(value), ...params];
31675            });
31676          }
31677        }
31678      }
31679    });
31680    for (const propertyBinding of propertyBindings) {
31681      this.updateInstructionWithAdvance(elementIndex, propertyBinding.span, propertyBinding.reference, propertyBinding.paramsOrFn);
31682    }
31683    for (const attributeBinding of attributeBindings) {
31684      this.updateInstructionWithAdvance(elementIndex, attributeBinding.span, Identifiers.attribute, attributeBinding.paramsOrFn);
31685    }
31686    // Traverse element child nodes
31687    visitAll$1(this, element.children);
31688    if (!isI18nRootElement && this.i18n) {
31689      this.i18n.appendElement(element.i18n, elementIndex, true);
31690    }
31691    if (!createSelfClosingInstruction) {
31692      // Finish element construction mode.
31693      const span = element.endSourceSpan ?? element.sourceSpan;
31694      if (isI18nRootElement) {
31695        this.i18nEnd(span, createSelfClosingI18nInstruction);
31696      }
31697      if (isNonBindableMode) {
31698        this.creationInstruction(span, Identifiers.enableBindings);
31699      }
31700      this.creationInstruction(span, isNgContainer$1 ? Identifiers.elementContainerEnd : Identifiers.elementEnd);
31701    }
31702  }
31703  prepareEmbeddedTemplateFn(children, contextNameSuffix, variables = [], i18nMeta, variableAliases) {
31704    const index = this.allocateDataSlot();
31705    if (this.i18n && i18nMeta) {
31706      if (i18nMeta instanceof BlockPlaceholder) {
31707        this.i18n.appendBlock(i18nMeta, index);
31708      } else {
31709        this.i18n.appendTemplate(i18nMeta, index);
31710      }
31711    }
31712    const contextName = `${this.contextName}${contextNameSuffix}_${index}`;
31713    // Note: For the unique name, we don't include an unique suffix, unless really needed.
31714    // This keeps the generated output more clean as most of the time, we don't expect conflicts.
31715    const name = this.constantPool.uniqueName(`${contextName}_Template`, /** alwaysIncludeSuffix */false);
31716    // Create the template function
31717    const visitor = new TemplateDefinitionBuilder(this.constantPool, this._bindingScope, this.level + 1, contextName, this.i18n, index, name, this._namespace, this.fileBasedI18nSuffix, this.i18nUseExternalIds, this.deferBlocks, this.elementLocations, this.allDeferrableDepsFn, this._constants);
31718    // Nested templates must not be visited until after their parent templates have completed
31719    // processing, so they are queued here until after the initial pass. Otherwise, we wouldn't
31720    // be able to support bindings in nested templates to local refs that occur after the
31721    // template definition. e.g. <div *ngIf="showing">{{ foo }}</div>  <div #foo></div>
31722    this._nestedTemplateFns.push(() => {
31723      const templateFunctionExpr = visitor.buildTemplateFunction(children, variables, this._ngContentReservedSlots.length + this._ngContentSelectorsOffset, i18nMeta, variableAliases);
31724      this.constantPool.statements.push(templateFunctionExpr.toDeclStmt(name));
31725      if (visitor._ngContentReservedSlots.length) {
31726        this._ngContentReservedSlots.push(...visitor._ngContentReservedSlots);
31727      }
31728    });
31729    return new TemplateData(name, index, visitor._bindingScope, visitor);
31730  }
31731  createEmbeddedTemplateFn(tagName, children, contextNameSuffix, sourceSpan, variables = [], attrsExprs, references, i18n) {
31732    const data = this.prepareEmbeddedTemplateFn(children, contextNameSuffix, variables, i18n);
31733    const parameters = [literal(data.index), variable(data.name), literal(tagName), this.addAttrsToConsts(attrsExprs || null)];
31734    // local refs (ex.: <ng-template #foo>)
31735    if (references && references.length > 0) {
31736      const refs = this.prepareRefsArray(references);
31737      parameters.push(this.addToConsts(refs));
31738      parameters.push(importExpr(Identifiers.templateRefExtractor));
31739    }
31740    // e.g. template(1, MyComp_Template_1)
31741    this.creationInstruction(sourceSpan, Identifiers.templateCreate, () => {
31742      parameters.splice(2, 0, literal(data.getConstCount()), literal(data.getVarCount()));
31743      return trimTrailingNulls(parameters);
31744    });
31745    return data.index;
31746  }
31747  visitTemplate(template) {
31748    // We don't care about the tag's namespace here, because we infer
31749    // it based on the parent nodes inside the template instruction.
31750    const tagNameWithoutNamespace = template.tagName ? splitNsName(template.tagName)[1] : template.tagName;
31751    const contextNameSuffix = template.tagName ? '_' + sanitizeIdentifier(template.tagName) : '';
31752    // prepare attributes parameter (including attributes used for directive matching)
31753    const attrsExprs = this.getAttributeExpressions(NG_TEMPLATE_TAG_NAME, template.attributes, template.inputs, template.outputs, undefined /* styles */, template.templateAttrs);
31754    const templateIndex = this.createEmbeddedTemplateFn(tagNameWithoutNamespace, template.children, contextNameSuffix, template.sourceSpan, template.variables, attrsExprs, template.references, template.i18n);
31755    // handle property bindings e.g. ɵɵproperty('ngForOf', ctx.items), et al;
31756    this.templatePropertyBindings(templateIndex, template.templateAttrs);
31757    // Only add normal input/output binding instructions on explicit <ng-template> elements.
31758    if (tagNameWithoutNamespace === NG_TEMPLATE_TAG_NAME) {
31759      const [i18nInputs, inputs] = partitionArray(template.inputs, hasI18nMeta);
31760      // Add i18n attributes that may act as inputs to directives. If such attributes are present,
31761      // generate `i18nAttributes` instruction. Note: we generate it only for explicit <ng-template>
31762      // elements, in case of inline templates, corresponding instructions will be generated in the
31763      // nested template function.
31764      if (i18nInputs.length > 0) {
31765        this.i18nAttributesInstruction(templateIndex, i18nInputs, template.startSourceSpan ?? template.sourceSpan);
31766      }
31767      // Add the input bindings
31768      if (inputs.length > 0) {
31769        this.templatePropertyBindings(templateIndex, inputs);
31770      }
31771      // Generate listeners for directive output
31772      for (const outputAst of template.outputs) {
31773        this.creationInstruction(outputAst.sourceSpan, outputAst.type === 2 /* ParsedEventType.TwoWay */ ? Identifiers.twoWayListener : Identifiers.listener, this.prepareListenerParameter('ng_template', outputAst, templateIndex));
31774      }
31775    }
31776  }
31777  visitBoundText(text) {
31778    if (this.i18n) {
31779      const value = text.value.visit(this._valueConverter);
31780      this.allocateBindingSlots(value);
31781      if (value instanceof Interpolation$1) {
31782        this.i18n.appendBoundText(text.i18n);
31783        this.i18nAppendBindings(value.expressions);
31784      }
31785      return;
31786    }
31787    const nodeIndex = this.allocateDataSlot();
31788    this.creationInstruction(text.sourceSpan, Identifiers.text, [literal(nodeIndex)]);
31789    const value = text.value.visit(this._valueConverter);
31790    this.allocateBindingSlots(value);
31791    if (value instanceof Interpolation$1) {
31792      this.updateInstructionWithAdvance(nodeIndex, text.sourceSpan, getTextInterpolationExpression(value), () => this.getUpdateInstructionArguments(value));
31793    } else {
31794      error('Text nodes should be interpolated and never bound directly.');
31795    }
31796  }
31797  visitText(text) {
31798    // when a text element is located within a translatable
31799    // block, we exclude this text element from instructions set,
31800    // since it will be captured in i18n content and processed at runtime
31801    if (!this.i18n) {
31802      this.creationInstruction(text.sourceSpan, Identifiers.text, [literal(this.allocateDataSlot()), literal(text.value)]);
31803    }
31804  }
31805  visitIcu(icu) {
31806    let initWasInvoked = false;
31807    // if an ICU was created outside of i18n block, we still treat
31808    // it as a translatable entity and invoke i18nStart and i18nEnd
31809    // to generate i18n context and the necessary instructions
31810    if (!this.i18n) {
31811      initWasInvoked = true;
31812      this.i18nStart(null, icu.i18n, true);
31813    }
31814    const i18n = this.i18n;
31815    const vars = this.i18nBindProps(icu.vars);
31816    const placeholders = this.i18nBindProps(icu.placeholders);
31817    // output ICU directly and keep ICU reference in context
31818    const message = icu.i18n;
31819    // we always need post-processing function for ICUs, to make sure that:
31820    // - all placeholders in a form of {PLACEHOLDER} are replaced with actual values (note:
31821    // `goog.getMsg` does not process ICUs and uses the `{PLACEHOLDER}` format for placeholders
31822    // inside ICUs)
31823    // - all ICU vars (such as `VAR_SELECT` or `VAR_PLURAL`) are replaced with correct values
31824    const transformFn = raw => {
31825      // Sort the map entries in the compiled output. This makes it easy to acheive identical output
31826      // in the template pipeline compiler.
31827      const params = Object.fromEntries(Object.entries({
31828        ...vars,
31829        ...placeholders
31830      }).sort());
31831      const formatted = formatI18nPlaceholderNamesInMap(params, /* useCamelCase */false);
31832      return invokeInstruction(null, Identifiers.i18nPostprocess, [raw, mapLiteral(formatted, true)]);
31833    };
31834    // in case the whole i18n message is a single ICU - we do not need to
31835    // create a separate top-level translation, we can use the root ref instead
31836    // and make this ICU a top-level translation
31837    // note: ICU placeholders are replaced with actual values in `i18nPostprocess` function
31838    // separately, so we do not pass placeholders into `i18nTranslate` function.
31839    if (isSingleI18nIcu(i18n.meta)) {
31840      this.i18nTranslate(message, /* placeholders */{}, i18n.ref, transformFn);
31841    } else {
31842      // output ICU directly and keep ICU reference in context
31843      const ref = this.i18nTranslate(message, /* placeholders */{}, /* ref */undefined, transformFn);
31844      i18n.appendIcu(icuFromI18nMessage(message).name, ref);
31845    }
31846    if (initWasInvoked) {
31847      this.i18nEnd(null, true);
31848    }
31849    return null;
31850  }
31851  visitIfBlock(block) {
31852    // Allocate one slot for the result of the expression.
31853    this.allocateBindingSlots(null);
31854    // We have to process the block in two steps: once here and again in the update instruction
31855    // callback in order to generate the correct expressions when pipes or pure functions are
31856    // used inside the branch expressions.
31857    const branchData = block.branches.map((branch, branchIndex) => {
31858      const {
31859        expression,
31860        expressionAlias,
31861        children,
31862        sourceSpan
31863      } = branch;
31864      // If the branch has an alias, it'll be assigned directly to the container's context.
31865      // We define a variable referring directly to the context so that any nested usages can be
31866      // rewritten to refer to it.
31867      const variables = expressionAlias !== null ? [new Variable(expressionAlias.name, DIRECT_CONTEXT_REFERENCE, expressionAlias.sourceSpan, expressionAlias.keySpan)] : undefined;
31868      let tagName = null;
31869      let attrsExprs;
31870      // Only the first branch can be used for projection, because the conditional
31871      // uses the container of the first branch as the insertion point for all branches.
31872      if (branchIndex === 0) {
31873        const inferredData = this.inferProjectionDataFromInsertionPoint(branch);
31874        tagName = inferredData.tagName;
31875        attrsExprs = inferredData.attrsExprs;
31876      }
31877      // Note: the template needs to be created *before* we process the expression,
31878      // otherwise pipes injecting some symbols won't work (see #52102).
31879      const templateIndex = this.createEmbeddedTemplateFn(tagName, children, '_Conditional', sourceSpan, variables, attrsExprs, undefined, branch.i18n);
31880      const processedExpression = expression === null ? null : expression.visit(this._valueConverter);
31881      return {
31882        index: templateIndex,
31883        expression: processedExpression,
31884        alias: expressionAlias
31885      };
31886    });
31887    // Use the index of the first block as the index for the entire container.
31888    const containerIndex = branchData[0].index;
31889    const paramsCallback = () => {
31890      let contextVariable = null;
31891      const generateBranch = branchIndex => {
31892        // If we've gone beyond the last branch, return the special -1 value which means that no
31893        // view will be rendered. Note that we don't need to reset the context here, because -1
31894        // won't render a view so the passed-in context won't be captured.
31895        if (branchIndex > branchData.length - 1) {
31896          return literal(-1);
31897        }
31898        const {
31899          index,
31900          expression,
31901          alias
31902        } = branchData[branchIndex];
31903        // If the branch has no expression, it means that it's the final `else`.
31904        // Return its index and stop the recursion. Assumes that there's only one
31905        // `else` condition and that it's the last branch.
31906        if (expression === null) {
31907          return literal(index);
31908        }
31909        let comparisonTarget;
31910        if (alias) {
31911          // If the branch is aliased, we need to assign the expression value to the temporary
31912          // variable and then pass it into `conditional`. E.g. for the expression:
31913          // `@if (foo(); as alias) {...}` we have to generate:
31914          // ```
31915          // let temp;
31916          // conditional(0, (temp = ctx.foo()) ? 0 : -1, temp);
31917          // ```
31918          contextVariable = this.allocateControlFlowTempVariable();
31919          comparisonTarget = contextVariable.set(this.convertPropertyBinding(expression));
31920        } else {
31921          comparisonTarget = this.convertPropertyBinding(expression);
31922        }
31923        return comparisonTarget.conditional(literal(index), generateBranch(branchIndex + 1));
31924      };
31925      const params = [literal(containerIndex), generateBranch(0)];
31926      if (contextVariable !== null) {
31927        params.push(contextVariable);
31928      }
31929      return params;
31930    };
31931    this.updateInstructionWithAdvance(containerIndex, block.branches[0].sourceSpan, Identifiers.conditional, paramsCallback);
31932  }
31933  visitSwitchBlock(block) {
31934    if (block.cases.length === 0) {
31935      return;
31936    }
31937    // We have to process the block in two steps: once here and again in the update instruction
31938    // callback in order to generate the correct expressions when pipes or pure functions are used.
31939    const caseData = block.cases.map(currentCase => {
31940      const index = this.createEmbeddedTemplateFn(null, currentCase.children, '_Case', currentCase.sourceSpan, undefined, undefined, undefined, currentCase.i18n);
31941      const expression = currentCase.expression === null ? null : currentCase.expression.visit(this._valueConverter);
31942      return {
31943        index,
31944        expression
31945      };
31946    });
31947    // Use the index of the first block as the index for the entire container.
31948    const containerIndex = caseData[0].index;
31949    // Note: the expression needs to be processed *after* the template,
31950    // otherwise pipes injecting some symbols won't work (see #52102).
31951    const blockExpression = block.expression.visit(this._valueConverter);
31952    this.allocateBindingSlots(null); // Allocate a slot for the primary block expression.
31953    this.updateInstructionWithAdvance(containerIndex, block.sourceSpan, Identifiers.conditional, () => {
31954      const generateCases = caseIndex => {
31955        // If we've gone beyond the last branch, return the special -1
31956        // value which means that no view will be rendered.
31957        if (caseIndex > caseData.length - 1) {
31958          return literal(-1);
31959        }
31960        const {
31961          index,
31962          expression
31963        } = caseData[caseIndex];
31964        // If the case has no expression, it means that it's the `default` case.
31965        // Return its index and stop the recursion. Assumes that there's only one
31966        // `default` condition and that it's defined last.
31967        if (expression === null) {
31968          return literal(index);
31969        }
31970        // If this is the very first comparison, we need to assign the value of the primary
31971        // expression as a part of the comparison so the remaining cases can reuse it. In practice
31972        // this looks as follows:
31973        // ```
31974        // let temp;
31975        // conditional(1, (temp = ctx.foo) === 1 ? 1 : temp === 2 ? 2 : temp === 3 ? 3 : 4);
31976        // ```
31977        const comparisonTarget = caseIndex === 0 ? this.allocateControlFlowTempVariable().set(this.convertPropertyBinding(blockExpression)) : this.allocateControlFlowTempVariable();
31978        return comparisonTarget.identical(this.convertPropertyBinding(expression)).conditional(literal(index), generateCases(caseIndex + 1));
31979      };
31980      return [literal(containerIndex), generateCases(0)];
31981    });
31982  }
31983  visitDeferredBlock(deferred) {
31984    const {
31985      loading,
31986      placeholder,
31987      error,
31988      triggers,
31989      prefetchTriggers
31990    } = deferred;
31991    const metadata = this.deferBlocks.get(deferred);
31992    if (!metadata) {
31993      throw new Error('Could not resolve `defer` block metadata. Block may need to be analyzed.');
31994    }
31995    const primaryTemplateIndex = this.createEmbeddedTemplateFn(null, deferred.children, '_Defer', deferred.sourceSpan, undefined, undefined, undefined, deferred.i18n);
31996    const loadingIndex = loading ? this.createEmbeddedTemplateFn(null, loading.children, '_DeferLoading', loading.sourceSpan, undefined, undefined, undefined, loading.i18n) : null;
31997    const loadingConsts = loading ? trimTrailingNulls([literal(loading.minimumTime), literal(loading.afterTime)]) : null;
31998    const placeholderIndex = placeholder ? this.createEmbeddedTemplateFn(null, placeholder.children, '_DeferPlaceholder', placeholder.sourceSpan, undefined, undefined, undefined, placeholder.i18n) : null;
31999    const placeholderConsts = placeholder && placeholder.minimumTime !== null ?
32000    // TODO(crisbeto): potentially pass the time directly instead of storing it in the `consts`
32001    // since the placeholder block can only have one parameter?
32002    literalArr([literal(placeholder.minimumTime)]) : null;
32003    const errorIndex = error ? this.createEmbeddedTemplateFn(null, error.children, '_DeferError', error.sourceSpan, undefined, undefined, undefined, error.i18n) : null;
32004    // Note: we generate this last so the index matches the instruction order.
32005    const deferredIndex = this.allocateDataSlot();
32006    const depsFnName = `${this.contextName}_Defer_${deferredIndex}_DepsFn`;
32007    // e.g. `defer(1, 0, MyComp_Defer_1_DepsFn, ...)`
32008    this.creationInstruction(deferred.sourceSpan, Identifiers.defer, trimTrailingNulls([literal(deferredIndex), literal(primaryTemplateIndex), this.allDeferrableDepsFn ?? this.createDeferredDepsFunction(depsFnName, metadata), literal(loadingIndex), literal(placeholderIndex), literal(errorIndex), loadingConsts?.length ? this.addToConsts(literalArr(loadingConsts)) : TYPED_NULL_EXPR, placeholderConsts ? this.addToConsts(placeholderConsts) : TYPED_NULL_EXPR, loadingConsts?.length || placeholderConsts ? importExpr(Identifiers.deferEnableTimerScheduling) : TYPED_NULL_EXPR]));
32009    // Allocate an extra data slot right after a defer block slot to store
32010    // instance-specific state of that defer block at runtime.
32011    this.allocateDataSlot();
32012    // Note: the triggers need to be processed *after* the various templates,
32013    // otherwise pipes injecting some symbols won't work (see #52102).
32014    this.createDeferTriggerInstructions(deferredIndex, triggers, metadata, false);
32015    this.createDeferTriggerInstructions(deferredIndex, prefetchTriggers, metadata, true);
32016  }
32017  createDeferredDepsFunction(name, metadata) {
32018    if (metadata.deps.length === 0) {
32019      return TYPED_NULL_EXPR;
32020    }
32021    // This defer block has deps for which we need to generate dynamic imports.
32022    const dependencyExp = [];
32023    for (const deferredDep of metadata.deps) {
32024      if (deferredDep.isDeferrable) {
32025        // Callback function, e.g. `m () => m.MyCmp;`.
32026        const innerFn = arrowFn([new FnParam('m', DYNAMIC_TYPE)],
32027        // Default imports are always accessed through the `default` property.
32028        variable('m').prop(deferredDep.isDefaultImport ? 'default' : deferredDep.symbolName));
32029        // Dynamic import, e.g. `import('./a').then(...)`.
32030        const importExpr = new DynamicImportExpr(deferredDep.importPath).prop('then').callFn([innerFn]);
32031        dependencyExp.push(importExpr);
32032      } else {
32033        // Non-deferrable symbol, just use a reference to the type.
32034        dependencyExp.push(deferredDep.type);
32035      }
32036    }
32037    const depsFnExpr = arrowFn([], literalArr(dependencyExp));
32038    this.constantPool.statements.push(depsFnExpr.toDeclStmt(name, StmtModifier.Final));
32039    return variable(name);
32040  }
32041  createDeferTriggerInstructions(deferredIndex, triggers, metadata, prefetch) {
32042    const {
32043      when,
32044      idle,
32045      immediate,
32046      timer,
32047      hover,
32048      interaction,
32049      viewport
32050    } = triggers;
32051    // `deferWhen(ctx.someValue)`
32052    if (when) {
32053      const value = when.value.visit(this._valueConverter);
32054      this.allocateBindingSlots(value);
32055      this.updateInstructionWithAdvance(deferredIndex, when.sourceSpan, prefetch ? Identifiers.deferPrefetchWhen : Identifiers.deferWhen, () => this.convertPropertyBinding(value));
32056    }
32057    // Note that we generate an implicit `on idle` if the `deferred` block has no triggers.
32058    // `deferOnIdle()`
32059    if (idle || !prefetch && Object.keys(triggers).length === 0) {
32060      this.creationInstruction(idle?.sourceSpan || null, prefetch ? Identifiers.deferPrefetchOnIdle : Identifiers.deferOnIdle);
32061    }
32062    // `deferOnImmediate()`
32063    if (immediate) {
32064      this.creationInstruction(immediate.sourceSpan, prefetch ? Identifiers.deferPrefetchOnImmediate : Identifiers.deferOnImmediate);
32065    }
32066    // `deferOnTimer(1337)`
32067    if (timer) {
32068      this.creationInstruction(timer.sourceSpan, prefetch ? Identifiers.deferPrefetchOnTimer : Identifiers.deferOnTimer, [literal(timer.delay)]);
32069    }
32070    // `deferOnHover(index, walkUpTimes)`
32071    if (hover) {
32072      this.domNodeBasedTrigger('hover', hover, metadata, prefetch ? Identifiers.deferPrefetchOnHover : Identifiers.deferOnHover);
32073    }
32074    // `deferOnInteraction(index, walkUpTimes)`
32075    if (interaction) {
32076      this.domNodeBasedTrigger('interaction', interaction, metadata, prefetch ? Identifiers.deferPrefetchOnInteraction : Identifiers.deferOnInteraction);
32077    }
32078    // `deferOnViewport(index, walkUpTimes)`
32079    if (viewport) {
32080      this.domNodeBasedTrigger('viewport', viewport, metadata, prefetch ? Identifiers.deferPrefetchOnViewport : Identifiers.deferOnViewport);
32081    }
32082  }
32083  domNodeBasedTrigger(name, trigger, metadata, instructionRef) {
32084    const triggerEl = metadata.triggerElements.get(trigger);
32085    // Don't generate anything if a trigger cannot be resolved.
32086    // We'll have template diagnostics to surface these to users.
32087    if (!triggerEl) {
32088      return;
32089    }
32090    this.creationInstruction(trigger.sourceSpan, instructionRef, () => {
32091      const location = this.elementLocations.get(triggerEl);
32092      if (!location) {
32093        throw new Error(`Could not determine location of reference passed into ` + `'${name}' trigger. Template may not have been fully analyzed.`);
32094      }
32095      // A negative depth means that the trigger is inside the placeholder.
32096      // Cap it at -1 since we only care whether or not it's negative.
32097      const depth = Math.max(this.level - location.level, -1);
32098      const params = [literal(location.index)];
32099      // The most common case should be a trigger within the view so we can omit a depth of
32100      // zero. For triggers in parent views and in the placeholder we need to pass it in.
32101      if (depth !== 0) {
32102        params.push(literal(depth));
32103      }
32104      return params;
32105    });
32106  }
32107  /**
32108   * Infers the data used for content projection (tag name and attributes) from the content of a
32109   * node.
32110   * @param node Node for which to infer the projection data.
32111   */
32112  inferProjectionDataFromInsertionPoint(node) {
32113    let root = null;
32114    let tagName = null;
32115    let attrsExprs;
32116    for (const child of node.children) {
32117      // Skip over comment nodes.
32118      if (child instanceof Comment$1) {
32119        continue;
32120      }
32121      // We can only infer the tag name/attributes if there's a single root node.
32122      if (root !== null) {
32123        root = null;
32124        break;
32125      }
32126      // Root nodes can only elements or templates with a tag name (e.g. `<div *foo></div>`).
32127      if (child instanceof Element$1 || child instanceof Template && child.tagName !== null) {
32128        root = child;
32129      }
32130    }
32131    // If we've found a single root node, its tag name and *static* attributes can be copied
32132    // to the surrounding template to be used for content projection. Note that it's important
32133    // that we don't copy any bound attributes since they don't participate in content projection
32134    // and they can be used in directive matching (in the case of `Template.templateAttrs`).
32135    if (root !== null) {
32136      const name = root instanceof Element$1 ? root.name : root.tagName;
32137      // Don't pass along `ng-template` tag name since it enables directive matching.
32138      tagName = name === NG_TEMPLATE_TAG_NAME ? null : name;
32139      attrsExprs = this.getAttributeExpressions(NG_TEMPLATE_TAG_NAME, root.attributes, root.inputs, []);
32140    }
32141    return {
32142      tagName,
32143      attrsExprs
32144    };
32145  }
32146  allocateDataSlot() {
32147    return this._dataIndex++;
32148  }
32149  visitForLoopBlock(block) {
32150    // Allocate one slot for the repeater metadata. The slots for the primary and empty block
32151    // are implicitly inferred by the runtime to index + 1 and index + 2.
32152    const blockIndex = this.allocateDataSlot();
32153    const {
32154      tagName,
32155      attrsExprs
32156    } = this.inferProjectionDataFromInsertionPoint(block);
32157    const primaryData = this.prepareEmbeddedTemplateFn(block.children, '_For', [block.item, block.contextVariables.$index, block.contextVariables.$count], block.i18n, {
32158      // We need to provide level-specific versions of `$index` and `$count`, because
32159      // they're used when deriving the remaining variables (`$odd`, `$even` etc.) while at the
32160      // same time being available implicitly. Without these aliases, we wouldn't be able to
32161      // access the `$index` of a parent loop from inside of a nested loop.
32162      [block.contextVariables.$index.name]: this.getLevelSpecificVariableName('$index', this.level + 1),
32163      [block.contextVariables.$count.name]: this.getLevelSpecificVariableName('$count', this.level + 1)
32164    });
32165    const {
32166      expression: trackByExpression,
32167      usesComponentInstance: trackByUsesComponentInstance
32168    } = this.createTrackByFunction(block);
32169    let emptyData = null;
32170    let emptyTagName = null;
32171    let emptyAttrsExprs;
32172    if (block.empty !== null) {
32173      const emptyInferred = this.inferProjectionDataFromInsertionPoint(block.empty);
32174      emptyTagName = emptyInferred.tagName;
32175      emptyAttrsExprs = emptyInferred.attrsExprs;
32176      emptyData = this.prepareEmbeddedTemplateFn(block.empty.children, '_ForEmpty', undefined, block.empty.i18n);
32177      // Allocate an extra slot for the empty block tracking.
32178      this.allocateBindingSlots(null);
32179    }
32180    this.registerComputedLoopVariables(block, primaryData.scope);
32181    // `repeaterCreate(0, ...)`
32182    this.creationInstruction(block.sourceSpan, Identifiers.repeaterCreate, () => {
32183      const params = [literal(blockIndex), variable(primaryData.name), literal(primaryData.getConstCount()), literal(primaryData.getVarCount()), literal(tagName), this.addAttrsToConsts(attrsExprs || null), trackByExpression];
32184      if (emptyData !== null) {
32185        params.push(literal(trackByUsesComponentInstance), variable(emptyData.name), literal(emptyData.getConstCount()), literal(emptyData.getVarCount()), literal(emptyTagName), this.addAttrsToConsts(emptyAttrsExprs || null));
32186      } else if (trackByUsesComponentInstance) {
32187        // If the tracking function doesn't use the component instance, we can omit the flag.
32188        params.push(literal(trackByUsesComponentInstance));
32189      }
32190      return trimTrailingNulls(params);
32191    });
32192    // Note: the expression needs to be processed *after* the template,
32193    // otherwise pipes injecting some symbols won't work (see #52102).
32194    // Note: we don't allocate binding slots for this expression,
32195    // because its value isn't stored in the LView.
32196    const value = block.expression.visit(this._valueConverter);
32197    // `advance(x); repeater(iterable)`
32198    this.updateInstructionWithAdvance(blockIndex, block.sourceSpan, Identifiers.repeater, () => [this.convertPropertyBinding(value)]);
32199  }
32200  registerComputedLoopVariables(block, bindingScope) {
32201    const level = bindingScope.bindingLevel;
32202    bindingScope.set(level, block.contextVariables.$odd.name, (scope, retrievalLevel) => {
32203      return this.getLevelSpecificForLoopVariable(block, scope, retrievalLevel, '$index').modulo(literal(2)).notIdentical(literal(0));
32204    });
32205    bindingScope.set(level, block.contextVariables.$even.name, (scope, retrievalLevel) => {
32206      return this.getLevelSpecificForLoopVariable(block, scope, retrievalLevel, '$index').modulo(literal(2)).identical(literal(0));
32207    });
32208    bindingScope.set(level, block.contextVariables.$first.name, (scope, retrievalLevel) => {
32209      return this.getLevelSpecificForLoopVariable(block, scope, retrievalLevel, '$index').identical(literal(0));
32210    });
32211    bindingScope.set(level, block.contextVariables.$last.name, (scope, retrievalLevel) => {
32212      const index = this.getLevelSpecificForLoopVariable(block, scope, retrievalLevel, '$index');
32213      const count = this.getLevelSpecificForLoopVariable(block, scope, retrievalLevel, '$count');
32214      return index.identical(count.minus(literal(1)));
32215    });
32216  }
32217  getLevelSpecificVariableName(name, level) {
32218    // We use the `ɵ` here to ensure that there are no name conflicts with user-defined variables.
32219    return `ɵ${name}_${level}`;
32220  }
32221  /**
32222   * Gets the name of a for loop variable at a specific binding level. This allows us to look
32223   * up implicitly shadowed variables like `$index` and `$count` at a specific level.
32224   */
32225  getLevelSpecificForLoopVariable(block, scope, retrievalLevel, name) {
32226    const scopeName = scope.bindingLevel === retrievalLevel ? block.contextVariables[name].name : this.getLevelSpecificVariableName(name, retrievalLevel);
32227    return scope.get(scopeName);
32228  }
32229  optimizeTrackByFunction(block) {
32230    const indexLocalName = block.contextVariables.$index.name;
32231    const itemName = block.item.name;
32232    const ast = block.trackBy.ast;
32233    // Top-level access of `$index` uses the built in `repeaterTrackByIndex`.
32234    if (ast instanceof PropertyRead && ast.receiver instanceof ImplicitReceiver && ast.name === indexLocalName) {
32235      return {
32236        expression: importExpr(Identifiers.repeaterTrackByIndex),
32237        usesComponentInstance: false
32238      };
32239    }
32240    // Top-level access of the item uses the built in `repeaterTrackByIdentity`.
32241    if (ast instanceof PropertyRead && ast.receiver instanceof ImplicitReceiver && ast.name === itemName) {
32242      return {
32243        expression: importExpr(Identifiers.repeaterTrackByIdentity),
32244        usesComponentInstance: false
32245      };
32246    }
32247    // Top-level calls in the form of `fn($index, item)` can be passed in directly.
32248    if (ast instanceof Call && ast.receiver instanceof PropertyRead && ast.receiver.receiver instanceof ImplicitReceiver && ast.args.length === 2) {
32249      const firstIsIndex = ast.args[0] instanceof PropertyRead && ast.args[0].receiver instanceof ImplicitReceiver && ast.args[0].name === indexLocalName;
32250      const secondIsItem = ast.args[1] instanceof PropertyRead && ast.args[1].receiver instanceof ImplicitReceiver && ast.args[1].name === itemName;
32251      if (firstIsIndex && secondIsItem) {
32252        // If we're in the top-level component, we can access directly through `ctx`,
32253        // otherwise we have to get a hold of the component through `componentInstance()`.
32254        const receiver = this.level === 0 ? variable(CONTEXT_NAME) : new ExternalExpr(Identifiers.componentInstance).callFn([]);
32255        return {
32256          expression: receiver.prop(ast.receiver.name),
32257          usesComponentInstance: false
32258        };
32259      }
32260    }
32261    return null;
32262  }
32263  createTrackByFunction(block) {
32264    const optimizedFn = this.optimizeTrackByFunction(block);
32265    // If the tracking function can be optimized, we don't need any further processing.
32266    if (optimizedFn !== null) {
32267      return optimizedFn;
32268    }
32269    const contextVars = block.contextVariables;
32270    const scope = new TrackByBindingScope(this._bindingScope, {
32271      // Alias `$index` and the item name to `$index` and `$item` respectively.
32272      // This allows us to reuse pure functions that may have different item names,
32273      // but are otherwise identical.
32274      [contextVars.$index.name]: '$index',
32275      [block.item.name]: '$item',
32276      // Accessing these variables in a tracking function will result in a template diagnostic.
32277      // We define them as globals so that their accesses are preserved verbatim instead of being
32278      // rewritten to the actual accesses.
32279      [contextVars.$count.name]: contextVars.$count.name,
32280      [contextVars.$first.name]: contextVars.$first.name,
32281      [contextVars.$last.name]: contextVars.$last.name,
32282      [contextVars.$even.name]: contextVars.$even.name,
32283      [contextVars.$odd.name]: contextVars.$odd.name
32284    });
32285    const params = [new FnParam('$index'), new FnParam('$item')];
32286    const stmts = convertPureComponentScopeFunction(block.trackBy.ast, scope, variable(CONTEXT_NAME), 'track');
32287    const usesComponentInstance = scope.getComponentAccessCount() > 0;
32288    let fn$1;
32289    if (!usesComponentInstance && stmts.length === 1 && stmts[0] instanceof ExpressionStatement) {
32290      fn$1 = arrowFn(params, stmts[0].expr);
32291    } else {
32292      // The last statement is returned implicitly.
32293      if (stmts.length > 0) {
32294        const lastStatement = stmts[stmts.length - 1];
32295        if (lastStatement instanceof ExpressionStatement) {
32296          stmts[stmts.length - 1] = new ReturnStatement(lastStatement.expr);
32297        }
32298      }
32299      // This has to be a function expression, because `.bind` doesn't work on arrow functions.
32300      fn$1 = fn(params, stmts);
32301    }
32302    return {
32303      expression: this.constantPool.getSharedFunctionReference(fn$1, '_forTrack'),
32304      usesComponentInstance
32305    };
32306  }
32307  getConstCount() {
32308    return this._dataIndex;
32309  }
32310  getVarCount() {
32311    return this._pureFunctionSlots;
32312  }
32313  getConsts() {
32314    return this._constants;
32315  }
32316  getNgContentSelectors() {
32317    return this._ngContentReservedSlots.length ? this.constantPool.getConstLiteral(asLiteral(this._ngContentReservedSlots), true) : null;
32318  }
32319  bindingContext() {
32320    return `${this._bindingContext++}`;
32321  }
32322  templatePropertyBindings(templateIndex, attrs) {
32323    const propertyBindings = [];
32324    for (const input of attrs) {
32325      if (!(input instanceof BoundAttribute)) {
32326        continue;
32327      }
32328      const value = input.value.visit(this._valueConverter);
32329      if (value === undefined) {
32330        continue;
32331      }
32332      this.allocateBindingSlots(value);
32333      if (value instanceof Interpolation$1) {
32334        // Params typically contain attribute namespace and value sanitizer, which is applicable
32335        // for regular HTML elements, but not applicable for <ng-template> (since props act as
32336        // inputs to directives), so keep params array empty.
32337        const params = [];
32338        // prop="{{value}}" case
32339        this.interpolatedUpdateInstruction(getPropertyInterpolationExpression(value), templateIndex, input.name, input, value, params);
32340      } else {
32341        // [prop]="value" case
32342        propertyBindings.push({
32343          span: input.sourceSpan,
32344          paramsOrFn: getBindingFunctionParams(() => this.convertPropertyBinding(value), input.name)
32345        });
32346      }
32347    }
32348    for (const propertyBinding of propertyBindings) {
32349      this.updateInstructionWithAdvance(templateIndex, propertyBinding.span, Identifiers.property, propertyBinding.paramsOrFn);
32350    }
32351  }
32352  // Bindings must only be resolved after all local refs have been visited, so all
32353  // instructions are queued in callbacks that execute once the initial pass has completed.
32354  // Otherwise, we wouldn't be able to support local refs that are defined after their
32355  // bindings. e.g. {{ foo }} <div #foo></div>
32356  instructionFn(fns, span, reference, paramsOrFn, prepend = false) {
32357    fns[prepend ? 'unshift' : 'push']({
32358      span,
32359      reference,
32360      paramsOrFn
32361    });
32362  }
32363  processStylingUpdateInstruction(elementIndex, instruction) {
32364    let allocateBindingSlots = 0;
32365    if (instruction) {
32366      for (const call of instruction.calls) {
32367        allocateBindingSlots += call.allocateBindingSlots;
32368        this.updateInstructionWithAdvance(elementIndex, call.sourceSpan, instruction.reference, () => call.params(value => call.supportsInterpolation && value instanceof Interpolation$1 ? this.getUpdateInstructionArguments(value) : this.convertPropertyBinding(value)));
32369      }
32370    }
32371    return allocateBindingSlots;
32372  }
32373  creationInstruction(span, reference, paramsOrFn, prepend) {
32374    this.instructionFn(this._creationCodeFns, span, reference, paramsOrFn || [], prepend);
32375  }
32376  updateInstructionWithAdvance(nodeIndex, span, reference, paramsOrFn) {
32377    this.addAdvanceInstructionIfNecessary(nodeIndex, span);
32378    this.updateInstruction(span, reference, paramsOrFn);
32379  }
32380  updateInstruction(span, reference, paramsOrFn) {
32381    this.instructionFn(this._updateCodeFns, span, reference, paramsOrFn || []);
32382  }
32383  addAdvanceInstructionIfNecessary(nodeIndex, span) {
32384    if (nodeIndex !== this._currentIndex) {
32385      const delta = nodeIndex - this._currentIndex;
32386      if (delta < 1) {
32387        throw new Error('advance instruction can only go forwards');
32388      }
32389      this.instructionFn(this._updateCodeFns, span, Identifiers.advance, delta > 1 ? [literal(delta)] : []);
32390      this._currentIndex = nodeIndex;
32391    }
32392  }
32393  allocatePureFunctionSlots(numSlots) {
32394    const originalSlots = this._pureFunctionSlots;
32395    this._pureFunctionSlots += numSlots;
32396    return originalSlots;
32397  }
32398  allocateBindingSlots(value) {
32399    this._bindingSlots += value instanceof Interpolation$1 ? value.expressions.length : 1;
32400  }
32401  /**
32402   * Gets an expression that refers to the implicit receiver. The implicit
32403   * receiver is always the root level context.
32404   */
32405  getImplicitReceiverExpr() {
32406    if (this._implicitReceiverExpr) {
32407      return this._implicitReceiverExpr;
32408    }
32409    return this._implicitReceiverExpr = this.level === 0 ? variable(CONTEXT_NAME) : this._bindingScope.getOrCreateSharedContextVar(0);
32410  }
32411  convertPropertyBinding(value) {
32412    const convertedPropertyBinding = convertPropertyBinding(this, this.getImplicitReceiverExpr(), value, this.bindingContext());
32413    const valExpr = convertedPropertyBinding.currValExpr;
32414    this._tempVariables.push(...convertedPropertyBinding.stmts);
32415    return valExpr;
32416  }
32417  /**
32418   * Gets a list of argument expressions to pass to an update instruction expression. Also updates
32419   * the temp variables state with temp variables that were identified as needing to be created
32420   * while visiting the arguments.
32421   * @param value The original expression we will be resolving an arguments list from.
32422   */
32423  getUpdateInstructionArguments(value) {
32424    const {
32425      args,
32426      stmts
32427    } = convertUpdateArguments(this, this.getImplicitReceiverExpr(), value, this.bindingContext());
32428    this._tempVariables.push(...stmts);
32429    return args;
32430  }
32431  /**
32432   * Creates and returns a variable that can be used to
32433   * store the state between control flow instructions.
32434   */
32435  allocateControlFlowTempVariable() {
32436    // Note: the assumption here is that we'll only need one temporary variable for all c
32436ontrol
32437    // flow instructions. It's expected that any instructions will overwrite it before passing it
32438    // into the parameters.
32439    if (this._controlFlowTempVariable === null) {
32440      const name = `${this.contextName}_contFlowTmp`;
32441      this._tempVariables.push(new DeclareVarStmt(name));
32442      this._controlFlowTempVariable = variable(name);
32443    }
32444    return this._controlFlowTempVariable;
32445  }
32446  /**
32447   * Prepares all attribute expression values for the `TAttributes` array.
32448   *
32449   * The purpose of this function is to properly construct an attributes array that
32450   * is passed into the `elementStart` (or just `element`) functions. Because there
32451   * are many different types of attributes, the array needs to be constructed in a
32452   * special way so that `elementStart` can properly evaluate them.
32453   *
32454   * The format looks like this:
32455   *
32456   * ```
32457   * attrs = [prop, value, prop2, value2,
32458   *   PROJECT_AS, selector,
32459   *   CLASSES, class1, class2,
32460   *   STYLES, style1, value1, style2, value2,
32461   *   BINDINGS, name1, name2, name3,
32462   *   TEMPLATE, name4, name5, name6,
32463   *   I18N, name7, name8, ...]
32464   * ```
32465   *
32466   * Note that this function will fully ignore all synthetic (@foo) attribute values
32467   * because those values are intended to always be generated as property instructions.
32468   */
32469  getAttributeExpressions(elementName, renderAttributes, inputs, outputs, styles, templateAttrs = [], boundI18nAttrs = []) {
32470    const alreadySeen = new Set();
32471    const attrExprs = [];
32472    let ngProjectAsAttr;
32473    for (const attr of renderAttributes) {
32474      if (attr.name === NG_PROJECT_AS_ATTR_NAME) {
32475        ngProjectAsAttr = attr;
32476      }
32477      // Note that static i18n attributes aren't in the i18n array,
32478      // because they're treated in the same way as regular attributes.
32479      if (attr.i18n) {
32480        // When i18n attributes are present on elements with structural directives
32481        // (e.g. `<div *ngIf title="Hello" i18n-title>`), we want to avoid generating
32482        // duplicate i18n translation blocks for `ɵɵtemplate` and `ɵɵelement` instruction
32483        // attributes. So we do a cache lookup to see if suitable i18n translation block
32484        // already exists.
32485        const {
32486          i18nVarRefsCache
32487        } = this._constants;
32488        let i18nVarRef;
32489        if (i18nVarRefsCache.has(attr.i18n)) {
32490          i18nVarRef = i18nVarRefsCache.get(attr.i18n);
32491        } else {
32492          i18nVarRef = this.i18nTranslate(attr.i18n);
32493          i18nVarRefsCache.set(attr.i18n, i18nVarRef);
32494        }
32495        attrExprs.push(literal(attr.name), i18nVarRef);
32496      } else {
32497        attrExprs.push(...getAttributeNameLiterals(attr.name), trustedConstAttribute(elementName, attr));
32498      }
32499    }
32500    // Keep ngProjectAs next to the other name, value pairs so we can verify that we match
32501    // ngProjectAs marker in the attribute name slot.
32502    if (ngProjectAsAttr) {
32503      attrExprs.push(...getNgProjectAsLiteral(ngProjectAsAttr));
32504    }
32505    function addAttrExpr(key, value) {
32506      if (typeof key === 'string') {
32507        if (!alreadySeen.has(key)) {
32508          attrExprs.push(...getAttributeNameLiterals(key));
32509          value !== undefined && attrExprs.push(value);
32510          alreadySeen.add(key);
32511        }
32512      } else {
32513        attrExprs.push(literal(key));
32514      }
32515    }
32516    // it's important that this occurs before BINDINGS and TEMPLATE because once `elementStart`
32517    // comes across the BINDINGS or TEMPLATE markers then it will continue reading each value as
32518    // as single property value cell by cell.
32519    if (styles) {
32520      styles.populateInitialStylingAttrs(attrExprs);
32521    }
32522    if (inputs.length || outputs.length) {
32523      const attrsLengthBeforeInputs = attrExprs.length;
32524      for (let i = 0; i < inputs.length; i++) {
32525        const input = inputs[i];
32526        // We don't want the animation and attribute bindings in the
32527        // attributes array since they aren't used for directive matching.
32528        if (input.type !== 4 /* BindingType.Animation */ && input.type !== 1 /* BindingType.Attribute */) {
32529          addAttrExpr(input.name);
32530        }
32531      }
32532      for (let i = 0; i < outputs.length; i++) {
32533        const output = outputs[i];
32534        if (output.type !== 1 /* ParsedEventType.Animation */) {
32535          addAttrExpr(output.name);
32536        }
32537      }
32538      // this is a cheap way of adding the marker only after all the input/output
32539      // values have been filtered (by not including the animation ones) and added
32540      // to the expressions. The marker is important because it tells the runtime
32541      // code that this is where attributes without values start...
32542      if (attrExprs.length !== attrsLengthBeforeInputs) {
32543        attrExprs.splice(attrsLengthBeforeInputs, 0, literal(3 /* core.AttributeMarker.Bindings */));
32544      }
32545    }
32546    if (templateAttrs.length) {
32547      attrExprs.push(literal(4 /* core.AttributeMarker.Template */));
32548      templateAttrs.forEach(attr => addAttrExpr(attr.name));
32549    }
32550    if (boundI18nAttrs.length) {
32551      attrExprs.push(literal(6 /* core.AttributeMarker.I18n */));
32552      boundI18nAttrs.forEach(attr => addAttrExpr(attr.name));
32553    }
32554    return attrExprs;
32555  }
32556  addToConsts(expression) {
32557    if (isNull(expression)) {
32558      return TYPED_NULL_EXPR;
32559    }
32560    const consts = this._constants.constExpressions;
32561    // Try to reuse a literal that's already in the array, if possible.
32562    for (let i = 0; i < consts.length; i++) {
32563      if (consts[i].isEquivalent(expression)) {
32564        return literal(i);
32565      }
32566    }
32567    return literal(consts.push(expression) - 1);
32568  }
32569  addAttrsToConsts(attrs) {
32570    return attrs !== null && attrs.length > 0 ? this.addToConsts(literalArr(attrs)) : TYPED_NULL_EXPR;
32571  }
32572  prepareRefsArray(references) {
32573    if (!references || references.length === 0) {
32574      return TYPED_NULL_EXPR;
32575    }
32576    const refsParam = references.flatMap(reference => {
32577      const slot = this.allocateDataSlot();
32578      // Generate the update temporary.
32579      const variableName = this._bindingScope.freshReferenceName();
32580      const retrievalLevel = this.level;
32581      const lhs = variable(variableName);
32582      this._bindingScope.set(retrievalLevel, reference.name, lhs, 0 /* DeclarationPriority.DEFAULT */, (scope, relativeLevel) => {
32583        // e.g. nextContext(2);
32584        const nextContextStmt = relativeLevel > 0 ? [generateNextContextExpr(relativeLevel).toStmt()] : [];
32585        // e.g. const $foo$ = reference(1);
32586        const refExpr = lhs.set(importExpr(Identifiers.reference).callFn([literal(slot)]));
32587        return nextContextStmt.concat(refExpr.toConstDecl());
32588      }, true);
32589      return [reference.name, reference.value];
32590    });
32591    return asLiteral(refsParam);
32592  }
32593  prepareListenerParameter(tagName, outputAst, index) {
32594    return () => {
32595      const eventName = outputAst.name;
32596      const bindingFnName = outputAst.type === 1 /* ParsedEventType.Animation */ ?
32597      // synthetic @listener.foo values are treated the exact same as are standard listeners
32598      prepareSyntheticListenerFunctionName(eventName, outputAst.phase) : sanitizeIdentifier(eventName);
32599      const handlerName = `${this.templateName}_${tagName}_${bindingFnName}_${index}_listener`;
32600      const scope = this._bindingScope.nestedScope(this._bindingScope.bindingLevel, EVENT_BINDING_SCOPE_GLOBALS);
32601      return prepareEventListenerParameters(outputAst, handlerName, scope);
32602    };
32603  }
32604}
32605class ValueConverter extends AstMemoryEfficientTransformer {
32606  constructor(constantPool, allocateSlot, allocatePureFunctionSlots, definePipe) {
32607    super();
32608    this.constantPool = constantPool;
32609    this.allocateSlot = allocateSlot;
32610    this.allocatePureFunctionSlots = allocatePureFunctionSlots;
32611    this.definePipe = definePipe;
32612    this._pipeBindExprs = [];
32613  }
32614  // AstMemoryEfficientTransformer
32615  visitPipe(pipe, context) {
32616    // Allocate a slot to create the pipe
32617    const slot = this.allocateSlot();
32618    const slotPseudoLocal = `PIPE:${slot}`;
32619    // Allocate one slot for the result plus one slot per pipe argument
32620    const pureFunctionSlot = this.allocatePureFunctionSlots(2 + pipe.args.length);
32621    const target = new PropertyRead(pipe.span, pipe.sourceSpan, pipe.nameSpan, new ImplicitReceiver(pipe.span, pipe.sourceSpan), slotPseudoLocal);
32622    const {
32623      identifier,
32624      isVarLength
32625    } = pipeBindingCallInfo(pipe.args);
32626    this.definePipe(pipe.name, slotPseudoLocal, slot, importExpr(identifier));
32627    const args = [pipe.exp, ...pipe.args];
32628    const convertedArgs = isVarLength ? this.visitAll([new LiteralArray(pipe.span, pipe.sourceSpan, args)]) : this.visitAll(args);
32629    const pipeBindExpr = new Call(pipe.span, pipe.sourceSpan, target, [new LiteralPrimitive(pipe.span, pipe.sourceSpan, slot), new LiteralPrimitive(pipe.span, pipe.sourceSpan, pureFunctionSlot), ...convertedArgs], null);
32630    this._pipeBindExprs.push(pipeBindExpr);
32631    return pipeBindExpr;
32632  }
32633  updatePipeSlotOffsets(bindingSlots) {
32634    this._pipeBindExprs.forEach(pipe => {
32635      // update the slot offset arg (index 1) to account for binding slots
32636      const slotOffset = pipe.args[1];
32637      slotOffset.value += bindingSlots;
32638    });
32639  }
32640  visitLiteralArray(array, context) {
32641    return new BuiltinFunctionCall(array.span, array.sourceSpan, this.visitAll(array.expressions), values => {
32642      // If the literal has calculated (non-literal) elements transform it into
32643      // calls to literal factories that compose the literal and will cache intermediate
32644      // values.
32645      const literal = literalArr(values);
32646      return getLiteralFactory(this.constantPool, literal, this.allocatePureFunctionSlots);
32647    });
32648  }
32649  visitLiteralMap(map, context) {
32650    return new BuiltinFunctionCall(map.span, map.sourceSpan, this.visitAll(map.values), values => {
32651      // If the literal has calculated (non-literal) elements  transform it into
32652      // calls to literal factories that compose the literal and will cache intermediate
32653      // values.
32654      const literal = literalMap(values.map((value, index) => ({
32655        key: map.keys[index].key,
32656        value,
32657        quoted: map.keys[index].quoted
32658      })));
32659      return getLiteralFactory(this.constantPool, literal, this.allocatePureFunctionSlots);
32660    });
32661  }
32662}
32663// Pipes always have at least one parameter, the value they operate on
32664const pipeBindingIdentifiers = [Identifiers.pipeBind1, Identifiers.pipeBind2, Identifiers.pipeBind3, Identifiers.pipeBind4];
32665function pipeBindingCallInfo(args) {
32666  const identifier = pipeBindingIdentifiers[args.length];
32667  return {
32668    identifier: identifier || Identifiers.pipeBindV,
32669    isVarLength: !identifier
32670  };
32671}
32672const pureFunctionIdentifiers = [Identifiers.pureFunction0, Identifiers.pureFunction1, Identifiers.pureFunction2, Identifiers.pureFunction3, Identifiers.pureFunction4, Identifiers.pureFunction5, Identifiers.pureFunction6, Identifiers.pureFunction7, Identifiers.pureFunction8];
32673function pureFunctionCallInfo(args) {
32674  const identifier = pureFunctionIdentifiers[args.length];
32675  return {
32676    identifier: identifier || Identifiers.pureFunctionV,
32677    isVarLength: !identifier
32678  };
32679}
32680// e.g. x(2);
32681function generateNextContextExpr(relativeLevelDiff) {
32682  return importExpr(Identifiers.nextContext).callFn(relativeLevelDiff > 1 ? [literal(relativeLevelDiff)] : []);
32683}
32684function getLiteralFactory(constantPool, literal$1, allocateSlots) {
32685  const {
32686    literalFactory,
32687    literalFactoryArguments
32688  } = constantPool.getLiteralFactory(literal$1);
32689  // Allocate 1 slot for the result plus 1 per argument
32690  const startSlot = allocateSlots(1 + literalFactoryArguments.length);
32691  const {
32692    identifier,
32693    isVarLength
32694  } = pureFunctionCallInfo(literalFactoryArguments);
32695  // Literal factories are pure functions that only need to be re-invoked when the parameters
32696  // change.
32697  const args = [literal(startSlot), literalFactory];
32698  if (isVarLength) {
32699    args.push(literalArr(literalFactoryArguments));
32700  } else {
32701    args.push(...literalFactoryArguments);
32702  }
32703  return importExpr(identifier).callFn(args);
32704}
32705/**
32706 * Gets an array of literals that can be added to an expression
32707 * to represent the name and namespace of an attribute. E.g.
32708 * `:xlink:href` turns into `[AttributeMarker.NamespaceURI, 'xlink', 'href']`.
32709 *
32710 * @param name Name of the attribute, including the namespace.
32711 */
32712function getAttributeNameLiterals(name) {
32713  const [attributeNamespace, attributeName] = splitNsName(name);
32714  const nameLiteral = literal(attributeName);
32715  if (attributeNamespace) {
32716    return [literal(0 /* core.AttributeMarker.NamespaceURI */), literal(attributeNamespace), nameLiteral];
32717  }
32718  return [nameLiteral];
32719}
32720/** The prefix used to get a shared context in BindingScope's map. */
32721const SHARED_CONTEXT_KEY = '$$shared_ctx$$';
32722class BindingScope {
32723  static createRootScope() {
32724    return new BindingScope();
32725  }
32726  constructor(bindingLevel = 0, parent = null, globals) {
32727    this.bindingLevel = bindingLevel;
32728    this.parent = parent;
32729    this.globals = globals;
32730    /** Keeps a map from local variables to their BindingData. */
32731    this.map = new Map();
32732    this.referenceNameIndex = 0;
32733    this.restoreViewVariable = null;
32734    this.usesRestoredViewContext = false;
32735    if (globals !== undefined) {
32736      for (const name of globals) {
32737        this.set(0, name, variable(name));
32738      }
32739    }
32740  }
32741  get(name) {
32742    let current = this;
32743    while (current) {
32744      let value = current.map.get(name);
32745      if (value != null) {
32746        if (current !== this) {
32747          // make a local copy and reset the `declare` state
32748          value = {
32749            retrievalLevel: value.retrievalLevel,
32750            lhs: value.lhs,
32751            declareLocalCallback: value.declareLocalCallback,
32752            declare: false,
32753            priority: value.priority
32754          };
32755          // Cache the value locally.
32756          this.map.set(name, value);
32757          // Possibly generate a shared context var
32758          this.maybeGenerateSharedContextVar(value);
32759          this.maybeRestoreView();
32760        }
32761        if (value.declareLocalCallback && !value.declare) {
32762          value.declare = true;
32763        }
32764        return typeof value.lhs === 'function' ? value.lhs(this, value.retrievalLevel) : value.lhs;
32765      }
32766      current = current.parent;
32767    }
32768    // If we get to this point, we are looking for a property on the top level component
32769    // - If level === 0, we are on the top and don't need to re-declare `ctx`.
32770    // - If level > 0, we are in an embedded view. We need to retrieve the name of the
32771    // local var we used to store the component context, e.g. const $comp$ = x();
32772    return this.bindingLevel === 0 ? null : this.getComponentProperty(name);
32773  }
32774  /** Checks whether a variable exists locally on the current scope. */
32775  hasLocal(name) {
32776    return this.map.has(name);
32777  }
32778  /**
32779   * Create a local variable for later reference.
32780   *
32781   * @param retrievalLevel The level from which this value can be retrieved
32782   * @param name Name of the variable.
32783   * @param lhs AST representing the left hand side of the `let lhs = rhs;`.
32784   * @param priority The sorting priority of this var
32785   * @param declareLocalCallback The callback to invoke when declaring this local var
32786   * @param localRef Whether or not this is a local ref
32787   */
32788  set(retrievalLevel, name, lhs, priority = 0 /* DeclarationPriority.DEFAULT */, declareLocalCallback, localRef) {
32789    if (this.map.has(name)) {
32790      if (localRef) {
32791        // Do not throw an error if it's a local ref and do not update existing value,
32792        // so the first defined ref is always returned.
32793        return this;
32794      }
32795      error(`The name ${name} is already defined in scope to be ${this.map.get(name)}`);
32796    }
32797    this.map.set(name, {
32798      retrievalLevel: retrievalLevel,
32799      lhs: lhs,
32800      declare: false,
32801      declareLocalCallback: declareLocalCallback,
32802      priority: priority
32803    });
32804    return this;
32805  }
32806  // Implemented as part of LocalResolver.
32807  getLocal(name) {
32808    return this.get(name);
32809  }
32810  // Implemented as part of LocalResolver.
32811  notifyImplicitReceiverUse() {
32812    if (this.bindingLevel !== 0) {
32813      // Since the implicit receiver is accessed in an embedded view, we need to
32814      // ensure that we declare a shared context variable for the current template
32815      // in the update variables.
32816      this.map.get(SHARED_CONTEXT_KEY + 0).declare = true;
32817    }
32818  }
32819  nestedScope(level, globals) {
32820    const newScope = new BindingScope(level, this, globals);
32821    if (level > 0) newScope.generateSharedContextVar(0);
32822    return newScope;
32823  }
32824  /**
32825   * Gets or creates a shared context variable and returns its expression. Note that
32826   * this does not mean that the shared variable will be declared. Variables in the
32827   * binding scope will be only declared if they are used.
32828   */
32829  getOrCreateSharedContextVar(retrievalLevel) {
32830    const bindingKey = SHARED_CONTEXT_KEY + retrievalLevel;
32831    if (!this.map.has(bindingKey)) {
32832      this.generateSharedContextVar(retrievalLevel);
32833    }
32834    // Shared context variables are always generated as "ReadVarExpr".
32835    return this.map.get(bindingKey).lhs;
32836  }
32837  getSharedContextName(retrievalLevel) {
32838    const sharedCtxObj = this.map.get(SHARED_CONTEXT_KEY + retrievalLevel);
32839    // Shared context variables are always generated as "ReadVarExpr".
32840    return sharedCtxObj && sharedCtxObj.declare ? sharedCtxObj.lhs : null;
32841  }
32842  maybeGenerateSharedContextVar(value) {
32843    if (value.priority === 1 /* DeclarationPriority.CONTEXT */ && value.retrievalLevel < this.bindingLevel) {
32844      const sharedCtxObj = this.map.get(SHARED_CONTEXT_KEY + value.retrievalLevel);
32845      if (sharedCtxObj) {
32846        sharedCtxObj.declare = true;
32847      } else {
32848        this.generateSharedContextVar(value.retrievalLevel);
32849      }
32850    }
32851  }
32852  generateSharedContextVar(retrievalLevel) {
32853    const lhs = variable(CONTEXT_NAME + this.freshReferenceName());
32854    this.map.set(SHARED_CONTEXT_KEY + retrievalLevel, {
32855      retrievalLevel: retrievalLevel,
32856      lhs: lhs,
32857      declareLocalCallback: (scope, relativeLevel) => {
32858        // const ctx_r0 = nextContext(2);
32859        return [lhs.set(generateNextContextExpr(relativeLevel)).toConstDecl()];
32860      },
32861      declare: false,
32862      priority: 2 /* DeclarationPriority.SHARED_CONTEXT */
32863    });
32864  }
32865  getComponentProperty(name) {
32866    const componentValue = this.map.get(SHARED_CONTEXT_KEY + 0);
32867    componentValue.declare = true;
32868    this.maybeRestoreView();
32869    const lhs = typeof componentValue.lhs === 'function' ? componentValue.lhs(this, componentValue.retrievalLevel) : componentValue.lhs;
32870    return name === DIRECT_CONTEXT_REFERENCE ? lhs : lhs.prop(name);
32871  }
32872  maybeRestoreView() {
32873    // View restoration is required for listener instructions inside embedded views, because
32874    // they only run in creation mode and they can have references to the context object.
32875    // If the context object changes in update mode, the reference will be incorrect, because
32876    // it was established during creation.
32877    if (this.isListenerScope()) {
32878      if (!this.parent.restoreViewVariable) {
32879        // parent saves variable to generate a shared `const $s$ = getCurrentView();` instruction
32880        this.parent.restoreViewVariable = variable(this.parent.freshReferenceName());
32881      }
32882      this.restoreViewVariable = this.parent.restoreViewVariable;
32883    }
32884  }
32885  restoreViewStatement() {
32886    if (this.restoreViewVariable) {
32887      const restoreCall = invokeInstruction(null, Identifiers.restoreView, [this.restoreViewVariable]);
32888      // Either `const restoredCtx = restoreView($state$);` or `restoreView($state$);`
32889      // depending on whether it is being used.
32890      return this.usesRestoredViewContext ? variable(RESTORED_VIEW_CONTEXT_NAME).set(restoreCall).toConstDecl() : restoreCall.toStmt();
32891    }
32892    return null;
32893  }
32894  viewSnapshotStatements() {
32895    // const $state$ = getCurrentView();
32896    return this.restoreViewVariable ? [this.restoreViewVariable.set(invokeInstruction(null, Identifiers.getCurrentView, [])).toConstDecl()] : [];
32897  }
32898  isListenerScope() {
32899    return this.parent && this.parent.bindingLevel === this.bindingLevel;
32900  }
32901  variableDeclarations() {
32902    let currentContextLevel = 0;
32903    return Array.from(this.map.values()).filter(value => value.declare).sort((a, b) => b.retrievalLevel - a.retrievalLevel || b.priority - a.priority).reduce((stmts, value) => {
32904      const levelDiff = this.bindingLevel - value.retrievalLevel;
32905      const currStmts = value.declareLocalCallback(this, levelDiff - currentContextLevel);
32906      currentContextLevel = levelDiff;
32907      return stmts.concat(currStmts);
32908    }, []);
32909  }
32910  freshReferenceName() {
32911    let current = this;
32912    // Find the top scope as it maintains the global reference count
32913    while (current.parent) current = current.parent;
32914    const ref = `${REFERENCE_PREFIX}${current.referenceNameIndex++}`;
32915    return ref;
32916  }
32917  hasRestoreViewVariable() {
32918    return !!this.restoreViewVariable;
32919  }
32920  notifyRestoredViewContextUse() {
32921    this.usesRestoredViewContext = true;
32922  }
32923}
32924/** Binding scope of a `track` function inside a `for` loop block. */
32925class TrackByBindingScope extends BindingScope {
32926  constructor(parentScope, globalOverrides) {
32927    super(parentScope.bindingLevel + 1, parentScope);
32928    this.globalOverrides = globalOverrides;
32929    this.componentAccessCount = 0;
32930  }
32931  get(name) {
32932    // Intercept any overridden globals.
32933    if (this.globalOverrides.hasOwnProperty(name)) {
32934      return variable(this.globalOverrides[name]);
32935    }
32936    let current = this.parent;
32937    // Prevent accesses of template variables outside the `for` loop.
32938    while (current) {
32939      if (current.hasLocal(name)) {
32940        return null;
32941      }
32942      current = current.parent;
32943    }
32944    // When the component scope is accessed, we redirect it through `this`.
32945    this.componentAccessCount++;
32946    return variable('this').prop(name);
32947  }
32948  /** Gets the number of times the host component has been accessed through the scope. */
32949  getComponentAccessCount() {
32950    return this.componentAccessCount;
32951  }
32952}
32953/**
32954 * Creates an array of expressions out of an `ngProjectAs` attributes
32955 * which can be added to the instruction parameters.
32956 */
32957function getNgProjectAsLiteral(attribute) {
32958  // Parse the attribute value into a CssSelectorList. Note that we only take the
32959  // first selector, because we don't support multiple selectors in ngProjectAs.
32960  const parsedR3Selector = parseSelectorToR3Selector(attribute.value)[0];
32961  return [literal(5 /* core.AttributeMarker.ProjectAs */), asLiteral(parsedR3Selector)];
32962}
32963/**
32964 * Gets the instruction to generate for an interpolated property
32965 * @param interpolation An Interpolation AST
32966 */
32967function getPropertyInterpolationExpression(interpolation) {
32968  switch (getInterpolationArgsLength(interpolation)) {
32969    case 1:
32970      return Identifiers.propertyInterpolate;
32971    case 3:
32972      return Identifiers.propertyInterpolate1;
32973    case 5:
32974      return Identifiers.propertyInterpolate2;
32975    case 7:
32976      return Identifiers.propertyInterpolate3;
32977    case 9:
32978      return Identifiers.propertyInterpolate4;
32979    case 11:
32980      return Identifiers.propertyInterpolate5;
32981    case 13:
32982      return Identifiers.propertyInterpolate6;
32983    case 15:
32984      return Identifiers.propertyInterpolate7;
32985    case 17:
32986      return Identifiers.propertyInterpolate8;
32987    default:
32988      return Identifiers.propertyInterpolateV;
32989  }
32990}
32991/**
32992 * Gets the instruction to generate for an interpolated attribute
32993 * @param interpolation An Interpolation AST
32994 */
32995function getAttributeInterpolationExpression(interpolation) {
32996  switch (getInterpolationArgsLength(interpolation)) {
32997    case 3:
32998      return Identifiers.attributeInterpolate1;
32999    case 5:
33000      return Identifiers.attributeInterpolate2;
33001    case 7:
33002      return Identifiers.attributeInterpolate3;
33003    case 9:
33004      return Identifiers.attributeInterpolate4;
33005    case 11:
33006      return Identifiers.attributeInterpolate5;
33007    case 13:
33008      return Identifiers.attributeInterpolate6;
33009    case 15:
33010      return Identifiers.attributeInterpolate7;
33011    case 17:
33012      return Identifiers.attributeInterpolate8;
33013    default:
33014      return Identifiers.attributeInterpolateV;
33015  }
33016}
33017/**
33018 * Gets the instruction to generate for interpolated text.
33019 * @param interpolation An Interpolation AST
33020 */
33021function getTextInterpolationExpression(interpolation) {
33022  switch (getInterpolationArgsLength(interpolation)) {
33023    case 1:
33024      return Identifiers.textInterpolate;
33025    case 3:
33026      return Identifiers.textInterpolate1;
33027    case 5:
33028      return Identifiers.textInterpolate2;
33029    case 7:
33030      return Identifiers.textInterpolate3;
33031    case 9:
33032      return Identifiers.textInterpolate4;
33033    case 11:
33034      return Identifiers.textInterpolate5;
33035    case 13:
33036      return Identifiers.textInterpolate6;
33037    case 15:
33038      return Identifiers.textInterpolate7;
33039    case 17:
33040      return Identifiers.textInterpolate8;
33041    default:
33042      return Identifiers.textInterpolateV;
33043  }
33044}
33045/**
33046 * Parse a template into render3 `Node`s and additional metadata, with no other dependencies.
33047 *
33048 * @param template text of the template to parse
33049 * @param templateUrl URL to use for source mapping of the parsed template
33050 * @param options options to modify how the template is parsed
33051 */
33052function parseTemplate(template, templateUrl, options = {}) {
33053  const {
33054    interpolationConfig,
33055    preserveWhitespaces,
33056    enableI18nLegacyMessageIdFormat
33057  } = options;
33058  const bindingParser = makeBindingParser(interpolationConfig);
33059  const htmlParser = new HtmlParser();
33060  const parseResult = htmlParser.parse(template, templateUrl, {
33061    leadingTriviaChars: LEADING_TRIVIA_CHARS,
33062    ...options,
33063    tokenizeExpansionForms: true,
33064    tokenizeBlocks: options.enableBlockSyntax ?? true
33065  });
33066  if (!options.alwaysAttemptHtmlToR3AstConversion && parseResult.errors && parseResult.errors.length > 0) {
33067    const parsedTemplate = {
33068      interpolationConfig,
33069      preserveWhitespaces,
33070      errors: parseResult.errors,
33071      nodes: [],
33072      styleUrls: [],
33073      styles: [],
33074      ngContentSelectors: []
33075    };
33076    if (options.collectCommentNodes) {
33077      parsedTemplate.commentNodes = [];
33078    }
33079    return parsedTemplate;
33080  }
33081  let rootNodes = parseResult.rootNodes;
33082  // process i18n meta information (scan attributes, generate ids)
33083  // before we run whitespace removal process, because existing i18n
33084  // extraction process (ng extract-i18n) relies on a raw content to generate
33085  // message ids
33086  const i18nMetaVisitor = new I18nMetaVisitor(interpolationConfig, /* keepI18nAttrs */!preserveWhitespaces, enableI18nLegacyMessageIdFormat);
33087  const i18nMetaResult = i18nMetaVisitor.visitAllWithErrors(rootNodes);
33088  if (!options.alwaysAttemptHtmlToR3AstConversion && i18nMetaResult.errors && i18nMetaResult.errors.length > 0) {
33089    const parsedTemplate = {
33090      interpolationConfig,
33091      preserveWhitespaces,
33092      errors: i18nMetaResult.errors,
33093      nodes: [],
33094      styleUrls: [],
33095      styles: [],
33096      ngContentSelectors: []
33097    };
33098    if (options.collectCommentNodes) {
33099      parsedTemplate.commentNodes = [];
33100    }
33101    return parsedTemplate;
33102  }
33103  rootNodes = i18nMetaResult.rootNodes;
33104  if (!preserveWhitespaces) {
33105    rootNodes = visitAll(new WhitespaceVisitor(), rootNodes);
33106    // run i18n meta visitor again in case whitespaces are removed (because that might affect
33107    // generated i18n message content) and first pass indicated that i18n content is present in a
33108    // template. During this pass i18n IDs generated at the first pass will be preserved, so we can
33109    // mimic existing extraction process (ng extract-i18n)
33110    if (i18nMetaVisitor.hasI18nMeta) {
33111      rootNodes = visitAll(new I18nMetaVisitor(interpolationConfig, /* keepI18nAttrs */false), rootNodes);
33112    }
33113  }
33114  const {
33115    nodes,
33116    errors,
33117    styleUrls,
33118    styles,
33119    ngContentSelectors,
33120    commentNodes
33121  } = htmlAstToRender3Ast(rootNodes, bindingParser, {
33122    collectCommentNodes: !!options.collectCommentNodes
33123  });
33124  errors.push(...parseResult.errors, ...i18nMetaResult.errors);
33125  const parsedTemplate = {
33126    interpolationConfig,
33127    preserveWhitespaces,
33128    errors: errors.length > 0 ? errors : null,
33129    nodes,
33130    styleUrls,
33131    styles,
33132    ngContentSelectors
33133  };
33134  if (options.collectCommentNodes) {
33135    parsedTemplate.commentNodes = commentNodes;
33136  }
33137  return parsedTemplate;
33138}
33139const elementRegistry = new DomElementSchemaRegistry();
33140/**
33141 * Construct a `BindingParser` with a default configuration.
33142 */
33143function makeBindingParser(interpolationConfig = DEFAULT_INTERPOLATION_CONFIG) {
33144  return new BindingParser(new Parser$1(new Lexer()), interpolationConfig, elementRegistry, []);
33145}
33146function resolveSanitizationFn(context, isAttribute) {
33147  switch (context) {
33148    case SecurityContext.HTML:
33149      return importExpr(Identifiers.sanitizeHtml);
33150    case SecurityContext.SCRIPT:
33151      return importExpr(Identifiers.sanitizeScript);
33152    case SecurityContext.STYLE:
33153      // the compiler does not fill in an instruction for [style.prop?] binding
33154      // values because the style algorithm knows internally what props are subject
33155      // to sanitization (only [attr.style] values are explicitly sanitized)
33156      return isAttribute ? importExpr(Identifiers.sanitizeStyle) : null;
33157    case SecurityContext.URL:
33158      return importExpr(Identifiers.sanitizeUrl);
33159    case SecurityContext.RESOURCE_URL:
33160      return importExpr(Identifiers.sanitizeResourceUrl);
33161    default:
33162      return null;
33163  }
33164}
33165function trustedConstAttribute(tagName, attr) {
33166  const value = asLiteral(attr.value);
33167  if (isTrustedTypesSink(tagName, attr.name)) {
33168    switch (elementRegistry.securityContext(tagName, attr.name, /* isAttribute */true)) {
33169      case SecurityContext.HTML:
33170        return taggedTemplate(importExpr(Identifiers.trustConstantHtml), new TemplateLiteral([new TemplateLiteralElement(attr.value)], []), undefined, attr.valueSpan);
33171      // NB: no SecurityContext.SCRIPT here, as the corresponding tags are stripped by the compiler.
33172      case SecurityContext.RESOURCE_URL:
33173        return taggedTemplate(importExpr(Identifiers.trustConstantResourceUrl), new TemplateLiteral([new TemplateLiteralElement(attr.value)], []), undefined, attr.valueSpan);
33174      default:
33175        return value;
33176    }
33177  } else {
33178    return value;
33179  }
33180}
33181function isSingleElementTemplate(children) {
33182  return children.length === 1 && children[0] instanceof Element$1;
33183}
33184function isTextNode(node) {
33185  return node instanceof Text$3 || node instanceof BoundText || node instanceof Icu$1;
33186}
33187function isIframeElement(tagName) {
33188  return tagName.toLowerCase() === 'iframe';
33189}
33190function hasTextChildrenOnly(children) {
33191  return children.every(isTextNode);
33192}
33193function getBindingFunctionParams(deferredParams, name, eagerParams) {
33194  return () => {
33195    const value = deferredParams();
33196    const fnParams = Array.isArray(value) ? value : [value];
33197    if (eagerParams) {
33198      fnParams.push(...eagerParams);
33199    }
33200    if (name) {
33201      // We want the property name to always be the first function parameter.
33202      fnParams.unshift(literal(name));
33203    }
33204    return fnParams;
33205  };
33206}
33207/** Name of the global variable that is used to determine if we use Closure translations or not */
33208const NG_I18N_CLOSURE_MODE = 'ngI18nClosureMode';
33209/**
33210 * Generate statements that define a given translation message.
33211 *
33212 * ```
33213 * var I18N_1;
33214 * if (typeof ngI18nClosureMode !== undefined && ngI18nClosureMode) {
33215 *     var MSG_EXTERNAL_XXX = goog.getMsg(
33216 *          "Some message with {$interpolation}!",
33217 *          { "interpolation": "\uFFFD0\uFFFD" }
33218 *     );
33219 *     I18N_1 = MSG_EXTERNAL_XXX;
33220 * }
33221 * else {
33222 *     I18N_1 = $localize`Some message with ${'\uFFFD0\uFFFD'}!`;
33223 * }
33224 * ```
33225 *
33226 * @param message The original i18n AST message node
33227 * @param variable The variable that will be assigned the translation, e.g. `I18N_1`.
33228 * @param closureVar The variable for Closure `goog.getMsg` calls, e.g. `MSG_EXTERNAL_XXX`.
33229 * @param params Object mapping placeholder names to their values (e.g.
33230 * `{ "interpolation": "\uFFFD0\uFFFD" }`).
33231 * @param transformFn Optional transformation function that will be applied to the translation (e.g.
33232 * post-processing).
33233 * @returns An array of statements that defined a given translation.
33234 */
33235function getTranslationDeclStmts(message, variable, closureVar, params = {}, transformFn) {
33236  // Sort the map entries in the compiled output. This makes it easy to acheive identical output in
33237  // the template pipeline compiler.
33238  params = Object.fromEntries(Object.entries(params).sort());
33239  const statements = [declareI18nVariable(variable), ifStmt(createClosureModeGuard(), createGoogleGetMsgStatements(variable, message, closureVar, params), createLocalizeStatements(variable, message, formatI18nPlaceholderNamesInMap(params, /* useCamelCase */false)))];
33240  if (transformFn) {
33241    statements.push(new ExpressionStatement(variable.set(transformFn(variable))));
33242  }
33243  return statements;
33244}
33245/**
33246 * Create the expression that will be used to guard the closure mode block
33247 * It is equivalent to:
33248 *
33249 * ```
33250 * typeof ngI18nClosureMode !== undefined && ngI18nClosureMode
33251 * ```
33252 */
33253function createClosureModeGuard() {
33254  return typeofExpr(variable(NG_I18N_CLOSURE_MODE)).notIdentical(literal('undefined', STRING_TYPE)).and(variable(NG_I18N_CLOSURE_MODE));
33255}
33256
33257/**
33258 * Translates query flags into `TQueryFlags` type in
33259 * packages/core/src/render3/interfaces/query.ts
33260 * @param query
33261 */
33262function toQueryFlags(query) {
33263  return (query.descendants ? 1 /* QueryFlags.descendants */ : 0 /* QueryFlags.none */) | (query.static ? 2 /* QueryFlags.isStatic */ : 0 /* QueryFlags.none */) | (query.emitDistinctChangesOnly ? 4 /* QueryFlags.emitDistinctChangesOnly */ : 0 /* QueryFlags.none */);
33264}
33265function getQueryPredicate(query, constantPool) {
33266  if (Array.isArray(query.predicate)) {
33267    let predicate = [];
33268    query.predicate.forEach(selector => {
33269      // Each item in predicates array may contain strings with comma-separated refs
33270      // (for ex. 'ref, ref1, ..., refN'), thus we extract individual refs and store them
33271      // as separate array entities
33272      const selectors = selector.split(',').map(token => literal(token.trim()));
33273      predicate.push(...selectors);
33274    });
33275    return constantPool.getConstLiteral(literalArr(predicate), true);
33276  } else {
33277    // The original predicate may have been wrapped in a `forwardRef()` call.
33278    switch (query.predicate.forwardRef) {
33279      case 0 /* ForwardRefHandling.None */:
33280      case 2 /* ForwardRefHandling.Unwrapped */:
33281        return query.predicate.expression;
33282      case 1 /* ForwardRefHandling.Wrapped */:
33283        return importExpr(Identifiers.resolveForwardRef).callFn([query.predicate.expression]);
33284    }
33285  }
33286}
33287function createQueryCreateCall(query, constantPool, queryTypeFns, prependParams) {
33288  const parameters = [];
33289  if (prependParams !== undefined) {
33290    parameters.push(...prependParams);
33291  }
33292  if (query.isSignal) {
33293    parameters.push(new ReadPropExpr(variable(CONTEXT_NAME), query.propertyName));
33294  }
33295  parameters.push(getQueryPredicate(query, constantPool), literal(toQueryFlags(query)));
33296  if (query.read) {
33297    parameters.push(query.read);
33298  }
33299  const queryCreateFn = query.isSignal ? queryTypeFns.signalBased : queryTypeFns.nonSignal;
33300  return importExpr(queryCreateFn).callFn(parameters);
33301}
33302const queryAdvancePlaceholder = Symbol('queryAdvancePlaceholder');
33303/**
33304 * Collapses query advance placeholders in a list of statements.
33305 *
33306 * This allows for less generated code because multiple sibling query advance
33307 * statements can be collapsed into a single call with the count as argument.
33308 *
33309 * e.g.
33310 *
33311 * ```ts
33312 *   bla();
33313 *   queryAdvance();
33314 *   queryAdvance();
33315 *   bla();
33316 * ```
33317 *
33318 *   --> will turn into
33319 *
33320 * ```
33321 *   bla();
33322 *   queryAdvance(2);
33323 *   bla();
33324 * ```
33325 */
33326function collapseAdvanceStatements(statements) {
33327  const result = [];
33328  let advanceCollapseCount = 0;
33329  const flushAdvanceCount = () => {
33330    if (advanceCollapseCount > 0) {
33331      result.unshift(importExpr(Identifiers.queryAdvance).callFn(advanceCollapseCount === 1 ? [] : [literal(advanceCollapseCount)]).toStmt());
33332      advanceCollapseCount = 0;
33333    }
33334  };
33335  // Iterate through statements in reverse and collapse advance placeholders.
33336  for (let i = statements.length - 1; i >= 0; i--) {
33337    const st = statements[i];
33338    if (st === queryAdvancePlaceholder) {
33339      advanceCollapseCount++;
33340    } else {
33341      flushAdvanceCount();
33342      result.unshift(st);
33343    }
33344  }
33345  flushAdvanceCount();
33346  return result;
33347}
33348// Define and update any view queries
33349function createViewQueriesFunction(viewQueries, constantPool, name) {
33350  const createStatements = [];
33351  const updateStatements = [];
33352  const tempAllocator = temporaryAllocator(st => updateStatements.push(st), TEMPORARY_NAME);
33353  viewQueries.forEach(query => {
33354    // creation call, e.g. r3.viewQuery(somePredicate, true) or
33355    //                r3.viewQuerySignal(ctx.prop, somePredicate, true);
33356    const queryDefinitionCall = createQueryCreateCall(query, constantPool, {
33357      signalBased: Identifiers.viewQuerySignal,
33358      nonSignal: Identifiers.viewQuery
33359    });
33360    createStatements.push(queryDefinitionCall.toStmt());
33361    // Signal queries update lazily and we just advance the index.
33362    if (query.isSignal) {
33363      updateStatements.push(queryAdvancePlaceholder);
33364      return;
33365    }
33366    // update, e.g. (r3.queryRefresh(tmp = r3.loadQuery()) && (ctx.someDir = tmp));
33367    const temporary = tempAllocator();
33368    const getQueryList = importExpr(Identifiers.loadQuery).callFn([]);
33369    const refresh = importExpr(Identifiers.queryRefresh).callFn([temporary.set(getQueryList)]);
33370    const updateDirective = variable(CONTEXT_NAME).prop(query.propertyName).set(query.first ? temporary.prop('first') : temporary);
33371    updateStatements.push(refresh.and(updateDirective).toStmt());
33372  });
33373  const viewQueryFnName = name ? `${name}_Query` : null;
33374  return fn([new FnParam(RENDER_FLAGS, NUMBER_TYPE), new FnParam(CONTEXT_NAME, null)], [renderFlagCheckIfStmt(1 /* core.RenderFlags.
33374Create */, createStatements), renderFlagCheckIfStmt(2 /* core.RenderFlags.Update */, collapseAdvanceStatements(updateStatements))], INFERRED_TYPE, null, viewQueryFnName);
33375}
33376// Define and update any content queries
33377function createContentQueriesFunction(queries, constantPool, name) {
33378  const createStatements = [];
33379  const updateStatements = [];
33380  const tempAllocator = temporaryAllocator(st => updateStatements.push(st), TEMPORARY_NAME);
33381  for (const query of queries) {
33382    // creation, e.g. r3.contentQuery(dirIndex, somePredicate, true, null) or
33383    //                r3.contentQuerySignal(dirIndex, propName, somePredicate, <flags>, <read>).
33384    createStatements.push(createQueryCreateCall(query, constantPool, {
33385      nonSignal: Identifiers.contentQuery,
33386      signalBased: Identifiers.contentQuerySignal
33387    }, /* prependParams */[variable('dirIndex')]).toStmt());
33388    // Signal queries update lazily and we just advance the index.
33389    if (query.isSignal) {
33390      updateStatements.push(queryAdvancePlaceholder);
33391      continue;
33392    }
33393    // update, e.g. (r3.queryRefresh(tmp = r3.loadQuery()) && (ctx.someDir = tmp));
33394    const temporary = tempAllocator();
33395    const getQueryList = importExpr(Identifiers.loadQuery).callFn([]);
33396    const refresh = importExpr(Identifiers.queryRefresh).callFn([temporary.set(getQueryList)]);
33397    const updateDirective = variable(CONTEXT_NAME).prop(query.propertyName).set(query.first ? temporary.prop('first') : temporary);
33398    updateStatements.push(refresh.and(updateDirective).toStmt());
33399  }
33400  const contentQueriesFnName = name ? `${name}_ContentQueries` : null;
33401  return fn([new FnParam(RENDER_FLAGS, NUMBER_TYPE), new FnParam(CONTEXT_NAME, null), new FnParam('dirIndex', null)], [renderFlagCheckIfStmt(1 /* core.RenderFlags.Create */, createStatements), renderFlagCheckIfStmt(2 /* core.RenderFlags.Update */, collapseAdvanceStatements(updateStatements))], INFERRED_TYPE, null, contentQueriesFnName);
33402}
33403
33404// This regex matches any binding names that contain the "attr." prefix, e.g. "attr.required"
33405// If there is a match, the first matching group will contain the attribute name to bind.
33406const ATTR_REGEX = /attr\.([^\]]+)/;
33407const COMPONENT_VARIABLE = '%COMP%';
33408const HOST_ATTR = `_nghost-${COMPONENT_VARIABLE}`;
33409const CONTENT_ATTR = `_ngcontent-${COMPONENT_VARIABLE}`;
33410function baseDirectiveFields(meta, constantPool, bindingParser) {
33411  const definitionMap = new DefinitionMap();
33412  const selectors = parseSelectorToR3Selector(meta.selector);
33413  // e.g. `type: MyDirective`
33414  definitionMap.set('type', meta.type.value);
33415  // e.g. `selectors: [['', 'someDir', '']]`
33416  if (selectors.length > 0) {
33417    definitionMap.set('selectors', asLiteral(selectors));
33418  }
33419  if (meta.queries.length > 0) {
33420    // e.g. `contentQueries: (rf, ctx, dirIndex) => { ... }
33421    definitionMap.set('contentQueries', createContentQueriesFunction(meta.queries, constantPool, meta.name));
33422  }
33423  if (meta.viewQueries.length) {
33424    definitionMap.set('viewQuery', createViewQueriesFunction(meta.viewQueries, constantPool, meta.name));
33425  }
33426  // e.g. `hostBindings: (rf, ctx) => { ... }
33427  definitionMap.set('hostBindings', createHostBindingsFunction(meta.host, meta.typeSourceSpan, bindingParser, constantPool, meta.selector || '', meta.name, definitionMap));
33428  // e.g 'inputs: {a: 'a'}`
33429  definitionMap.set('inputs', conditionallyCreateDirectiveBindingLiteral(meta.inputs, true));
33430  // e.g 'outputs: {a: 'a'}`
33431  definitionMap.set('outputs', conditionallyCreateDirectiveBindingLiteral(meta.outputs));
33432  if (meta.exportAs !== null) {
33433    definitionMap.set('exportAs', literalArr(meta.exportAs.map(e => literal(e))));
33434  }
33435  if (meta.isStandalone) {
33436    definitionMap.set('standalone', literal(true));
33437  }
33438  if (meta.isSignal) {
33439    definitionMap.set('signals', literal(true));
33440  }
33441  return definitionMap;
33442}
33443/**
33444 * Add features to the definition map.
33445 */
33446function addFeatures(definitionMap, meta) {
33447  // e.g. `features: [NgOnChangesFeature]`
33448  const features = [];
33449  const providers = meta.providers;
33450  const viewProviders = meta.viewProviders;
33451  const inputKeys = Object.keys(meta.inputs);
33452  if (providers || viewProviders) {
33453    const args = [providers || new LiteralArrayExpr([])];
33454    if (viewProviders) {
33455      args.push(viewProviders);
33456    }
33457    features.push(importExpr(Identifiers.ProvidersFeature).callFn(args));
33458  }
33459  for (const key of inputKeys) {
33460    if (meta.inputs[key].transformFunction !== null) {
33461      features.push(importExpr(Identifiers.InputTransformsFeatureFeature));
33462      break;
33463    }
33464  }
33465  // Note: host directives feature needs to be inserted before the
33466  // inheritance feature to ensure the correct execution order.
33467  if (meta.hostDirectives?.length) {
33468    features.push(importExpr(Identifiers.HostDirectivesFeature).callFn([createHostDirectivesFeatureArg(meta.hostDirectives)]));
33469  }
33470  if (meta.usesInheritance) {
33471    features.push(importExpr(Identifiers.InheritDefinitionFeature));
33472  }
33473  if (meta.fullInheritance) {
33474    features.push(importExpr(Identifiers.CopyDefinitionFeature));
33475  }
33476  if (meta.lifecycle.usesOnChanges) {
33477    features.push(importExpr(Identifiers.NgOnChangesFeature));
33478  }
33479  // TODO: better way of differentiating component vs directive metadata.
33480  if (meta.hasOwnProperty('template') && meta.isStandalone) {
33481    features.push(importExpr(Identifiers.StandaloneFeature));
33482  }
33483  if (features.length) {
33484    definitionMap.set('features', literalArr(features));
33485  }
33486}
33487/**
33488 * Compile a directive for the render3 runtime as defined by the `R3DirectiveMetadata`.
33489 */
33490function compileDirectiveFromMetadata(meta, constantPool, bindingParser) {
33491  const definitionMap = baseDirectiveFields(meta, constantPool, bindingParser);
33492  addFeatures(definitionMap, meta);
33493  const expression = importExpr(Identifiers.defineDirective).callFn([definitionMap.toLiteralMap()], undefined, true);
33494  const type = createDirectiveType(meta);
33495  return {
33496    expression,
33497    type,
33498    statements: []
33499  };
33500}
33501/**
33502 * Creates an AST for a function that contains dynamic imports representing
33503 * deferrable dependencies.
33504 */
33505function createDeferredDepsFunction(constantPool, name, deps) {
33506  // This defer block has deps for which we need to generate dynamic imports.
33507  const dependencyExp = [];
33508  for (const [symbolName, {
33509    importPath,
33510    isDefaultImport
33511  }] of deps) {
33512    // Callback function, e.g. `m () => m.MyCmp;`.
33513    const innerFn = arrowFn([new FnParam('m', DYNAMIC_TYPE)], variable('m').prop(isDefaultImport ? 'default' : symbolName));
33514    // Dynamic import, e.g. `import('./a').then(...)`.
33515    const importExpr = new DynamicImportExpr(importPath).prop('then').callFn([innerFn]);
33516    dependencyExp.push(importExpr);
33517  }
33518  const depsFnExpr = arrowFn([], literalArr(dependencyExp));
33519  constantPool.statements.push(depsFnExpr.toDeclStmt(name, StmtModifier.Final));
33520  return variable(name);
33521}
33522/**
33523 * Compile a component for the render3 runtime as defined by the `R3ComponentMetadata`.
33524 */
33525function compileComponentFromMetadata(meta, constantPool, bindingParser) {
33526  const definitionMap = baseDirectiveFields(meta, constantPool, bindingParser);
33527  addFeatures(definitionMap, meta);
33528  const selector = meta.selector && CssSelector.parse(meta.selector);
33529  const firstSelector = selector && selector[0];
33530  // e.g. `attr: ["class", ".my.app"]`
33531  // This is optional an only included if the first selector of a component specifies attributes.
33532  if (firstSelector) {
33533    const selectorAttributes = firstSelector.getAttrs();
33534    if (selectorAttributes.length) {
33535      definitionMap.set('attrs', constantPool.getConstLiteral(literalArr(selectorAttributes.map(value => value != null ? literal(value) : literal(undefined))), /* forceShared */true));
33536    }
33537  }
33538  // e.g. `template: function MyComponent_Template(_ctx, _cm) {...}`
33539  const templateTypeName = meta.name;
33540  const templateName = templateTypeName ? `${templateTypeName}_Template` : null;
33541  let allDeferrableDepsFn = null;
33542  if (meta.deferBlocks.size > 0 && meta.deferrableTypes.size > 0 && meta.deferBlockDepsEmitMode === 1 /* DeferBlockDepsEmitMode.PerComponent */) {
33543    const fnName = `${templateTypeName}_DeferFn`;
33544    allDeferrableDepsFn = createDeferredDepsFunction(constantPool, fnName, meta.deferrableTypes);
33545  }
33546  // Template compilation is currently conditional as we're in the process of rewriting it.
33547  if (!USE_TEMPLATE_PIPELINE && !meta.useTemplatePipeline) {
33548    // This is the main path currently used in compilation, which compiles the template with the
33549    // legacy `TemplateDefinitionBuilder`.
33550    const template = meta.template;
33551    const templateBuilder = new TemplateDefinitionBuilder(constantPool, BindingScope.createRootScope(), 0, templateTypeName, null, null, templateName, Identifiers.namespaceHTML, meta.relativeContextFilePath, meta.i18nUseExternalIds, meta.deferBlocks, new Map(), allDeferrableDepsFn);
33552    const templateFunctionExpression = templateBuilder.buildTemplateFunction(template.nodes, []);
33553    // We need to provide this so that dynamically generated components know what
33554    // projected content blocks to pass through to the component when it is
33555    //     instantiated.
33556    const ngContentSelectors = templateBuilder.getNgContentSelectors();
33557    if (ngContentSelectors) {
33558      definitionMap.set('ngContentSelectors', ngContentSelectors);
33559    }
33560    // e.g. `decls: 2`
33561    // definitionMap.set('decls', o.literal(tpl.root.decls!));
33562    definitionMap.set('decls', literal(templateBuilder.getConstCount()));
33563    // e.g. `vars: 2`
33564    // definitionMap.set('vars', o.literal(tpl.root.vars!));
33565    definitionMap.set('vars', literal(templateBuilder.getVarCount()));
33566    // Generate `consts` section of ComponentDef:
33567    // - either as an array:
33568    //   `consts: [['one', 'two'], ['three', 'four']]`
33569    // - or as a factory function in case additional statements are present (to support i18n):
33570    //   `consts: () => { var i18n_0; if (ngI18nClosureMode) {...} else {...} return [i18n_0];
33571    //   }`
33572    const {
33573      constExpressions,
33574      prepareStatements
33575    } = templateBuilder.getConsts();
33576    if (constExpressions.length > 0) {
33577      let constsExpr = literalArr(constExpressions);
33578      // Prepare statements are present - turn `consts` into a function.
33579      if (prepareStatements.length > 0) {
33580        constsExpr = arrowFn([], [...prepareStatements, new ReturnStatement
33580(constsExpr)]);
33581      }
33582      definitionMap.set('consts', constsExpr);
33583    }
33584    definitionMap.set('template', templateFunctionExpression);
33585  } else {
33586    // This path compiles the template using the prototype template pipeline. First the template is
33587    // ingested into IR:
33588    const tpl = ingestComponent(meta.name, meta.template.nodes, constantPool, meta.relativeContextFilePath, meta.i18nUseExternalIds, meta.deferBlocks, allDeferrableDepsFn);
33589    // Then the IR is transformed to prepare it for cod egeneration.
33590    transform(tpl, CompilationJobKind.Tmpl);
33591    // Finally we emit the template function:
33592    const templateFn = emitTemplateFn(tpl, constantPool);
33593    if (tpl.contentSelectors !== null) {
33594      definitionMap.set('ngContentSelectors', tpl.contentSelectors);
33595    }
33596    definitionMap.set('decls', literal(tpl.root.decls));
33597    definitionMap.set('vars', literal(tpl.root.vars));
33598    if (tpl.consts.length > 0) {
33599      if (tpl.constsInitializers.length > 0) {
33600        definitionMap.set('consts', arrowFn([], [...tpl.constsInitializers, new ReturnStatement
33600(literalArr(tpl.consts))]));
33601      } else {
33602        definitionMap.set('consts', literalArr(tpl.consts));
33603      }
33604    }
33605    definitionMap.set('template', templateFn);
33606  }
33607  if (meta.declarationListEmitMode !== 3 /* DeclarationListEmitMode.RuntimeResolved */ && meta.declarations.length > 0) {
33608    definitionMap.set('dependencies', compileDeclarationList(literalArr(meta.declarations.map(decl => decl.type)), meta.declarationListEmitMode));
33609  } else if (meta.declarationListEmitMode === 3 /* DeclarationListEmitMode.RuntimeResolved */) {
33610    const args = [meta.type.value];
33611    if (meta.rawImports) {
33612      args.push(meta.rawImports);
33613    }
33614    definitionMap.set('dependencies', importExpr(Identifiers.getComponentDepsFactory).callFn(args));
33615  }
33616  if (meta.encapsulation === null) {
33617    meta.encapsulation = ViewEncapsulation.Emulated;
33618  }
33619  // e.g. `styles: [str1, str2]`
33620  if (meta.styles && meta.styles.length) {
33621    const styleValues = meta.encapsulation == ViewEncapsulation.Emulated ? compileStyles(meta.styles, CONTENT_ATTR, HOST_ATTR) : meta.styles;
33622    const styleNodes = styleValues.reduce((result, style) => {
33623      if (style.trim().length > 0) {
33624        result.push(constantPool.getConstLiteral(literal(style)));
33625      }
33626      return result;
33627    }, []);
33628    if (styleNodes.length > 0) {
33629      definitionMap.set('styles', literalArr(styleNodes));
33630    }
33631  } else if (meta.encapsulation === ViewEncapsulation.Emulated) {
33632    // If there is no style, don't generate css selectors on elements
33633    meta.encapsulation = ViewEncapsulation.None;
33634  }
33635  // Only set view encapsulation if it's not the default value
33636  if (meta.encapsulation !== ViewEncapsulation.Emulated) {
33637    definitionMap.set('encapsulation', literal(meta.encapsulation));
33638  }
33639  // e.g. `animation: [trigger('123', [])]`
33640  if (meta.animations !== null) {
33641    definitionMap.set('data', literalMap([{
33642      key: 'animation',
33643      value: meta.animations,
33644      quoted: false
33645    }]));
33646  }
33647  // Setting change detection flag
33648  if (meta.changeDetection !== null) {
33649    if (typeof meta.changeDetection === 'number' && meta.changeDetection !== ChangeDetectionStrategy.Default) {
33650      // changeDetection is resolved during analysis. Only set it if not the default.
33651      definitionMap.set('changeDetection', literal(meta.changeDetection));
33652    } else if (typeof meta.changeDetection === 'object') {
33653      // changeDetection is not resolved during analysis (e.g., we are in local compilation mode).
33654      // So place it as is.
33655      definitionMap.set('changeDetection', meta.changeDetection);
33656    }
33657  }
33658  const expression = importExpr(Identifiers.defineComponent).callFn([definitionMap.toLiteralMap()], undefined, true);
33659  const type = createComponentType(meta);
33660  return {
33661    expression,
33662    type,
33663    statements: []
33664  };
33665}
33666/**
33667 * Creates the type specification from the component meta. This type is inserted into .d.ts files
33668 * to be consumed by upstream compilations.
33669 */
33670function createComponentType(meta) {
33671  const typeParams = createBaseDirectiveTypeParams(meta);
33672  typeParams.push(stringArrayAsType(meta.template.ngContentSelectors));
33673  typeParams.push(expressionType(literal(meta.isStandalone)));
33674  typeParams.push(createHostDirectivesType(meta));
33675  // TODO(signals): Always include this metadata starting with v17. Right
33676  // now Angular v16.0.x does not support this field and library distributions
33677  // would then be incompatible with v16.0.x framework users.
33678  if (meta.isSignal) {
33679    typeParams.push(expressionType(literal(meta.isSignal)));
33680  }
33681  return expressionType(importExpr(Identifiers.ComponentDeclaration, typeParams));
33682}
33683/**
33684 * Compiles the array literal of declarations into an expression according to the provided emit
33685 * mode.
33686 */
33687function compileDeclarationList(list, mode) {
33688  switch (mode) {
33689    case 0 /* DeclarationListEmitMode.Direct */:
33690      // directives: [MyDir],
33691      return list;
33692    case 1 /* DeclarationListEmitMode.Closure */:
33693      // directives: function () { return [MyDir]; }
33694      return arrowFn([], list);
33695    case 2 /* DeclarationListEmitMode.ClosureResolved */:
33696      // directives: function () { return [MyDir].map(ng.resolveForwardRef); }
33697      const resolvedList = list.prop('map').callFn([importExpr(Identifiers.resolveForwardRef)]);
33698      return arrowFn([], resolvedList);
33699    case 3 /* DeclarationListEmitMode.RuntimeResolved */:
33700      throw new Error(`Unsupported with an array of pre-resolved dependencies`);
33701  }
33702}
33703function convertAttributesToExpressions(attributes) {
33704  const values = [];
33705  for (let key of Object.getOwnPropertyNames(attributes)) {
33706    const value = attributes[key];
33707    values.push(literal(key), value);
33708  }
33709  return values;
33710}
33711function stringAsType(str) {
33712  return expressionType(literal(str));
33713}
33714function stringMapAsLiteralExpression(map) {
33715  const mapValues = Object.keys(map).map(key => {
33716    const value = Array.isArray(map[key]) ? map[key][0] : map[key];
33717    return {
33718      key,
33719      value: literal(value),
33720      quoted: true
33721    };
33722  });
33723  return literalMap(mapValues);
33724}
33725function stringArrayAsType(arr) {
33726  return arr.length > 0 ? expressionType(literalArr(arr.map(value => literal(value)))) : NONE_TYPE;
33727}
33728function createBaseDirectiveTypeParams(meta) {
33729  // On the type side, remove newlines from the selector as it will need to fit into a TypeScript
33730  // string literal, which must be on one line.
33731  const selectorForType = meta.selector !== null ? meta.selector.replace(/\n/g, '') : null;
33732  return [typeWithParameters(meta.type.type, meta.typeArgumentCount), selectorForType !== null ? stringAsType(selectorForType) : NONE_TYPE, meta.exportAs !== null ? stringArrayAsType(meta.exportAs) : NONE_TYPE, expressionType(getInputsTypeExpression(meta)), expressionType(stringMapAsLiteralExpression(meta.outputs)), stringArrayAsType(meta.queries.map(q => q.propertyName))];
33733}
33734function getInputsTypeExpression(meta) {
33735  return literalMap(Object.keys(meta.inputs).map(key => {
33736    const value = meta.inputs[key];
33737    const values = [{
33738      key: 'alias',
33739      value: literal(value.bindingPropertyName),
33740      quoted: true
33741    }, {
33742      key: 'required',
33743      value: literal(value.required),
33744      quoted: true
33745    }];
33746    // TODO(legacy-partial-output-inputs): Consider always emitting this information,
33747    // or leaving it as is.
33748    if (value.isSignal) {
33749      values.push({
33750        key: 'isSignal',
33751        value: literal(value.isSignal),
33752        quoted: true
33753      });
33754    }
33755    return {
33756      key,
33757      value: literalMap(values),
33758      quoted: true
33759    };
33760  }));
33761}
33762/**
33763 * Creates the type specification from the directive meta. This type is inserted into .d.ts files
33764 * to be consumed by upstream compilations.
33765 */
33766function createDirectiveType(meta) {
33767  const typeParams = createBaseDirectiveTypeParams(meta);
33768  // Directives have no NgContentSelectors slot, but instead express a `never` type
33769  // so that future fields align.
33770  typeParams.push(NONE_TYPE);
33771  typeParams.push(expressionType(literal(meta.isStandalone)));
33772  typeParams.push(createHostDirectivesType(meta));
33773  // TODO(signals): Always include this metadata starting with v17. Right
33774  // now Angular v16.0.x does not support this field and library distributions
33775  // would then be incompatible with v16.0.x framework users.
33776  if (meta.isSignal) {
33777    typeParams.push(expressionType(literal(meta.isSignal)));
33778  }
33779  return expressionType(importExpr(Identifiers.DirectiveDeclaration, typeParams));
33780}
33781// Return a host binding function or null if one is not necessary.
33782function createHostBindingsFunction(hostBindingsMetadata, typeSourceSpan, bindingParser, constantPool, selector, name, definitionMap) {
33783  const bindings = bindingParser.createBoundHostProperties(hostBindingsMetadata.properties, typeSourceSpan);
33784  // Calculate host event bindings
33785  const eventBindings = bindingParser.createDirectiveHostEventAsts(hostBindingsMetadata.listeners, typeSourceSpan);
33786  if (USE_TEMPLATE_PIPELINE || hostBindingsMetadata.useTemplatePipeline) {
33787    // The parser for host bindings treats class and style attributes specially -- they are
33788    // extracted into these separate fields. This is not the case for templates, so the compiler can
33789    // actually already handle these special attributes internally. Therefore, we just drop them
33790    // into the attributes map.
33791    if (hostBindingsMetadata.specialAttributes.styleAttr) {
33792      hostBindingsMetadata.attributes['style'] = literal(hostBindingsMetadata.specialAttributes.styleAttr);
33793    }
33794    if (hostBindingsMetadata.specialAttributes.classAttr) {
33795      hostBindingsMetadata.attributes['class'] = literal(hostBindingsMetadata.specialAttributes.classAttr);
33796    }
33797    const hostJob = ingestHostBinding({
33798      componentName: name,
33799      componentSelector: selector,
33800      properties: bindings,
33801      events: eventBindings,
33802      attributes: hostBindingsMetadata.attributes
33803    }, bindingParser, constantPool);
33804    transform(hostJob, CompilationJobKind.Host);
33805    definitionMap.set('hostAttrs', hostJob.root.attributes);
33806    const varCount = hostJob.root.vars;
33807    if (varCount !== null && varCount > 0) {
33808      definitionMap.set('hostVars', literal(varCount));
33809    }
33810    return emitHostBindingFunction(hostJob);
33811  }
33812  let bindingId = 0;
33813  const getNextBindingId = () => `${bindingId++}`;
33814  const bindingContext = variable(CONTEXT_NAME);
33815  const styleBuilder = new StylingBuilder(bindingContext);
33816  const {
33817    styleAttr,
33818    classAttr
33819  }
33819 = hostBindingsMetadata.specialAttributes;
33820  if (styleAttr !== undefined) {
33821    styleBuilder.registerStyleAttr(styleAttr);
33822  }
33823  if (classAttr !== undefined) {
33824    styleBuilder.registerClassAttr(classAttr);
33825  }
33826  const createInstructions = [];
33827  const updateInstructions = [];
33828  const updateVariables = [];
33829  const hostBindingSourceSpan = typeSourceSpan;
33830  if (eventBindings && eventBindings.length) {
33831    createInstructions.push(...createHostListeners(eventBindings, name));
33832  }
33833  // Calculate the host property bindings
33834  const allOtherBindings = [];
33835  // We need to calculate the total amount of binding slots required by
33836  // all the instructions together before any value conversions happen.
33837  // Value conversions may require additional slots for interpolation and
33838  // bindings with pipes. These calculates happen after this block.
33839  let totalHostVarsCount = 0;
33840  bindings && bindings.forEach(binding => {
33841    const stylingInputWasSet = styleBuilder.registerInputBasedOnName(binding.name, binding.expression, hostBindingSourceSpan);
33842    if (stylingInputWasSet) {
33843      totalHostVarsCount += MIN_STYLING_BINDING_SLOTS_REQUIRED;
33844    } else {
33845      allOtherBindings.push(binding);
33846      totalHostVarsCount++;
33847    }
33848  });
33849  let valueConverter;
33850  const getValueConverter = () => {
33851    if (!valueConverter) {
33852      const hostVarsCountFn = numSlots => {
33853        const originalVarsCount = totalHostVarsCount;
33854        totalHostVarsCount += numSlots;
33855        return originalVarsCount;
33856      };
33857      valueConverter = new ValueConverter(constantPool, () => error('Unexpected node'),
33858      // new nodes are illegal here
33859      hostVarsCountFn, () => error('Unexpected pipe')); // pipes are illegal here
33860    }
33861    return valueConverter;
33862  };
33863  const propertyBindings = [];
33864  const attributeBindings = [];
33865  const syntheticHostBindings = [];
33866  for (const binding of allOtherBindings) {
33867    // resolve literal arrays and literal objects
33868    const value = binding.expression.visit(getValueConverter());
33869    const bindingExpr = bindingFn(bindingContext, value, getNextBindingId);
33870    const {
33871      bindingName,
33872      instruction,
33873      isAttribute
33874    } = getBindingNameAndInstruction(binding);
33875    const securityContexts = bindingParser.calcPossibleSecurityContexts(selector, bindingName, isAttribute).filter(context => context !== SecurityContext.NONE);
33876    let sanitizerFn = null;
33877    if (securityContexts.length) {
33878      if (securityContexts.length === 2 && securityContexts.indexOf(SecurityContext.URL) > -1 && securityContexts.indexOf(SecurityContext.RESOURCE_URL) > -1) {
33879        // Special case for some URL attributes (such as "src" and "href") that may be a part
33880        // of different security contexts. In this case we use special sanitization function and
33881        // select the actual sanitizer at runtime based on a tag name that is provided while
33882        // invoking sanitization function.
33883        sanitizerFn = importExpr(Identifiers.sanitizeUrlOrResourceUrl);
33884      } else {
33885        sanitizerFn = resolveSanitizationFn(securityContexts[0], isAttribute);
33886      }
33887    }
33888    const instructionParams = [literal(bindingName), bindingExpr.currValExpr];
33889    if (sanitizerFn) {
33890      instructionParams.push(sanitizerFn);
33891    } else {
33892      // If there was no sanitization function found based on the security context
33893      // of an attribute/property binding - check whether this attribute/property is
33894      // one of the security-sensitive <iframe> attributes.
33895      // Note: for host bindings defined on a directive, we do not try to find all
33896      // possible places where it can be matched, so we can not determine whether
33897      // the host element is an <iframe>. In this case, if an attribute/binding
33898      // name is in the `IFRAME_SECURITY_SENSITIVE_ATTRS` set - append a validation
33899      // function, which would be invoked at runtime and would have access to the
33900      // underlying DOM element, check if it's an <iframe> and if so - runs extra checks.
33901      if (isIframeSecuritySensitiveAttr(bindingName)) {
33902        instructionParams.push(importExpr(Identifiers.validateIframeAttribute));
33903      }
33904    }
33905    updateVariables.push(...bindingExpr.stmts);
33906    if (instruction === Identifiers.hostProperty) {
33907      propertyBindings.push(instructionParams);
33908    } else if (instruction === Identifiers.attribute) {
33909      attributeBindings.push(instructionParams);
33910    } else if (instruction === Identifiers.syntheticHostProperty) {
33911      syntheticHostBindings.push(instructionParams);
33912    } else {
33913      updateInstructions.push({
33914        reference: instruction,
33915        paramsOrFn: instructionParams,
33916        span: null
33917      });
33918    }
33919  }
33920  for (const bindingParams of propertyBindings) {
33921    updateInstructions.push({
33922      reference: Identifiers.hostProperty,
33923      paramsOrFn: bindingParams,
33924      span: null
33925    });
33926  }
33927  for (const bindingParams of attributeBindings) {
33928    updateInstructions.push({
33929      reference: Identifiers.attribute,
33930      paramsOrFn: bindingParams,
33931      span: null
33932    });
33933  }
33934  for (const bindingParams of syntheticHostBindings) {
33935    updateInstructions.push({
33936      reference: Identifiers.syntheticHostProperty,
33937      paramsOrFn: bindingParams,
33938      span: null
33939    });
33940  }
33941  // since we're dealing with directives/components and both have hostBinding
33942  // functions, we need to generate a special hostAttrs instruction that deals
33943  // with both the assignment of styling as well as static attributes to the host
33944  // element. The instruction below will instruct all initial styling (styling
33945  // that is inside of a host binding within a directive/component) to be attached
33946  // to the host element alongside any of the provided host attributes that were
33947  // collected earlier.
33948  const hostAttrs = convertAttributesToExpressions(hostBindingsMetadata.attributes);
33949  styleBuilder.assignHostAttrs(hostAttrs, definitionMap);
33950  if (styleBuilder.hasBindings) {
33951    // finally each binding that was registered in the statement above will need to be added to
33952    // the update block of a component/directive templateFn/hostBindingsFn so that the bindings
33953    // are evaluated and updated for the element.
33954    styleBuilder.buildUpdateLevelInstructions(getValueConverter()).forEach(instruction => {
33955      for (const call of instruction.calls) {
33956        // we subtract a value of `1` here because the binding slot was already allocated
33957        // at the top of this method when all the input bindings were counted.
33958        totalHostVarsCount += Math.max(call.allocateBindingSlots - MIN_STYLING_BINDING_SLOTS_REQUIRED, 0);
33959        const {
33960          params,
33961          stmts
33962        } = convertStylingCall(call, bindingContext, bindingFn, getNextBindingId);
33963        updateVariables.push(...stmts);
33964        updateInstructions.push({
33965          reference: instruction.reference,
33966          paramsOrFn: params,
33967          span: null
33968        });
33969      }
33970    });
33971  }
33972  if (totalHostVarsCount) {
33973    definitionMap.set('hostVars', literal(totalHostVarsCount));
33974  }
33975  if (createInstructions.length > 0 || updateInstructions.length > 0) {
33976    const hostBindingsFnName = name ? `${name}_HostBindings` : null;
33977    const statements = [];
33978    if (createInstructions.length > 0) {
33979      statements.push(renderFlagCheckIfStmt(1 /* core.RenderFlags.Create */, getInstructionStatements(createInstructions)));
33980    }
33981    if (updateInstructions.length > 0) {
33982      statements.push(renderFlagCheckIfStmt(2 /* core.RenderFlags.Update */, updateVariables.concat(getInstructionStatements(updateInstructions))));
33983    }
33984    return fn([new FnParam(RENDER_FLAGS, NUMBER_TYPE), new FnParam(CONTEXT_NAME, null)], statements, INFERRED_TYPE, null, hostBindingsFnName);
33985  }
33986  return null;
33987}
33988function bindingFn(implicit, value, getNextBindingIdFn) {
33989  return convertPropertyBinding(null, implicit, value, getNextBindingIdFn());
33990}
33991function convertStylingCall(call, bindingContext, bindingFn, getNextBindingIdFn) {
33992  const stmts = [];
33993  const params = call.params(value => {
33994    const result = bindingFn(bindingContext, value, getNextBindingIdFn);
33995    if (Array.isArray(result.stmts) && result.stmts.length > 0) {
33996      stmts.push(...result.stmts);
33997    }
33998    return result.currValExpr;
33999  });
34000  return {
34001    params,
34002    stmts
34003  };
34004}
34005function getBindingNameAndInstruction(binding) {
34006  let bindingName = binding.name;
34007  let instruction;
34008  // Check to see if this is an attr binding or a property binding
34009  const attrMatches = bindingName.match(ATTR_REGEX);
34010  if (attrMatches) {
34011    bindingName = attrMatches[1];
34012    instruction = Identifiers.attribute;
34013  } else {
34014    if (binding.isAnimation) {
34015      bindingName = prepareSyntheticPropertyName(bindingName);
34016      // host bindings that have a synthetic property (e.g. @foo) should always be rendered
34017      // in the context of the component and not the parent. Therefore there is a special
34018      // compatibility instruction available for this purpose.
34019      instruction = Identifiers.syntheticHostProperty;
34020    } else {
34021      instruction = Identifiers.hostProperty;
34022    }
34023  }
34024  return {
34025    bindingName,
34026    instruction,
34027    isAttribute: !!attrMatches
34028  };
34029}
34030function createHostListeners(eventBindings, name) {
34031  const listenerParams = [];
34032  const syntheticListenerParams = [];
34033  const instructions = [];
34034  for (const binding of eventBindings) {
34035    let bindingName = binding.name && sanitizeIdentifier(binding.name);
34036    const bindingFnName = binding.type === 1 /* ParsedEventType.Animation */ ? prepareSyntheticListenerFunctionName(bindingName, binding.targetOrPhase) : bindingName;
34037    const handlerName = name && bindingName ? `${name}_${bindingFnName}_HostBindingHandler` : null;
34038    const params = prepareEventListenerParameters(BoundEvent.fromParsedEvent(binding), handlerName);
34039    if (binding.type == 1 /* ParsedEventType.Animation */) {
34040      syntheticListenerParams.push(params);
34041    } else {
34042      listenerParams.push(params);
34043    }
34044  }
34045  for (const params of syntheticListenerParams) {
34046    instructions.push({
34047      reference: Identifiers.syntheticHostListener,
34048      paramsOrFn: params,
34049      span: null
34050    });
34051  }
34052  for (const params of listenerParams) {
34053    instructions.push({
34054      reference: Identifiers.listener,
34055      paramsOrFn: params,
34056      span: null
34057    });
34058  }
34059  return instructions;
34060}
34061const HOST_REG_EXP = /^(?:\[([^\]]+)\])|(?:\(([^\)]+)\))$/;
34062function parseHostBindings(host) {
34063  const attributes = {};
34064  const listeners = {};
34065  const properties = {};
34066  const specialAttributes = {};
34067  for (const key of Object.keys(host)) {
34068    const value = host[key];
34069    const matches = key.match(HOST_REG_EXP);
34070    if (matches === null) {
34071      switch (key) {
34072        case 'class':
34073          if (typeof value !== 'string') {
34074            // TODO(alxhub): make this a diagnostic.
34075            throw new Error(`Class binding must be string`);
34076          }
34077          specialAttributes.classAttr = value;
34078          break;
34079        case 'style':
34080          if (typeof value !== 'string') {
34081            // TODO(alxhub): make this a diagnostic.
34082            throw new Error(`Style binding must be string`);
34083          }
34084          specialAttributes.styleAttr = value;
34085          break;
34086        default:
34087          if (typeof value === 'string') {
34088            attributes[key] = literal(value);
34089          } else {
34090            attributes[key] = value;
34091          }
34092      }
34093    } else if (matches[1 /* HostBindingGroup.Binding */] != null) {
34094      if (typeof value !== 'string') {
34095        // TODO(alxhub): make this a diagnostic.
34096        throw new Error(`Property binding must be string`);
34097      }
34098      // synthetic properties (the ones that have a `@` as a prefix)
34099      // are still treated the same as regular properties. Therefore
34100      // there is no point in storing them in a separate map.
34101      properties[matches[1 /* HostBindingGroup.Binding */]] = value;
34102    } else if (matches[2 /* HostBindingGroup.Event */] != null) {
34103      if (typeof value !== 'string') {
34104        // TODO(alxhub): make this a diagnostic.
34105        throw new Error(`Event binding must be string`);
34106      }
34107      listeners[matches[2 /* HostBindingGroup.Event */]] = value;
34108    }
34109  }
34110  return {
34111    attributes,
34112    listeners,
34113    properties,
34114    specialAttributes
34115  };
34116}
34117/**
34118 * Verifies host bindings and returns the list of errors (if any). Empty array indicates that a
34119 * given set of host bindings has no errors.
34120 *
34121 * @param bindings set of host bindings to verify.
34122 * @param sourceSpan source span where host bindings were defined.
34123 * @returns array of errors associated with a given set of host bindings.
34124 */
34125function verifyHostBindings(bindings, sourceSpan) {
34126  // TODO: abstract out host bindings verification logic and use it instead of
34127  // creating events and properties ASTs to detect errors (FW-996)
34128  const bindingParser = makeBindingParser();
34129  bindingParser.createDirectiveHostEventAsts(bindings.listeners, sourceSpan);
34130  bindingParser.createBoundHostProperties(bindings.properties, sourceSpan);
34131  return bindingParser.errors;
34132}
34133function compileStyles(styles, selector, hostSelector) {
34134  const shadowCss = new ShadowCss();
34135  return styles.map(style => {
34136    return shadowCss.shimCssText(style, selector, hostSelector);
34137  });
34138}
34139/**
34140 * Encapsulates a CSS stylesheet with emulated view encapsulation.
34141 * This allows a stylesheet to be used with an Angular component that
34142 * is using the `ViewEncapsulation.Emulated` mode.
34143 *
34144 * @param style The content of a CSS stylesheet.
34145 * @returns The encapsulated content for the style.
34146 */
34147function encapsulateStyle(style) {
34148  const shadowCss = new ShadowCss();
34149  return shadowCss.shimCssText(style, CONTENT_ATTR, HOST_ATTR);
34150}
34151function createHostDirectivesType(meta) {
34152  if (!meta.hostDirectives?.length) {
34153    return NONE_TYPE;
34154  }
34155  return expressionType(literalArr(meta.hostDirectives.map(hostMeta => literalMap([{
34156    key: 'directive',
34157    value: typeofExpr(hostMeta.directive.type),
34158    quoted: false
34159  }, {
34160    key: 'inputs',
34161    value: stringMapAsLiteralExpression(hostMeta.inputs || {}),
34162    quoted: false
34163  }, {
34164    key: 'outputs',
34165    value: stringMapAsLiteralExpression(hostMeta.outputs || {}),
34166    quoted: false
34167  }]))));
34168}
34169function createHostDirectivesFeatureArg(hostDirectives) {
34170  const expressions = [];
34171  let hasForwardRef = false;
34172  for (const current of hostDirectives) {
34173    // Use a shorthand if there are no inputs or outputs.
34174    if (!current.inputs && !current.outputs) {
34175      expressions.push(current.directive.type);
34176    } else {
34177      const keys = [{
34178        key: 'directive',
34179        value: current.directive.type,
34180        quoted: false
34181      }];
34182      if (current.inputs) {
34183        const inputsLiteral = createHostDirectivesMappingArray(current.inputs);
34184        if (inputsLiteral) {
34185          keys.push({
34186            key: 'inputs',
34187            value: inputsLiteral,
34188            quoted: false
34189          });
34190        }
34191      }
34192      if (current.outputs) {
34193        const outputsLiteral = createHostDirectivesMappingArray(current.outputs);
34194        if (outputsLiteral) {
34195          keys.push({
34196            key: 'outputs',
34197            value: outputsLiteral,
34198            quoted: false
34199          });
34200        }
34201      }
34202      expressions.push(literalMap(keys));
34203    }
34204    if (current.isForwardReference) {
34205      hasForwardRef = true;
34206    }
34207  }
34208  // If there's a forward reference, we generate a `function() { return [HostDir] }`,
34209  // otherwise we can save some bytes by using a plain array, e.g. `[HostDir]`.
34210  return hasForwardRef ? new FunctionExpr([], [new ReturnStatement
34210(literalArr(expressions))]) : literalArr(expressions);
34211}
34212/**
34213 * Converts an input/output mapping object literal into an array where the even keys are the
34214 * public name of the binding and the odd ones are the name it was aliased to. E.g.
34215 * `{inputOne: 'aliasOne', inputTwo: 'aliasTwo'}` will become
34216 * `['inputOne', 'aliasOne', 'inputTwo', 'aliasTwo']`.
34217 *
34218 * This conversion is necessary, because hosts bind to the public name of the host directive and
34219 * keeping the mapping in an object literal will break for apps using property renaming.
34220 */
34221function createHostDirectivesMappingArray(mapping) {
34222  const elements = [];
34223  for (const publicName in mapping) {
34224    if (mapping.hasOwnProperty(publicName)) {
34225      elements.push(literal(publicName), literal(mapping[publicName]));
34226    }
34227  }
34228  return elements.length > 0 ? literalArr(elements) : null;
34229}
34230
34231/**
34232 * Processes `Target`s with a given set of directives and performs a binding operation, which
34233 * returns an object similar to TypeScript's `ts.TypeChecker` that contains knowledge about the
34234 * target.
34235 */
34236class R3TargetBinder {
34237  constructor(directiveMatcher) {
34238    this.directiveMatcher = directiveMatcher;
34239  }
34240  /**
34241   * Perform a binding operation on the given `Target` and return a `BoundTarget` which contains
34242   * metadata about the types referenced in the template.
34243   */
34244  bind(target) {
34245    if (!target.template) {
34246      // TODO(alxhub): handle targets which contain things like HostBindings, etc.
34247      throw new Error('Binding without a template not yet supported');
34248    }
34249    // First, parse the template into a `Scope` structure. This operation captures the syntactic
34250    // scopes in the template and makes them available for later use.
34251    const scope = Scope.apply(target.template);
34252    // Use the `Scope` to extract the entities present at every level of the template.
34253    const scopedNodeEntities = extractScopedNodeEntities(scope);
34254    // Next, perform directive matching on the template using the `DirectiveBinder`. This returns:
34255    //   - directives: Map of nodes (elements & ng-templates) to the directives on them.
34256    //   - bindings: Map of inputs, outputs, and attributes to the directive/element that claims
34257    //     them. TODO(alxhub): handle multiple directives claiming an input/output/etc.
34258    //   - references: Map of #references to their targets.
34259    const {
34260      directives,
34261      eagerDirectives,
34262      bindings,
34263      references
34264    } = DirectiveBinder.apply(target.template, this.directiveMatcher);
34265    // Finally, run the TemplateBinder to bind references, variables, and other entities within the
34266    // template. This extracts all the metadata that doesn't depend on directive matching.
34267    const {
34268      expressions,
34269      symbols,
34270      nestingLevel,
34271      usedPipes,
34272      eagerPipes,
34273      deferBlocks
34274    } = TemplateBinder.applyWithScope(target.template, scope);
34275    return new R3BoundTarget(target, directives, eagerDirectives, bindings, references, expressions, symbols, nestingLevel, scopedNodeEntities, usedPipes, eagerPipes, deferBlocks);
34276  }
34277}
34278/**
34279 * Represents a binding scope within a template.
34280 *
34281 * Any variables, references, or other named entities declared within the template will
34282 * be captured and available by name in `namedEntities`. Additionally, child templates will
34283 * be analyzed and have their child `Scope`s available in `childScopes`.
34284 */
34285class Scope {
34286  constructor(parentScope, rootNode) {
34287    this.parentScope = parentScope;
34288    this.rootNode = rootNode;
34289    /**
34290     * Named members of the `Scope`, such as `Reference`s or `Variable`s.
34291     */
34292    this.namedEntities = new Map();
34293    /**
34294     * Set of elements that belong to this scope.
34295     */
34296    this.elementsInScope = new Set();
34297    /**
34298     * Child `Scope`s for immediately nested `ScopedNode`s.
34299     */
34300    this.childScopes = new Map();
34301    this.isDeferred = parentScope !== null && parentScope.isDeferred ? true : rootNode instanceof DeferredBlock;
34302  }
34303  static newRootScope() {
34304    return new Scope(null, null);
34305  }
34306  /**
34307   * Process a template (either as a `Template` sub-template with variables, or a plain array of
34308   * template `Node`s) and construct its `Scope`.
34309   */
34310  static apply(template) {
34311    const scope = Scope.newRootScope();
34312    scope.ingest(template);
34313    return scope;
34314  }
34315  /**
34316   * Internal method to process the scoped node and populate the `Scope`.
34317   */
34318  ingest(nodeOrNodes) {
34319    if (nodeOrNodes instanceof Template) {
34320      // Variables on an <ng-template> are defined in the inner scope.
34321      nodeOrNodes.variables.forEach(node => this.visitVariable(node));
34322      // Process the nodes of the template.
34323      nodeOrNodes.children.forEach(node => node.visit(this));
34324    } else if (nodeOrNodes instanceof IfBlockBranch) {
34325      if (nodeOrNodes.expressionAlias !== null) {
34326        this.visitVariable(nodeOrNodes.expressionAlias);
34327      }
34328      nodeOrNodes.children.forEach(node => node.visit(this));
34329    } else if (nodeOrNodes instanceof ForLoopBlock) {
34330      this.visitVariable(nodeOrNodes.item);
34331      Object.values(nodeOrNodes.contextVariables).forEach(v => this.visitVariable(v));
34332      nodeOrNodes.children.forEach(node => node.visit(this));
34333    } else if (nodeOrNodes instanceof SwitchBlockCase || nodeOrNodes instanceof ForLoopBlockEmpty || nodeOrNodes instanceof DeferredBlock || nodeOrNodes instanceof DeferredBlockError || nodeOrNodes instanceof DeferredBlockPlaceholder || nodeOrNodes instanceof DeferredBlockLoading) {
34334      nodeOrNodes.children.forEach(node => node.visit(this));
34335    } else {
34336      // No overarching `Template` instance, so process the nodes directly.
34337      nodeOrNodes.forEach(node => node.visit(this));
34338    }
34339  }
34340  visitElement(element) {
34341    // `Element`s in the template may have `Reference`s which are captured in the scope.
34342    element.references.forEach(node => this.visitReference(node));
34343    // Recurse into the `Element`'s children.
34344    element.children.forEach(node => node.visit(this));
34345    this.elementsInScope.add(element);
34346  }
34347  visitTemplate(template) {
34348    // References on a <ng-template> are defined in the outer scope, so capture them before
34349    // processing the template's child scope.
34350    template.references.forEach(node => this.visitReference(node));
34351    // Next, create an inner scope and process the template within it.
34352    this.ingestScopedNode(template);
34353  }
34354  visitVariable(variable) {
34355    // Declare the variable if it's not already.
34356    this.maybeDeclare(variable);
34357  }
34358  visitReference(reference) {
34359    // Declare the variable if it's not already.
34360    this.maybeDeclare(reference);
34361  }
34362  visitDeferredBlock(deferred) {
34363    this.ingestScopedNode(deferred);
34364    deferred.placeholder?.visit(this);
34365    deferred.loading?.visit(this);
34366    deferred.error?.visit(this);
34367  }
34368  visitDeferredBlockPlaceholder(block) {
34369    this.ingestScopedNode(block);
34370  }
34371  visitDeferredBlockError(block) {
34372    this.ingestScopedNode(block);
34373  }
34374  visitDeferredBlockLoading(block) {
34375    this.ingestScopedNode(block);
34376  }
34377  visitSwitchBlock(block) {
34378    block.cases.forEach(node => node.visit(this));
34379  }
34380  visitSwitchBlockCase(block) {
34381    this.ingestScopedNode(block);
34382  }
34383  visitForLoopBlock(block) {
34384    this.ingestScopedNode(block);
34385    block.empty?.visit(this);
34386  }
34387  visitForLoopBlockEmpty(block) {
34388    this.ingestScopedNode(block);
34389  }
34390  visitIfBlock(block) {
34391    block.branches.forEach(node => node.visit(this));
34392  }
34393  visitIfBlockBranch(block) {
34394    this.ingestScopedNode(block);
34395  }
34396  // Unused visitors.
34397  visitContent(content) {}
34398  visitBoundAttribute(attr) {}
34399  visitBoundEvent(event) {}
34400  visitBoundText(text) {}
34401  visitText(text) {}
34402  visitTextAttribute(attr) {}
34403  visitIcu(icu) {}
34404  visitDeferredTrigger(trigger) {}
34405  visitUnknownBlock(block) {}
34406  maybeDeclare(thing) {
34407    // Declare something with a name, as long as that name isn't taken.
34408    if (!this.namedEntities.has(thing.name)) {
34409      this.namedEntities.set(thing.name, thing);
34410    }
34411  }
34412  /**
34413   * Look up a variable within this `Scope`.
34414   *
34415   * This can recurse into a parent `Scope` if it's available.
34416   */
34417  lookup(name) {
34418    if (this.namedEntities.has(name)) {
34419      // Found in the local scope.
34420      return this.namedEntities.get(name);
34421    } else if (this.parentScope !== null) {
34422      // Not in the local scope, but there's a parent scope so check there.
34423      return this.parentScope.lookup(name);
34424    } else {
34425      // At the top level and it wasn't found.
34426      return null;
34427    }
34428  }
34429  /**
34430   * Get the child scope for a `ScopedNode`.
34431   *
34432   * This should always be defined.
34433   */
34434  getChildScope(node) {
34435    const res = this.childScopes.get(node);
34436    if (res === undefined) {
34437      throw new Error(`Assertion error: child scope for ${node} not found`);
34438    }
34439    return res;
34440  }
34441  ingestScopedNode(node) {
34442    const scope = new Scope(this, node);
34443    scope.ingest(node);
34444    this.childScopes.set(node, scope);
34445  }
34446}
34447/**
34448 * Processes a template and matches directives on nodes (elements and templates).
34449 *
34450 * Usually used via the static `apply()` method.
34451 */
34452class DirectiveBinder {
34453  constructor(matcher, directives, eagerDirectives, bindings, references) {
34454    this.matcher = matcher;
34455    this.directives = directives;
34456    this.eagerDirectives = eagerDirectives;
34457    this.bindings = bindings;
34458    this.references = references;
34459    // Indicates whether we are visiting elements within a `defer` block
34460    this.isInDeferBlock = false;
34461  }
34462  /**
34463   * Process a template (list of `Node`s) and perform directive matching against each node.
34464   *
34465   * @param template the list of template `Node`s to match (recursively).
34466   * @param selectorMatcher a `SelectorMatcher` containing the directives that are in scope for
34467   * this template.
34468   * @returns three maps which contain information about directives in the template: the
34469   * `directives` map which lists directives matched on each node, the `bindings` map which
34470   * indicates which directives claimed which bindings (inputs, outputs, etc), and the `references`
34471   * map which resolves #references (`Reference`s) within the template to the named directive or
34472   * template node.
34473   */
34474  static apply(template, selectorMatcher) {
34475    const directives = new Map();
34476    const bindings = new Map();
34477    const references = new Map();
34478    const eagerDirectives = [];
34479    const matcher = new DirectiveBinder(selectorMatcher, directives, eagerDirectives, bindings, references);
34480    matcher.ingest(template);
34481    return {
34482      directives,
34483      eagerDirectives,
34484      bindings,
34485      references
34486    };
34487  }
34488  ingest(template) {
34489    template.forEach(node => node.visit(this));
34490  }
34491  visitElement(element) {
34492    this.visitElementOrTemplate(element);
34493  }
34494  visitTemplate(template) {
34495    this.visitElementOrTemplate(template);
34496  }
34497  visitElementOrTemplate(node) {
34498    // First, determine the HTML shape of the node for the purpose of directive matching.
34499    // Do this by building up a `CssSelector` for the node.
34500    const cssSelector = createCssSelectorFromNode(node);
34501    // Next, use the `SelectorMatcher` to get the list of directives on the node.
34502    const directives = [];
34503    this.matcher.match(cssSelector, (_selector, results) => directives.push(...results));
34504    if (directives.length > 0) {
34505      this.directives.set(node, directives);
34506      if (!this.isInDeferBlock) {
34507        this.eagerDirectives.push(...directives);
34508      }
34509    }
34510    // Resolve any references that are created on this node.
34511    node.references.forEach(ref => {
34512      let dirTarget = null;
34513      // If the reference expression is empty, then it matches the "primary" directive on the node
34514      // (if there is one). Otherwise it matches the host node itself (either an element or
34515      // <ng-template> node).
34516      if (ref.value.trim() === '') {
34517        // This could be a reference to a component if there is one.
34518        dirTarget = directives.find(dir => dir.isComponent) || null;
34519      } else {
34520        // This should be a reference to a directive exported via exportAs.
34521        dirTarget = directives.find(dir => dir.exportAs !== null && dir.exportAs.some(value => value === ref.value)) || null;
34522        // Check if a matching directive was found.
34523        if (dirTarget === null) {
34524          // No matching directive was found - this reference points to an unknown target. Leave it
34525          // unmapped.
34526          return;
34527        }
34528      }
34529      if (dirTarget !== null) {
34530        // This reference points to a directive.
34531        this.references.set(ref, {
34532          directive: dirTarget,
34533          node
34534        });
34535      } else {
34536        // This reference points to the node itself.
34537        this.references.set(ref, node);
34538      }
34539    });
34540    const setAttributeBinding = (attribute, ioType) => {
34541      const dir = directives.find(dir => dir[ioType].hasBindingPropertyName(attribute.name));
34542      const binding = dir !== undefined ? dir : node;
34543      this.bindings.set(attribute, binding);
34544    };
34545    // Node inputs (bound attributes) and text attributes can be bound to an
34546    // input on a directive.
34547    node.inputs.forEach(input => setAttributeBinding(input, 'inputs'));
34548    node.attributes.forEach(attr => setAttributeBinding(attr, 'inputs'));
34549    if (node instanceof Template) {
34550      node.templateAttrs.forEach(attr => setAttributeBinding(attr, 'inputs'));
34551    }
34552    // Node outputs (bound events) can be bound to an output on a directive.
34553    node.outputs.forEach(output => setAttributeBinding(output, 'outputs'));
34554    // Recurse into the node's children.
34555    node.children.forEach(child => child.visit(this));
34556  }
34557  visitDeferredBlock(deferred) {
34558    const wasInDeferBlock = this.isInDeferBlock;
34559    this.isInDeferBlock = true;
34560    deferred.children.forEach(child => child.visit(this));
34561    this.isInDeferBlock = wasInDeferBlock;
34562    deferred.placeholder?.visit(this);
34563    deferred.loading?.visit(this);
34564    deferred.error?.visit(this);
34565  }
34566  visitDeferredBlockPlaceholder(block) {
34567    block.children.forEach(child => child.visit(this));
34568  }
34569  visitDeferredBlockError(block) {
34570    block.children.forEach(child => child.visit(this));
34571  }
34572  visitDeferredBlockLoading(block) {
34573    block.children.forEach(child => child.visit(this));
34574  }
34575  visitSwitchBlock(block) {
34576    block.cases.forEach(node => node.visit(this));
34577  }
34578  visitSwitchBlockCase(block) {
34579    block.children.forEach(node => node.visit(this));
34580  }
34581  visitForLoopBlock(block) {
34582    block.item.visit(this);
34583    Object.values(block.contextVariables).forEach(v => v.visit(this));
34584    block.children.forEach(node => node.visit(this));
34585    block.empty?.visit(this);
34586  }
34587  visitForLoopBlockEmpty(block) {
34588    block.children.forEach(node => node.visit(this));
34589  }
34590  visitIfBlock(block) {
34591    block.branches.forEach(node => node.visit(this));
34592  }
34593  visitIfBlockBranch(block) {
34594    block.expressionAlias?.visit(this);
34595    block.children.forEach(node => node.visit(this));
34596  }
34597  // Unused visitors.
34598  visitContent(content) {}
34599  visitVariable(variable) {}
34600  visitReference(reference) {}
34601  visitTextAttribute(attribute) {}
34602  visitBoundAttribute(attribute) {}
34603  visitBoundEvent(attribute) {}
34604  visitBoundAttributeOrEvent(node) {}
34605  visitText(text) {}
34606  visitBoundText(text) {}
34607  visitIcu(icu) {}
34608  visitDeferredTrigger(trigger) {}
34609  visitUnknownBlock(block) {}
34610}
34611/**
34612 * Processes a template and extract metadata about expressions and symbols within.
34613 *
34614 * This is a companion to the `DirectiveBinder` that doesn't require knowledge of directives matched
34615 * within the template in order to operate.
34616 *
34617 * Expressions are visited by the superclass `RecursiveAstVisitor`, with custom logic provided
34618 * by overridden methods from that visitor.
34619 */
34620class TemplateBinder extends RecursiveAstVisitor {
34621  constructor(bindings, symbols, usedPipes, eagerPipes, deferBlocks, nestingLevel, scope, rootNode, level) {
34622    super();
34623    this.bindings = bindings;
34624    this.symbols = symbols;
34625    this.usedPipes = usedPipes;
34626    this.eagerPipes = eagerPipes;
34627    this.deferBlocks = deferBlocks;
34628    this.nestingLevel = nestingLevel;
34629    this.scope = scope;
34630    this.rootNode = rootNode;
34631    this.level = level;
34632    // Save a bit of processing time by constructing this closure in advance.
34633    this.visitNode = node => node.visit(this);
34634  }
34635  // This method is defined to reconcile the type of TemplateBinder since both
34636  // RecursiveAstVisitor and Visitor define the visit() method in their
34637  // interfaces.
34638  visit(node, context) {
34639    if (node instanceof AST) {
34640      node.visit(this, context);
34641    } else {
34642      node.visit(this);
34643    }
34644  }
34645  /**
34646   * Process a template and extract metadata about expressions and symbols within.
34647   *
34648   * @param nodes the nodes of the template to process
34649   * @param scope the `Scope` of the template being processed.
34650   * @returns three maps which contain metadata about the template: `expressions` which interprets
34651   * special `AST` nodes in expressions as pointing to references or variables declared within the
34652   * template, `symbols` which maps those variables and references to the nested `Template` which
34653   * declares them, if any, and `nestingLevel` which associates each `Template` with a integer
34654   * nesting level (how many levels deep within the template structure the `Template` is), starting
34655   * at 1.
34656   */
34657  static applyWithScope(nodes, scope) {
34658    const expressions = new Map();
34659    const symbols = new Map();
34660    const nestingLevel = new Map();
34661    const usedPipes = new Set();
34662    const eagerPipes = new Set();
34663    const template = nodes instanceof Template ? nodes : null;
34664    const deferBlocks = new Map();
34665    // The top-level template has nesting level 0.
34666    const binder = new TemplateBinder(expressions, symbols, usedPipes, eagerPipes, deferBlocks, nestingLevel, scope, template, 0);
34667    binder.ingest(nodes);
34668    return {
34669      expressions,
34670      symbols,
34671      nestingLevel,
34672      usedPipes,
34673      eagerPipes,
34674      deferBlocks
34675    };
34676  }
34677  ingest(nodeOrNodes) {
34678    if (nodeOrNodes instanceof Template) {
34679      // For <ng-template>s, process only variables and child nodes. Inputs, outputs, templateAttrs,
34680      // and references were all processed in the scope of the containing template.
34681      nodeOrNodes.variables.forEach(this.visitNode);
34682      nodeOrNodes.children.forEach(this.visitNode);
34683      // Set the nesting level.
34684      this.nestingLevel.set(nodeOrNodes, this.level);
34685    } else if (nodeOrNodes instanceof IfBlockBranch) {
34686      if (nodeOrNodes.expressionAlias !== null) {
34687        this.visitNode(nodeOrNodes.expressionAlias);
34688      }
34689      nodeOrNodes.children.forEach(this.visitNode);
34690      this.nestingLevel.set(nodeOrNodes, this.level);
34691    } else if (nodeOrNodes instanceof ForLoopBlock) {
34692      this.visitNode(nodeOrNodes.item);
34693      Object.values(nodeOrNodes.contextVariables).forEach(v => this.visitNode(v));
34694      nodeOrNodes.trackBy.visit(this);
34695      nodeOrNodes.children.forEach(this.visitNode);
34696      this.nestingLevel.set(nodeOrNodes, this.level);
34697    } else if (nodeOrNodes instanceof DeferredBlock) {
34698      if (this.scope.rootNode !== nodeOrNodes) {
34699        throw new Error(`Assertion error: resolved incorrect scope for deferred block ${nodeOrNodes}`);
34700      }
34701      this.deferBlocks.set(nodeOrNodes, this.scope);
34702      nodeOrNodes.children.forEach(node => node.visit(this));
34703      this.nestingLevel.set(nodeOrNodes, this.level);
34704    } else if (nodeOrNodes instanceof SwitchBlockCase || nodeOrNodes instanceof ForLoopBlockEmpty || nodeOrNodes instanceof DeferredBlockError || nodeOrNodes instanceof DeferredBlockPlaceholder || nodeOrNodes instanceof DeferredBlockLoading) {
34705      nodeOrNodes.children.forEach(node => node.visit(this));
34706      this.nestingLevel.set(nodeOrNodes, this.level);
34707    } else {
34708      // Visit each node from the top-level template.
34709      nodeOrNodes.forEach(this.visitNode);
34710    }
34711  }
34712  visitElement(element) {
34713    // Visit the inputs, outputs, and children of the element.
34714    element.inputs.forEach(this.visitNode);
34715    element.outputs.forEach(this.visitNode);
34716    element.children.forEach(this.visitNode);
34717    element.references.forEach(this.visitNode);
34718  }
34719  visitTemplate(template) {
34720    // First, visit inputs, outputs and template attributes of the template node.
34721    template.inputs.forEach(this.visitNode);
34722    template.outputs.forEach(this.visitNode);
34723    template.templateAttrs.forEach(this.visitNode);
34724    template.references.forEach(this.visitNode);
34725    // Next, recurse into the template.
34726    this.ingestScopedNode(template);
34727  }
34728  visitVariable(variable) {
34729    // Register the `Variable` as a symbol in the current `Template`.
34730    if (this.rootNode !== null) {
34731      this.symbols.set(variable, this.rootNode);
34732    }
34733  }
34734  visitReference(reference) {
34735    // Register the `Reference` as a symbol in the current `Template`.
34736    if (this.rootNode !== null) {
34737      this.symbols.set(reference, this.rootNode);
34738    }
34739  }
34740  // Unused template visitors
34741  visitText(text) {}
34742  visitContent(content) {}
34743  visitTextAttribute(attribute) {}
34744  visitUnknownBlock(block) {}
34745  visitDeferredTrigger() {}
34746  visitIcu(icu) {
34747    Object.keys(icu.vars).forEach(key => icu.vars[key].visit(this));
34748    Object.keys(icu.placeholders).forEach(key => icu.placeholders[key].visit(this));
34749  }
34750  // The remaining visitors are concerned with processing AST expressions within template bindings
34751  visitBoundAttribute(attribute) {
34752    attribute.value.visit(this);
34753  }
34754  visitBoundEvent(event) {
34755    event.handler.visit(this);
34756  }
34757  visitDeferredBlock(deferred) {
34758    this.ingestScopedNode(deferred);
34759    deferred.triggers.when?.value.visit(this);
34760    deferred.prefetchTriggers.when?.value.visit(this);
34761    deferred.placeholder && this.visitNode(deferred.placeholder);
34762    deferred.loading && this.visitNode(deferred.loading);
34763    deferred.error && this.visitNode(deferred.error);
34764  }
34765  visitDeferredBlockPlaceholder(block) {
34766    this.ingestScopedNode(block);
34767  }
34768  visitDeferredBlockError(block) {
34769    this.ingestScopedNode(block);
34770  }
34771  visitDeferredBlockLoading(block) {
34772    this.ingestScopedNode(block);
34773  }
34774  visitSwitchBlock(block) {
34775    block.expression.visit(this);
34776    block.cases.forEach(this.visitNode);
34777  }
34778  visitSwitchBlockCase(block) {
34779    block.expression?.visit(this);
34780    this.ingestScopedNode(block);
34781  }
34782  visitForLoopBlock(block) {
34783    block.expression.visit(this);
34784    this.ingestScopedNode(block);
34785    block.empty?.visit(this);
34786  }
34787  visitForLoopBlockEmpty(block) {
34788    this.ingestScopedNode(block);
34789  }
34790  visitIfBlock(block) {
34791    block.branches.forEach(node => node.visit(this));
34792  }
34793  visitIfBlockBranch(block) {
34794    block.expression?.visit(this);
34795    this.ingestScopedNode(block);
34796  }
34797  visitBoundText(text) {
34798    text.value.visit(this);
34799  }
34800  visitPipe(ast, context) {
34801    this.usedPipes.add(ast.name);
34802    if (!this.scope.isDeferred) {
34803      this.eagerPipes.add(ast.name);
34804    }
34805    return super.visitPipe(ast, context);
34806  }
34807  // These five types of AST expressions can refer to expression roots, which could be variables
34808  // or references in the current scope.
34809  visitPropertyRead(ast, context) {
34810    this.maybeMap(ast, ast.name);
34811    return super.visitPropertyRead(ast, context);
34812  }
34813  visitSafePropertyRead(ast, context) {
34814    this.maybeMap(ast, ast.name);
34815    return super.visitSafePropertyRead(ast, context);
34816  }
34817  visitPropertyWrite(ast, context) {
34818    this.maybeMap(ast, ast.name);
34819    return super.visitPropertyWrite(ast, context);
34820  }
34821  ingestScopedNode(node) {
34822    const childScope = this.scope.getChildScope(node);
34823    const binder = new TemplateBinder(this.bindings, this.symbols, this.usedPipes, this.eagerPipes, this.deferBlocks, this.nestingLevel, childScope, node, this.level + 1);
34824    binder.ingest(node);
34825  }
34826  maybeMap(ast, name) {
34827    // If the receiver of the expression isn't the `ImplicitReceiver`, this isn't the root of an
34828    // `AST` expression that maps to a `Variable` or `Reference`.
34829    if (!(ast.receiver instanceof ImplicitReceiver)) {
34830      return;
34831    }
34832    // Check whether the name exists in the current scope. If so, map it. Otherwise, the name is
34833    // probably a property on the top-level component context.
34834    let target = this.scope.lookup(name);
34835    if (target !== null) {
34836      this.bindings.set(ast, target);
34837    }
34838  }
34839}
34840/**
34841 * Metadata container for a `Target` that allows queries for specific bits of metadata.
34842 *
34843 * See `BoundTarget` for documentation on the individual methods.
34844 */
34845class R3BoundTarget {
34846  constructor(target, directives, eagerDirectives, bindings, references, exprTargets, symbols, nestingLevel, scopedNodeEntities, usedPipes, eagerPipes, deferBlocks) {
34847    this.target = target;
34848    this.directives = directives;
34849    this.eagerDirectives = eagerDirectives;
34850    this.bindings = bindings;
34851    this.references = references;
34852    this.exprTargets = exprTargets;
34853    this.symbols = symbols;
34854    this.nestingLevel = nestingLevel;
34855    this.scopedNodeEntities = scopedNodeEntities;
34856    this.usedPipes = usedPipes;
34857    this.eagerPipes = eagerPipes;
34858    this.deferBlocks = deferBlocks;
34859  }
34860  getEntitiesInScope(node) {
34861    return this.scopedNodeEntities.get(node) ?? new Set();
34862  }
34863  getDirectivesOfNode(node) {
34864    return this.directives.get(node) || null;
34865  }
34866  getReferenceTarget(ref) {
34867    return this.references.get(ref) || null;
34868  }
34869  getConsumerOfBinding(binding) {
34870    return this.bindings.get(binding) || null;
34871  }
34872  getExpressionTarget(expr) {
34873    return this.exprTargets.get(expr) || null;
34874  }
34875  getDefinitionNodeOfSymbol(symbol) {
34876    return this.symbols.get(symbol) || null;
34877  }
34878  getNestingLevel(node) {
34879    return this.nestingLevel.get(node) || 0;
34880  }
34881  getUsedDirectives() {
34882    const set = new Set();
34883    this.directives.forEach(dirs => dirs.forEach(dir => set.add(dir)));
34884    return Array.from(set.values());
34885  }
34886  getEagerlyUsedDirectives() {
34887    const set = new Set(this.eagerDirectives);
34888    return Array.from(set.values());
34889  }
34890  getUsedPipes() {
34891    return Array.from(this.usedPipes);
34892  }
34893  getEagerlyUsedPipes() {
34894    return Array.from(this.eagerPipes);
34895  }
34896  getDeferBlocks() {
34897    return Array.from(this.deferBlocks.keys());
34898  }
34899  getDeferredTriggerTarget(block, trigger) {
34900    // Only triggers that refer to DOM nodes can be resolved.
34901    if (!(trigger instanceof InteractionDeferredTrigger) && !(trigger instanceof ViewportDeferredTrigger) && !(trigger instanceof HoverDeferredTrigger)) {
34902      return null;
34903    }
34904    const name = trigger.reference;
34905    if (name === null) {
34906      let trigger = null;
34907      if (block.placeholder !== null) {
34908        for (const child of block.placeholder.children) {
34909          // Skip over comment nodes. Currently by default the template parser doesn't capture
34910          // comments, but we have a safeguard here just in case since it can be enabled.
34911          if (child instanceof Comment$1) {
34912            continue;
34913          }
34914          // We can only infer the trigger if there's one root element node. Any other
34915          // nodes at the root make it so that we can't infer the trigger anymore.
34916          if (trigger !== null) {
34917            return null;
34918          }
34919          if (child instanceof Element$1) {
34920            trigger = child;
34921          }
34922        }
34923      }
34924      return trigger;
34925    }
34926    const outsideRef = this.findEntityInScope(block, name);
34927    // First try to resolve the target in the scope of the main deferred block. Note that we
34928    // skip triggers defined inside the main block itself, because they might not exist yet.
34929    if (outsideRef instanceof Reference && this.getDefinitionNodeOfSymbol(outsideRef) !== block) {
34930      const target = this.getReferenceTarget(outsideRef);
34931      if (target !== null) {
34932        return this.referenceTargetToElement(target);
34933      }
34934    }
34935    // If the trigger couldn't be found in the main block, check the
34936    // placeholder block which is shown before the main block has loaded.
34937    if (block.placeholder !== null) {
34938      const refInPlaceholder = this.findEntityInScope(block.placeholder, name);
34939      const targetInPlaceholder = refInPlaceholder instanceof Reference ? this.getReferenceTarget(refInPlaceholder) : null;
34940      if (targetInPlaceholder !== null) {
34941        return this.referenceTargetToElement(targetInPlaceholder);
34942      }
34943    }
34944    return null;
34945  }
34946  isDeferred(element) {
34947    for (const deferredScope of this.deferBlocks.values()) {
34948      const stack = [deferredScope];
34949      while (stack.length > 0) {
34950        const current = stack.pop();
34951        if (current.elementsInScope.has(element)) {
34952          return true;
34953        }
34954        stack.push(...current.childScopes.values());
34955      }
34956    }
34957    return false;
34958  }
34959  /**
34960   * Finds an entity with a specific name in a scope.
34961   * @param rootNode Root node of the scope.
34962   * @param name Name of the entity.
34963   */
34964  findEntityInScope(rootNode, name) {
34965    const entities = this.getEntitiesInScope(rootNode);
34966    for (const entitity of entities) {
34967      if (entitity.name === name) {
34968        return entitity;
34969      }
34970    }
34971    return null;
34972  }
34973  /** Coerces a `ReferenceTarget` to an `Element`, if possible. */
34974  referenceTargetToElement(target) {
34975    if (target instanceof Element$1) {
34976      return target;
34977    }
34978    if (target instanceof Template) {
34979      return null;
34980    }
34981    return this.referenceTargetToElement(target.node);
34982  }
34983}
34984function extractScopedNodeEntities(rootScope) {
34985  const entityMap = new Map();
34986  function extractScopeEntities(scope) {
34987    if (entityMap.has(scope.rootNode)) {
34988      return entityMap.get(scope.rootNode);
34989    }
34990    const currentEntities = scope.namedEntities;
34991    let entities;
34992    if (scope.parentScope !== null) {
34993      entities = new Map([...extractScopeEntities(scope.parentScope), ...currentEntities]);
34994    } else {
34995      entities = new Map(currentEntities);
34996    }
34997    entityMap.set(scope.rootNode, entities);
34998    return entities;
34999  }
35000  const scopesToProcess = [rootScope];
35001  while (scopesToProcess.length > 0) {
35002    const scope = scopesToProcess.pop();
35003    for (const childScope of scope.childScopes.values()) {
35004      scopesToProcess.push(childScope);
35005    }
35006    extractScopeEntities(scope);
35007  }
35008  const templateEntities = new Map();
35009  for (const [template, entities] of entityMap) {
35010    templateEntities.set(template, new Set(entities.values()));
35011  }
35012  return templateEntities;
35013}
35014
35015/**
35016 * An interface for retrieving documents by URL that the compiler uses to
35017 * load templates.
35018 *
35019 * This is an abstract class, rather than an interface, so that it can be used
35020 * as injection token.
35021 */
35022class ResourceLoader {}
35023const SHOULD_USE_TEMPLATE_PIPELINE_FOR_JIT = true;
35024class CompilerFacadeImpl {
35025  constructor(jitEvaluator = new JitEvaluator()) {
35026    this.jitEvaluator = jitEvaluator;
35027    this.FactoryTarget = FactoryTarget$1;
35028    this.ResourceLoader = ResourceLoader;
35029    this.elementSchemaRegistry = new DomElementSchemaRegistry();
35030  }
35031  compilePipe(angularCoreEnv, sourceMapUrl, facade) {
35032    const metadata = {
35033      name: facade.name,
35034      type: wrapReference(facade.type),
35035      typeArgumentCount: 0,
35036      deps: null,
35037      pipeName: facade.pipeName,
35038      pure: facade.pure,
35039      isStandalone: facade.isStandalone
35040    };
35041    const res = compilePipeFromMetadata(metadata);
35042    return this.jitExpression(res.expression, angularCoreEnv, sourceMapUrl, []);
35043  }
35044  compilePipeDeclaration(angularCoreEnv, sourceMapUrl, declaration) {
35045    const meta = convertDeclarePipeFacadeToMetadata(declaration);
35046    const res = compilePipeFromMetadata(meta);
35047    return this.jitExpression(res.expression, angularCoreEnv, sourceMapUrl, []);
35048  }
35049  compileInjectable(angularCoreEnv, sourceMapUrl, facade) {
35050    const {
35051      expression,
35052      statements
35053    } = compileInjectable({
35054      name: facade.name,
35055      type: wrapReference(facade.type),
35056      typeArgumentCount: facade.typeArgumentCount,
35057      providedIn: computeProvidedIn(facade.providedIn),
35058      useClass: convertToProviderExpression(facade, 'useClass'),
35059      useFactory: wrapExpression(facade, 'useFactory'),
35060      useValue: convertToProviderExpression(facade, 'useValue'),
35061      useExisting: convertToProviderExpression(facade, 'useExisting'),
35062      deps: facade.deps?.map(convertR3DependencyMetadata)
35063    }, /* resolveForwardRefs */true);
35064    return this.jitExpression(expression, angularCoreEnv, sourceMapUrl, statements);
35065  }
35066  compileInjectableDeclaration(angularCoreEnv, sourceMapUrl, facade) {
35067    const {
35068      expression,
35069      statements
35070    } = compileInjectable({
35071      name: facade.type.name,
35072      type: wrapReference(facade.type),
35073      typeArgumentCount: 0,
35074      providedIn: computeProvidedIn(facade.providedIn),
35075      useClass: convertToProviderExpression(facade, 'useClass'),
35076      useFactory: wrapExpression(facade, 'useFactory'),
35077      useValue: convertToProviderExpression(facade, 'useValue'),
35078      useExisting: convertToProviderExpression(facade, 'useExisting'),
35079      deps: facade.deps?.map(convertR3DeclareDependencyMetadata)
35080    }, /* resolveForwardRefs */true);
35081    return this.jitExpression(expression, angularCoreEnv, sourceMapUrl, statements);
35082  }
35083  compileInjector(angularCoreEnv, sourceMapUrl, facade) {
35084    const meta = {
35085      name: facade.name,
35086      type: wrapReference(facade.type),
35087      providers: facade.providers && facade.providers.length > 0 ? new WrappedNodeExpr(facade.providers) : null,
35088      imports: facade.imports.map(i => new WrappedNodeExpr(i))
35089    };
35090    const res = compileInjector(meta);
35091    return this.jitExpression(res.expression, angularCoreEnv, sourceMapUrl, []);
35092  }
35093  compileInjectorDeclaration(angularCoreEnv, sourceMapUrl, declaration) {
35094    const meta = convertDeclareInjectorFacadeToMetadata(declaration);
35095    const res = compileInjector(meta);
35096    return this.jitExpression(res.expression, angularCoreEnv, sourceMapUrl, []);
35097  }
35098  compileNgModule(angularCoreEnv, sourceMapUrl, facade) {
35099    const meta = {
35100      kind: R3NgModuleMetadataKind.Global,
35101      type: wrapReference(facade.type),
35102      bootstrap: facade.bootstrap.map(wrapReference),
35103      declarations: facade.declarations.map(wrapReference),
35104      publicDeclarationTypes: null,
35105      // only needed for types in AOT
35106      imports: facade.imports.map(wrapReference),
35107      includeImportTypes: true,
35108      exports: facade.exports.map(wrapReference),
35109      selectorScopeMode: R3SelectorScopeMode.Inline,
35110      containsForwardDecls: false,
35111      schemas: facade.schemas ? facade.schemas.map(wrapReference) : null,
35112      id: facade.id ? new WrappedNodeExpr(facade.id) : null
35113    };
35114    const res = compileNgModule(meta);
35115    return this.jitExpression(res.expression, angularCoreEnv, sourceMapUrl, []);
35116  }
35117  compileNgModuleDeclaration(angularCoreEnv, sourceMapUrl, declaration) {
35118    const expression = compileNgModuleDeclarationExpression(declaration);
35119    return this.jitExpression(expression, angularCoreEnv, sourceMapUrl, []);
35120  }
35121  compileDirective(angularCoreEnv, sourceMapUrl, facade) {
35122    const meta = convertDirectiveFacadeToMetadata(facade);
35123    return this.compileDirectiveFromMeta(angularCoreEnv, sourceMapUrl, meta);
35124  }
35125  compileDirectiveDeclaration(angularCoreEnv, sourceMapUrl, declaration) {
35126    const typeSourceSpan = this.createParseSourceSpan('Directive', declaration.type.name, sourceMapUrl);
35127    const meta = convertDeclareDirectiveFacadeToMetadata(declaration, typeSourceSpan);
35128    return this.compileDirectiveFromMeta(angularCoreEnv, sourceMapUrl, meta);
35129  }
35130  compileDirectiveFromMeta(angularCoreEnv, sourceMapUrl, meta) {
35131    const constantPool = new ConstantPool();
35132    const bindingParser = makeBindingParser();
35133    const res = compileDirectiveFromMetadata(meta, constantPool, bindingParser);
35134    return this.jitExpression(res.expression, angularCoreEnv, sourceMapUrl, constantPool.statements);
35135  }
35136  compileComponent(angularCoreEnv, sourceMapUrl, facade) {
35137    // Parse the template and check for errors.
35138    const {
35139      template,
35140      interpolation,
35141      deferBlocks
35142    } = parseJitTemplate(facade.template, facade.name, sourceMapUrl, facade.preserveWhitespace
35142s, facade.interpolation);
35143    // Compile the component metadata, including template, into an expression.
35144    const meta = {
35145      ...facade,
35146      ...convertDirectiveFacadeToMetadata(facade),
35147      selector: facade.selector || this.elementSchemaRegistry.getDefaultComponentElementName(),
35148      template,
35149      declarations: facade.declarations.map(convertDeclarationFacadeToMetadata),
35150      declarationListEmitMode: 0 /* DeclarationListEmitMode.Direct */,
35151      deferBlocks,
35152      deferrableTypes: new Map(),
35153      deferrableDeclToImportDecl: new Map(),
35154      deferBlockDepsEmitMode: 0 /* DeferBlockDepsEmitMode.PerBlock */,
35155      styles: [...facade.styles, ...template.styles],
35156      encapsulation: facade.encapsulation,
35157      interpolation,
35158      changeDetection: facade.changeDetection ?? null,
35159      animations: facade.animations != null ? new WrappedNodeExpr(facade.animations) : null,
35160      viewProviders: facade.viewProviders != null ? new WrappedNodeExpr(facade.viewProviders) : null,
35161      relativeContextFilePath: '',
35162      i18nUseExternalIds: true,
35163      useTemplatePipeline: SHOULD_USE_TEMPLATE_PIPELINE_FOR_JIT
35164    };
35165    const jitExpressionSourceMap = `ng:///${facade.name}.js`;
35166    return this.compileComponentFromMeta(angularCoreEnv, jitExpressionSourceMap, meta);
35167  }
35168  compileComponentDeclaration(angularCoreEnv, sourceMapUrl, declaration) {
35169    const typeSourceSpan = this.createParseSourceSpan('Component', declaration.type.name, sourceMapUrl);
35170    const meta = convertDeclareComponentFacadeToMetadata(declaration, typeSourceSpan, sourceMapUrl);
35171    return this.compileComponentFromMeta(angularCoreEnv, sourceMapUrl, meta);
35172  }
35173  compileComponentFromMeta(angularCoreEnv, sourceMapUrl, meta) {
35174    const constantPool = new ConstantPool();
35175    const bindingParser = makeBindingParser(meta.interpolation);
35176    const res = compileComponentFromMetadata(meta, constantPool, bindingParser);
35177    return this.jitExpression(res.expression, angularCoreEnv, sourceMapUrl, constantPool.statements);
35178  }
35179  compileFactory(angularCoreEnv, sourceMapUrl, meta) {
35180    const factoryRes = compileFactoryFunction({
35181      name: meta.name,
35182      type: wrapReference(meta.type),
35183      typeArgumentCount: meta.typeArgumentCount,
35184      deps: convertR3DependencyMetadataArray(meta.deps),
35185      target: meta.target
35186    });
35187    return this.jitExpression(factoryRes.expression, angularCoreEnv, sourceMapUrl, factoryRes.statements);
35188  }
35189  compileFactoryDeclaration(angularCoreEnv, sourceMapUrl, meta) {
35190    const factoryRes = compileFactoryFunction({
35191      name: meta.type.name,
35192      type: wrapReference(meta.type),
35193      typeArgumentCount: 0,
35194      deps: Array.isArray(meta.deps) ? meta.deps.map(convertR3DeclareDependencyMetadata) : meta.deps,
35195      target: meta.target
35196    });
35197    return this.jitExpression(factoryRes.expression, angularCoreEnv, sourceMapUrl, factoryRes.statements);
35198  }
35199  createParseSourceSpan(kind, typeName, sourceUrl) {
35200    return r3JitTypeSourceSpan(kind, typeName, sourceUrl);
35201  }
35202  /**
35203   * JIT compiles an expression and returns the result of executing that expression.
35204   *
35205   * @param def the definition which will be compiled and executed to get the value to patch
35206   * @param context an object map of @angular/core symbol names to symbols which will be available
35207   * in the context of the compiled expression
35208   * @param sourceUrl a URL to use for the source map of the compiled expression
35209   * @param preStatements a collection of statements that should be evaluated before the expression.
35210   */
35211  jitExpression(def, context, sourceUrl, preStatements) {
35212    // The ConstantPool may contain Statements which declare variables used in the final expression.
35213    // Therefore, its statements need to precede the actual JIT operation. The final statement is a
35214    // declaration of $def which is set to the expression being compiled.
35215    const statements = [...preStatements, new DeclareVarStmt('$def', def, undefined, StmtModifier.Exported)];
35216    const res = this.jitEvaluator.evaluateStatements(sourceUrl, statements, new R3JitReflector(context), /* enableSourceMaps */true);
35217    return res['$def'];
35218  }
35219}
35220function convertToR3QueryMetadata(facade) {
35221  return {
35222    ...facade,
35223    isSignal: facade.isSignal,
35224    predicate: convertQueryPredicate(facade.predicate),
35225    read: facade.read ? new WrappedNodeExpr(facade.read) : null,
35226    static: facade.static,
35227    emitDistinctChangesOnly: facade.emitDistinctChangesOnly
35228  };
35229}
35230function convertQueryDeclarationToMetadata(declaration) {
35231  return {
35232    propertyName: declaration.propertyName,
35233    first: declaration.first ?? false,
35234    predicate: convertQueryPredicate(declaration.predicate),
35235    descendants: declaration.descendants ?? false,
35236    read: declaration.read ? new WrappedNodeExpr(declaration.read) : null,
35237    static: declaration.static ?? false,
35238    emitDistinctChangesOnly: declaration.emitDistinctChangesOnly ?? true,
35239    isSignal: !!declaration.isSignal
35240  };
35241}
35242function convertQueryPredicate(predicate) {
35243  return Array.isArray(predicate) ?
35244  // The predicate is an array of strings so pass it through.
35245  predicate :
35246  // The predicate is a type - assume that we will need to unwrap any `forwardRef()` calls.
35247  createMayBeForwardRefExpression(new WrappedNodeExpr(predicate), 1 /* ForwardRefHandling.Wrapped */);
35248}
35249function convertDirectiveFacadeToMetadata(facade) {
35250  const inputsFromMetadata = parseInputsArray(facade.inputs || []);
35251  const outputsFromMetadata = parseMappingStringArray(facade.outputs || []);
35252  const propMetadata = facade.propMetadata;
35253  const inputsFromType = {};
35254  const outputsFromType = {};
35255  for (const field in propMetadata) {
35256    if (propMetadata.hasOwnProperty(field)) {
35257      propMetadata[field].forEach(ann => {
35258        if (isInput(ann)) {
35259          inputsFromType[field] = {
35260            bindingPropertyName: ann.alias || field,
35261            classPropertyName: field,
35262            required: ann.required || false,
35263            // For JIT, decorators are used to declare signal inputs. That is because of
35264            // a technical limitation where it's not possible to statically reflect class
35265            // members of a directive/component at runtime before instantiating the class.
35266            isSignal: !!ann.isSignal,
35267            transformFunction: ann.transform != null ? new WrappedNodeExpr(ann.transform) : null
35268          };
35269        } else if (isOutput(ann)) {
35270          outputsFromType[field] = ann.alias || field;
35271        }
35272      });
35273    }
35274  }
35275  return {
35276    ...facade,
35277    typeArgumentCount: 0,
35278    typeSourceSpan: facade.typeSourceSpan,
35279    type: wrapReference(facade.type),
35280    deps: null,
35281    host: {
35282      ...extractHostBindings(facade.propMetadata, facade.typeSourceSpan, facade.host),
35283      useTemplatePipeline: SHOULD_USE_TEMPLATE_PIPELINE_FOR_JIT
35284    },
35285    inputs: {
35286      ...inputsFromMetadata,
35287      ...inputsFromType
35288    },
35289    outputs: {
35290      ...outputsFromMetadata,
35291      ...outputsFromType
35292    },
35293    queries: facade.queries.map(convertToR3QueryMetadata),
35294    providers: facade.providers != null ? new WrappedNodeExpr(facade.providers) : null,
35295    viewQueries: facade.viewQueries.map(convertToR3QueryMetadata),
35296    fullInheritance: false,
35297    hostDirectives: convertHostDirectivesToMetadata(facade)
35298  };
35299}
35300function convertDeclareDirectiveFacadeToMetadata(declaration, typeSourceSpan) {
35301  return {
35302    name: declaration.type.name,
35303    type: wrapReference(declaration.type),
35304    typeSourceSpan,
35305    selector: declaration.selector ?? null,
35306    inputs: declaration.inputs ? inputsPartialMetadataToInputMetadata(declaration.inputs) : {},
35307    outputs: declaration.outputs ?? {},
35308    host: convertHostDeclarationToMetadata(declaration.host),
35309    queries: (declaration.queries ?? []).map(convertQueryDeclarationToMetadata),
35310    viewQueries: (declaration.viewQueries ?? []).map(convertQueryDeclarationToMetadata),
35311    providers: declaration.providers !== undefined ? new WrappedNodeExpr(declaration.providers) : null,
35312    exportAs: declaration.exportAs ?? null,
35313    usesInheritance: declaration.usesInheritance ?? false,
35314    lifecycle: {
35315      usesOnChanges: declaration.usesOnChanges ?? false
35316    },
35317    deps: null,
35318    typeArgumentCount: 0,
35319    fullInheritance: false,
35320    isStandalone: declaration.isStandalone ?? false,
35321    isSignal: declaration.isSignal ?? false,
35322    hostDirectives: convertHostDirectivesToMetadata(declaration)
35323  };
35324}
35325function convertHostDeclarationToMetadata(host = {}) {
35326  return {
35327    attributes: convertOpaqueValuesToExpressions(host.attributes ?? {}),
35328    listeners: host.listeners ?? {},
35329    properties: host.properties ?? {},
35330    specialAttributes: {
35331      classAttr: host.classAttribute,
35332      styleAttr: host.styleAttribute
35333    },
35334    useTemplatePipeline: SHOULD_USE_TEMPLATE_PIPELINE_FOR_JIT
35335  };
35336}
35337function convertHostDirectivesToMetadata(metadata) {
35338  if (metadata.hostDirectives?.length) {
35339    return metadata.hostDirectives.map(hostDirective => {
35340      return typeof hostDirective === 'function' ? {
35341        directive: wrapReference(hostDirective),
35342        inputs: null,
35343        outputs: null,
35344        isForwardReference: false
35345      } : {
35346        directive: wrapReference(hostDirective.directive),
35347        isForwardReference: false,
35348        inputs: hostDirective.inputs ? parseMappingStringArray(hostDirective.inputs) : null,
35349        outputs: hostDirective.outputs ? parseMappingStringArray(hostDirective.outputs) : null
35350      };
35351    });
35352  }
35353  return null;
35354}
35355function convertOpaqueValuesToExpressions(obj) {
35356  const result = {};
35357  for (const key of Object.keys(obj)) {
35358    result[key] = new WrappedNodeExpr(obj[key]);
35359  }
35360  return result;
35361}
35362function convertDeclareComponentFacadeToMetadata(decl, typeSourceSpan, sourceMapUrl) {
35363  const {
35364    template,
35365    interpolation,
35366    deferBlocks
35367  }
35367 = parseJitTemplate(decl.template, decl.type.name, sourceMapUrl, decl.preserveWhitespaces ?? false, decl.interpolation);
35368  const declarations = [];
35369  if (decl.dependencies) {
35370    for (const innerDep of decl.dependencies) {
35371      switch (innerDep.kind) {
35372        case 'directive':
35373        case 'component':
35374          declarations.push(convertDirectiveDeclarationToMetadata(innerDep));
35375          break;
35376        case 'pipe':
35377          declarations.push(convertPipeDeclarationToMetadata(innerDep));
35378          break;
35379      }
35380    }
35381  } else if (decl.components || decl.directives || decl.pipes) {
35382    // Existing declarations on NPM may not be using the new `dependencies` merged field, and may
35383    // have separate fields for dependencies instead. Unify them for JIT compilation.
35384    decl.components && declarations.push(...decl.components.map(dir => convertDirectiveDeclarationToMetadata(dir, /* isComponent */true)));
35385    decl.directives && declarations.push(...decl.directives.map(dir => convertDirectiveDeclarationToMetadata(dir)));
35386    decl.pipes && declarations.push(...convertPipeMapToMetadata(decl.pipes));
35387  }
35388  return {
35389    ...convertDeclareDirectiveFacadeToMetadata(decl, typeSourceSpan),
35390    template,
35391    styles: decl.styles ?? [],
35392    declarations,
35393    viewProviders: decl.viewProviders !== undefined ? new WrappedNodeExpr(decl.viewProviders) : null,
35394    animations: decl.animations !== undefined ? new WrappedNodeExpr(decl.animations) : null,
35395    deferBlocks,
35396    deferrableTypes: new Map(),
35397    deferrableDeclToImportDecl: new Map(),
35398    deferBlockDepsEmitMode: 0 /* DeferBlockDepsEmitMode.PerBlock */,
35399    changeDetection: decl.changeDetection ?? ChangeDetectionStrategy.Default,
35400    encapsulation: decl.encapsulation ?? ViewEncapsulation.Emulated,
35401    interpolation,
35402    declarationListEmitMode: 2 /* DeclarationListEmitMode.ClosureResolved */,
35403    relativeContextFilePath: '',
35404    i18nUseExternalIds: true,
35405    useTemplatePipeline: SHOULD_USE_TEMPLATE_PIPELINE_FOR_JIT
35406  };
35407}
35408function convertDeclarationFacadeToMetadata(declaration) {
35409  return {
35410    ...declaration,
35411    type: new WrappedNodeExpr(declaration.type)
35412  };
35413}
35414function convertDirectiveDeclarationToMetadata(declaration, isComponent = null) {
35415  return {
35416    kind: R3TemplateDependencyKind.Directive,
35417    isComponent: isComponent || declaration.kind === 'component',
35418    selector: declaration.selector,
35419    type: new WrappedNodeExpr(declaration.type),
35420    inputs: declaration.inputs ?? [],
35421    outputs: declaration.outputs ?? [],
35422    exportAs: declaration.exportAs ?? null
35423  };
35424}
35425function convertPipeMapToMetadata(pipes) {
35426  if (!pipes) {
35427    return [];
35428  }
35429  return Object.keys(pipes).map(name => {
35430    return {
35431      kind: R3TemplateDependencyKind.Pipe,
35432      name,
35433      type: new WrappedNodeExpr(pipes[name])
35434    };
35435  });
35436}
35437function convertPipeDeclarationToMetadata(pipe) {
35438  return {
35439    kind: R3TemplateDependencyKind.Pipe,
35440    name: pipe.name,
35441    type: new WrappedNodeExpr(pipe.type)
35442  };
35443}
35444function parseJitTemplate(template, typeName, sourceMapUrl, preserveWhitespaces, interpolation) {
35445  const interpolationConfig = interpolation ? InterpolationConfig.fromArray(interpolation) : DEFAULT_INTERPOLATION_CONFIG;
35446  // Parse the template and check for errors.
35447  const parsed = parseTemplate(template, sourceMapUrl, {
35448    preserveWhitespaces,
35449    interpolationConfig
35450  });
35451  if (parsed.errors !== null) {
35452    const errors = parsed.errors.map(err => err.toString()).join(', ');
35453    throw new Error(`Errors during JIT compilation of template for ${typeName}: ${errors}`);
35454  }
35455  const binder = new R3TargetBinder(new SelectorMatcher());
35456  const boundTarget = binder.bind({
35457    template: parsed.nodes
35458  });
35459  return {
35460    template: parsed,
35461    interpolation: interpolationConfig,
35462    deferBlocks: createR3DeferredMetadata(boundTarget)
35463  };
35464}
35465/**
35466 * Convert the expression, if present to an `R3ProviderExpression`.
35467 *
35468 * In JIT mode we do not want the compiler to wrap the expression in a `forwardRef()` call because,
35469 * if it is referencing a type that has not yet been defined, it will have already been wrapped in
35470 * a `forwardRef()` - either by the application developer or during partial-compilation. Thus we can
35471 * use `ForwardRefHandling.None`.
35472 */
35473function convertToProviderExpression(obj, property) {
35474  if (obj.hasOwnProperty(property)) {
35475    return createMayBeForwardRefExpression(new WrappedNodeExpr(obj[property]), 0 /* ForwardRefHandling.None */);
35476  } else {
35477    return undefined;
35478  }
35479}
35480function wrapExpression(obj, property) {
35481  if (obj.hasOwnProperty(property)) {
35482    return new WrappedNodeExpr(obj[property]);
35483  } else {
35484    return undefined;
35485  }
35486}
35487function computeProvidedIn(providedIn) {
35488  const expression = typeof providedIn === 'function' ? new WrappedNodeExpr(providedIn) : new LiteralExpr(providedIn ?? null);
35489  // See `convertToProviderExpression()` for why this uses `ForwardRefHandling.None`.
35490  return createMayBeForwardRefExpression(expression, 0 /* ForwardRefHandling.None */);
35491}
35492function convertR3DependencyMetadataArray(facades) {
35493  return facades == null ? null : facades.map(convertR3DependencyMetadata);
35494}
35495function convertR3DependencyMetadata(facade) {
35496  const isAttributeDep = facade.attribute != null; // both `null` and `undefined`
35497  const rawToken = facade.token === null ? null : new WrappedNodeExpr(facade.token);
35498  // In JIT mode, if the dep is an `@Attribute()` then we use the attribute name given in
35499  // `attribute` rather than the `token`.
35500  const token = isAttributeDep ? new WrappedNodeExpr(facade.attribute) : rawToken;
35501  return createR3DependencyMetadata(token, isAttributeDep, facade.host, facade.optional, facade.self, facade.skipSelf);
35502}
35503function convertR3DeclareDependencyMetadata(facade) {
35504  const isAttributeDep = facade.attribute ?? false;
35505  const token = facade.token === null ? null : new WrappedNodeExpr(facade.token);
35506  return createR3DependencyMetadata(token, isAttributeDep, facade.host ?? false, facade.optional ?? false, facade.self ?? false, facade.skipSelf ?? false);
35507}
35508function createR3DependencyMetadata(token, isAttributeDep, host, optional, self, skipSelf) {
35509  // If the dep is an `@Attribute()` the `attributeNameType` ought to be the `unknown` type.
35510  // But types are not available at runtime so we just use a literal `"<unknown>"` string as a dummy
35511  // marker.
35512  const attributeNameType = isAttributeDep ? literal('unknown') : null;
35513  return {
35514    token,
35515    attributeNameType,
35516    host,
35517    optional,
35518    self,
35519    skipSelf
35520  };
35521}
35522function createR3DeferredMetadata(boundTarget) {
35523  const deferredBlocks = boundTarget.getDeferBlocks();
35524  const meta = new Map();
35525  for (const block of deferredBlocks) {
35526    const triggerElements = new Map();
35527    resolveDeferTriggers(block, block.triggers, boundTarget, triggerElements);
35528    resolveDeferTriggers(block, block.prefetchTriggers, boundTarget, triggerElements);
35529    // TODO: leaving `deps` empty in JIT mode for now, to be implemented as one of the next steps.
35530    meta.set(block, {
35531      deps: [],
35532      triggerElements
35533    });
35534  }
35535  return meta;
35536}
35537function resolveDeferTriggers(block, triggers, boundTarget, triggerElements) {
35538  Object.keys(triggers).forEach(key => {
35539    const trigger = triggers[key];
35540    triggerElements.set(trigger, boundTarget.getDeferredTriggerTarget(block, trigger));
35541  });
35542}
35543function extractHostBindings(propMetadata, sourceSpan, host) {
35544  // First parse the declarations from the metadata.
35545  const bindings = parseHostBindings(host || {});
35546  // After that check host bindings for errors
35547  const errors = verifyHostBindings(bindings, sourceSpan);
35548  if (errors.length) {
35549    throw new Error(errors.map(error => error.msg).join('\n'));
35550  }
35551  // Next, loop over the properties of the object, looking for @HostBinding and @HostListener.
35552  for (const field in propMetadata) {
35553    if (propMetadata.hasOwnProperty(field)) {
35554      propMetadata[field].forEach(ann => {
35555        if (isHostBinding(ann)) {
35556          // Since this is a decorator, we know that the value is a class member. Always access it
35557          // through `this` so that further down the line it can't be confused for a literal value
35558          // (e.g. if there's a property called `true`).
35559          bindings.properties[ann.hostPropertyName || field] = getSafePropertyAccessString('this', field);
35560        } else if (isHostListener(ann)) {
35561          bindings.listeners[ann.eventName || field] = `${field}(${(ann.args || []).join(',')})`;
35562        }
35563      });
35564    }
35565  }
35566  return bindings;
35567}
35568function isHostBinding(value) {
35569  return value.ngMetadataName === 'HostBinding';
35570}
35571function isHostListener(value) {
35572  return value.ngMetadataName === 'HostListener';
35573}
35574function isInput(value) {
35575  return value.ngMetadataName === 'Input';
35576}
35577function isOutput(value) {
35578  return value.ngMetadataName === 'Output';
35579}
35580function inputsPartialMetadataToInputMetadata(inputs) {
35581  return Object.keys(inputs).reduce((result, minifiedClassName) => {
35582    const value = inputs[minifiedClassName];
35583    // Handle legacy partial input output.
35584    if (typeof value === 'string' || Array.isArray(value)) {
35585      result[minifiedClassName] = parseLegacyInputPartialOutput(value);
35586    } else {
35587      result[minifiedClassName] = {
35588        bindingPropertyName: value.publicName,
35589        classPropertyName: minifiedClassName,
35590        transformFunction: value.transformFunction !== null ? new WrappedNodeExpr(value.transformFunction) : null,
35591        required: value.isRequired,
35592        isSignal: value.isSignal
35593      };
35594    }
35595    return result;
35596  }, {});
35597}
35598/**
35599 * Parses the legacy input partial output. For more details see `partial/directive.ts`.
35600 * TODO(legacy-partial-output-inputs): Remove in v18.
35601 */
35602function parseLegacyInputPartialOutput(value) {
35603  if (typeof value === 'string') {
35604    return {
35605      bindingPropertyName: value,
35606      classPropertyName: value,
35607      transformFunction: null,
35608      required: false,
35609      // legacy partial output does not capture signal inputs.
35610      isSignal: false
35611    };
35612  }
35613  return {
35614    bindingPropertyName: value[0],
35615    classPropertyName: value[1],
35616    transformFunction: value[2] ? new WrappedNodeExpr(value[2]) : null,
35617    required: false,
35618    // legacy partial output does not capture signal inputs.
35619    isSignal: false
35620  };
35621}
35622function parseInputsArray(values) {
35623  return values.reduce((results, value) => {
35624    if (typeof value === 'string') {
35625      const [bindingPropertyName, classPropertyName] = parseMappingString(value);
35626      results[classPropertyName] = {
35627        bindingPropertyName,
35628        classPropertyName,
35629        required: false,
35630        // Signal inputs not supported for the inputs array.
35631        isSignal: false,
35632        transformFunction: null
35633      };
35634    } else {
35635      results[value.name] = {
35636        bindingPropertyName: value.alias || value.name,
35637        classPropertyName: value.name,
35638        required: value.required || false,
35639        // Signal inputs not supported for the inputs array.
35640        isSignal: false,
35641        transformFunction: value.transform != null ? new WrappedNodeExpr(value.transform) : null
35642      };
35643    }
35644    return results;
35645  }, {});
35646}
35647function parseMappingStringArray(values) {
35648  return values.reduce((results, value) => {
35649    const [alias, fieldName] = parseMappingString(value);
35650    results[fieldName] = alias;
35651    return results;
35652  }, {});
35653}
35654function parseMappingString(value) {
35655  // Either the value is 'field' or 'field: property'. In the first case, `property` will
35656  // be undefined, in which case the field name should also be used as the property name.
35657  const [fieldName, bindingPropertyName] = value.split(':', 2).map(str => str.trim());
35658  return [bindingPropertyName ?? fieldName, fieldName];
35659}
35660function convertDeclarePipeFacadeToMetadata(declaration) {
35661  return {
35662    name: declaration.type.name,
35663    type: wrapReference(declaration.type),
35664    typeArgumentCount: 0,
35665    pipeName: declaration.name,
35666    deps: null,
35667    pure: declaration.pure ?? true,
35668    isStandalone: declaration.isStandalone ?? false
35669  };
35670}
35671function convertDeclareInjectorFacadeToMetadata(declaration) {
35672  return {
35673    name: declaration.type.name,
35674    type: wrapReference(declaration.type),
35675    providers: declaration.providers !== undefined && declaration.providers.length > 0 ? new WrappedNodeExpr(declaration.providers) : null,
35676    imports: declaration.imports !== undefined ? declaration.imports.map(i => new WrappedNodeExpr(i)) : []
35677  };
35678}
35679function publishFacade(global) {
35680  const ng = global.ng || (global.ng = {});
35681  ng.ɵcompilerFacade = new CompilerFacadeImpl();
35682}
35683
35684/**
35685 * @module
35686 * @description
35687 * Entry point for all public APIs of the compiler package.
35688 */
35689const VERSION = new Version('17.3.9');
35690class CompilerConfig {
35691  constructor({
35692    defaultEncapsulation = ViewEncapsulation.Emulated,
35693    preserveWhitespaces,
35694    strictInjectionParameters
35695  } = {}) {
35696    this.defaultEncapsulation = defaultEncapsulation;
35697    this.preserveWhitespaces = preserveWhitespacesDefault(noUndefined(preserveWhitespaces));
35698    this.strictInjectionParameters = strictInjectionParameters === true;
35699  }
35700}
35701function preserveWhitespacesDefault(preserveWhitespacesOption, defaultSetting = false) {
35702  return preserveWhitespacesOption === null ? defaultSetting : preserveWhitespacesOption;
35703}
35704const _I18N_ATTR = 'i18n';
35705const _I18N_ATTR_PREFIX = 'i18n-';
35706const _I18N_COMMENT_PREFIX_REGEXP = /^i18n:?/;
35707const MEANING_SEPARATOR = '|';
35708const ID_SEPARATOR = '@@';
35709let i18nCommentsWarned = false;
35710/**
35711 * Extract translatable messages from an html AST
35712 */
35713function extractMessages(nodes, interpolationConfig, implicitTags, implicitAttrs) {
35714  const visitor = new _Visitor(implicitTags, implicitAttrs);
35715  return visitor.extract(nodes, interpolationConfig);
35716}
35717function mergeTranslations(nodes, translations, interpolationConfig, implicitTags, implicitAttrs) {
35718  const visitor = new _Visitor(implicitTags, implicitAttrs);
35719  return visitor.merge(nodes, translations, interpolationConfig);
35720}
35721class ExtractionResult {
35722  constructor(messages, errors) {
35723    this.messages = messages;
35724    this.errors = errors;
35725  }
35726}
35727var _VisitorMode;
35728(function (_VisitorMode) {
35729  _VisitorMode[_VisitorMode["Extract"] = 0] = "Extract";
35730  _VisitorMode[_VisitorMode["Merge"] = 1] = "Merge";
35731})(_VisitorMode || (_VisitorMode = {}));
35732/**
35733 * This Visitor is used:
35734 * 1. to extract all the translatable strings from an html AST (see `extract()`),
35735 * 2. to replace the translatable strings with the actual translations (see `merge()`)
35736 *
35737 * @internal
35738 */
35739class _Visitor {
35740  constructor(_implicitTags, _implicitAttrs) {
35741    this._implicitTags = _implicitTags;
35742    this._implicitAttrs = _implicitAttrs;
35743  }
35744  /**
35745   * Extracts the messages from the tree
35746   */
35747  extract(nodes, interpolationConfig) {
35748    this._init(_VisitorMode.Extract, interpolationConfig);
35749    nodes.forEach(node => node.visit(this, null));
35750    if (this._inI18nBlock) {
35751      this._reportError(nodes[nodes.length - 1], 'Unclosed block');
35752    }
35753    return new ExtractionResult(this._messages, this._errors);
35754  }
35755  /**
35756   * Returns a tree where all translatable nodes are translated
35757   */
35758  merge(nodes, translations, interpolationConfig) {
35759    this._init(_VisitorMode.Merge, interpolationConfig);
35760    this._translations = translations;
35761    // Construct a single fake root element
35762    const wrapper = new Element('wrapper', [], nodes, undefined, undefined, undefined);
35763    const translatedNode = wrapper.visit(this, null);
35764    if (this._inI18nBlock) {
35765      this._reportError(nodes[nodes.length - 1], 'Unclosed block');
35766    }
35767    return new ParseTreeResult(translatedNode.children, this._errors);
35768  }
35769  visitExpansionCase(icuCase, context) {
35770    // Parse cases for translatable html attributes
35771    const expression = visitAll(this, icuCase.expression, context);
35772    if (this._mode === _VisitorMode.Merge) {
35773      return new ExpansionCase(icuCase.value, expression, icuCase.sourceSpan, icuCase.valueSourceSpan, icuCase.expSourceSpan);
35774    }
35775  }
35776  visitExpansion(icu, context) {
35777    this._mayBeAddBlockChildren(icu);
35778    const wasInIcu = this._inIcu;
35779    if (!this._inIcu) {
35780      // nested ICU messages should not be extracted but top-level translated as a whole
35781      if (this._isInTranslatableSection) {
35782        this._addMessage([icu]);
35783      }
35784      this._inIcu = true;
35785    }
35786    const cases = visitAll(this, icu.cases, context);
35787    if (this._mode === _VisitorMode.Merge) {
35788      icu = new Expansion(icu.switchValue, icu.type, cases, icu.sourceSpan, icu.switchValueSourceSpan);
35789    }
35790    this._inIcu = wasInIcu;
35791    return icu;
35792  }
35793  visitComment(comment, context) {
35794    const isOpening = _isOpeningComment(comment);
35795    if (isOpening && this._isInTranslatableSection) {
35796      this._reportError(comment, 'Could not start a block inside a translatable section');
35797      return;
35798    }
35799    const isClosing = _isClosingComment(comment);
35800    if (isClosing && !this._inI18nBlock) {
35801      this._reportError(comment, 'Trying to close an unopened block');
35802      return;
35803    }
35804    if (!this._inI18nNode && !this._inIcu) {
35805      if (!this._inI18nBlock) {
35806        if (isOpening) {
35807          // deprecated from v5 you should use <ng-container i18n> instead of i18n comments
35808          if (!i18nCommentsWarned && console && console.warn) {
35809            i18nCommentsWarned = true;
35810            const details = comment.sourceSpan.details ? `, ${comment.sourceSpan.details}` : '';
35811            // TODO(ocombe): use a log service once there is a public one available
35812            console.warn(`I18n comments are deprecated, use an <ng-container> element instead (${comment.sourceSpan.start}${details})`);
35813          }
35814          this._inI18nBlock = true;
35815          this._blockStartDepth = this._depth;
35816          this._blockChildren = [];
35817          this._blockMeaningAndDesc = comment.value.replace(_I18N_COMMENT_PREFIX_REGEXP, '').trim();
35818          this._openTranslatableSection(comment);
35819        }
35820      } else {
35821        if (isClosing) {
35822          if (this._depth == this._blockStartDepth) {
35823            this._closeTranslatableSection(comment, this._blockChildren);
35824            this._inI18nBlock = false;
35825            const message = this._addMessage(this._blockChildren, this._blockMeaningAndDesc);
35826            // merge attributes in sections
35827            const nodes = this._translateMessage(comment, message);
35828            return visitAll(this, nodes);
35829          } else {
35830            this._reportError(comment, 'I18N blocks should not cross element boundaries');
35831            return;
35832          }
35833        }
35834      }
35835    }
35836  }
35837  visitText(text, context) {
35838    if (this._isInTranslatableSection) {
35839      this._mayBeAddBlockChildren(text);
35840    }
35841    return text;
35842  }
35843  visitElement(el, context) {
35844    this._mayBeAddBlockChildren(el);
35845    this._depth++;
35846    const wasInI18nNode = this._inI18nNode;
35847    const wasInImplicitNode = this._inImplicitNode;
35848    let childNodes = [];
35849    let translatedChildNodes = undefined;
35850    // Extract:
35851    // - top level nodes with the (implicit) "i18n" attribute if not already in a section
35852    // - ICU messages
35853    const i18nAttr = _getI18nAttr(el);
35854    const i18nMeta = i18nAttr ? i18nAttr.value : '';
35855    const isImplicit = this._implicitTags.some(tag => el.name === tag) && !this._inIcu && !this._isInTranslatableSection;
35856    const isTopLevelImplicit = !wasInImplicitNode && isImplicit;
35857    this._inImplicitNode = wasInImplicitNode || isImplicit;
35858    if (!this._isInTranslatableSection && !this._inIcu) {
35859      if (i18nAttr || isTopLevelImplicit) {
35860        this._inI18nNode = true;
35861        const message = this._addMessage(el.children, i18nMeta);
35862        translatedChildNodes = this._translateMessage(el, message);
35863      }
35864      if (this._mode == _VisitorMode.Extract) {
35865        const isTranslatable = i18nAttr || isTopLevelImplicit;
35866        if (isTranslatable) this._openTranslatableSection(el);
35867        visitAll(this, el.children);
35868        if (isTranslatable) this._closeTranslatableSection(el, el.children);
35869      }
35870    } else {
35871      if (i18nAttr || isTopLevelImplicit) {
35872        this._reportError(el, 'Could not mark an element as translatable inside a translatable section');
35873      }
35874      if (this._mode == _VisitorMode.Extract) {
35875        // Descend into child nodes for extraction
35876        visitAll(this, el.children);
35877      }
35878    }
35879    if (this._mode === _VisitorMode.Merge) {
35880      const visitNodes = translatedChildNodes || el.children;
35881      visitNodes.forEach(child => {
35882        const visited = child.visit(this, context);
35883        if (visited && !this._isInTranslatableSection) {
35884          // Do not add the children from translatable sections (= i18n blocks here)
35885          // They will be added later in this loop when the block closes (i.e. on `<!-- /i18n -->`)
35886          childNodes = childNodes.concat(visited);
35887        }
35888      });
35889    }
35890    this._visitAttributesOf(el);
35891    this._depth--;
35892    this._inI18nNode = wasInI18nNode;
35893    this._inImplicitNode = wasInImplicitNode;
35894    if (this._mode === _VisitorMode.Merge) {
35895      const translatedAttrs = this._translateAttributes(el);
35896      return new Element(el.name, translatedAttrs, childNodes, el.sourceSpan, el.startSourceSpan, el.endSourceSpan);
35897    }
35898    return null;
35899  }
35900  visitAttribute(attribute, context) {
35901    throw new Error('unreachable code');
35902  }
35903  visitBlock(block, context) {
35904    visitAll(this, block.children, context);
35905  }
35906  visitBlockParameter(parameter, context) {}
35907  _init(mode, interpolationConfig) {
35908    this._mode = mode;
35909    this._inI18nBlock = false;
35910    this._inI18nNode = false;
35911    this._depth = 0;
35912    this._inIcu = false;
35913    this._msgCountAtSectionStart = undefined;
35914    this._errors = [];
35915    this._messages = [];
35916    this._inImplicitNode = false;
35917    this._createI18nMessage = createI18nMessageFactory(interpolationConfig, DEFAULT_CONTAINER_BLOCKS);
35918  }
35919  // looks for translatable attributes
35920  _visitAttributesOf(el) {
35921    const explicitAttrNameToValue = {};
35922    const implicitAttrNames = this._implicitAttrs[el.name] || [];
35923    el.attrs.filter(attr => attr.name.startsWith(_I18N_ATTR_PREFIX)).forEach(attr => explicitAttrNameToValue[attr.name.slice(_I18N_ATTR_PREFIX.length)] = attr.value);
35924    el.attrs.forEach(attr => {
35925      if (attr.name in explicitAttrNameToValue) {
35926        this._addMessage([attr], explicitAttrNameToValue[attr.name]);
35927      } else if (implicitAttrNames.some(name => attr.name === name)) {
35928        this._addMessage([attr]);
35929      }
35930    });
35931  }
35932  // add a translatable message
35933  _addMessage(ast, msgMeta) {
35934    if (ast.length == 0 || ast.length == 1 && ast[0] instanceof Attribute && !ast[0].value) {
35935      // Do not create empty messages
35936      return null;
35937    }
35938    const {
35939      meaning,
35940      description,
35941      id
35942    } = _parseMessageMeta(msgMeta);
35943    const message = this._createI18nMessage(ast, meaning, description, id);
35944    this._messages.push(message);
35945    return message;
35946  }
35947  // Translates the given message given the `TranslationBundle`
35948  // This is used for translating elements / blocks - see `_translateAttributes` for attributes
35949  // no-op when called in extraction mode (returns [])
35950  _translateMessage(el, message) {
35951    if (message && this._mode === _VisitorMode.Merge) {
35952      const nodes = this._translations.get(message);
35953      if (nodes) {
35954        return nodes;
35955      }
35956      this._reportError(el, `Translation unavailable for message id="${this._translations.digest(message)}"`);
35957    }
35958    return [];
35959  }
35960  // translate the attributes of an element and remove i18n specific attributes
35961  _translateAttributes(el) {
35962    const attributes = el.attrs;
35963    const i18nParsedMessageMeta = {};
35964    attributes.forEach(attr => {
35965      if (attr.name.startsWith(_I18N_ATTR_PREFIX)) {
35966        i18nParsedMessageMeta[attr.name.slice(_I18N_ATTR_PREFIX.length)] = _parseMessageMeta(attr.value);
35967      }
35968    });
35969    const translatedAttributes = [];
35970    attributes.forEach(attr => {
35971      if (attr.name === _I18N_ATTR || attr.name.startsWith(_I18N_ATTR_PREFIX)) {
35972        // strip i18n specific attributes
35973        return;
35974      }
35975      if (attr.value && attr.value != '' && i18nParsedMessageMeta.hasOwnProperty(attr.name)) {
35976        const {
35977          meaning,
35978          description,
35979          id
35980        } = i18nParsedMessageMeta[attr.name];
35981        const message = this._createI18nMessage([attr], meaning, description, id);
35982        const nodes = this._translations.get(message);
35983        if (nodes) {
35984          if (nodes.length == 0) {
35985            translatedAttributes.push(new Attribute(attr.name, '', attr.sourceSpan, undefined /* keySpan */, undefined /* valueSpan */, undefined /* valueTokens */, undefined /* i18n */));
35986          } else if (nodes[0] instanceof Text) {
35987            const value = nodes[0].value;
35988            translatedAttributes.push(new Attribute(attr.name, value, attr.sourceSpan, undefined /* keySpan */, undefined /* valueSpan */, undefined /* valueTokens */, undefined /* i18n */));
35989          } else {
35990            this._reportError(el, `Unexpected translation for attribute "${attr.name}" (id="${id || this._translations.digest(message)}")`);
35991          }
35992        } else {
35993          this._reportError(el, `Translation unavailable for attribute "${attr.name}" (id="${id || this._translations.digest(message)}")`);
35994        }
35995      } else {
35996        translatedAttributes.push(attr);
35997      }
35998    });
35999    return translatedAttributes;
36000  }
36001  /**
36002   * Add the node as a child of the block when:
36003   * - we are in a block,
36004   * - we are not inside a ICU message (those are handled separately),
36005   * - the node is a "direct child" of the block
36006   */
36007  _mayBeAddBlockChildren(node) {
36008    if (this._inI18nBlock && !this._inIcu && this._depth == this._blockStartDepth) {
36009      this._blockChildren.push(node);
36010    }
36011  }
36012  /**
36013   * Marks the start of a section, see `_closeTranslatableSection`
36014   */
36015  _openTranslatableSection(node) {
36016    if (this._isInTranslatableSection) {
36017      this._reportError(node, 'Unexpected section start');
36018    } else {
36019      this._msgCountAtSectionStart = this._messages.length;
36020    }
36021  }
36022  /**
36023   * A translatable section could be:
36024   * - the content of translatable element,
36025   * - nodes between `<!-- i18n -->` and `<!-- /i18n -->` comments
36026   */
36027  get _isInTranslatableSection() {
36028    return this._msgCountAtSectionStart !== void 0;
36029  }
36030  /**
36031   * Terminates a section.
36032   *
36033   * If a section has only one significant children (comments not significant) then we should not
36034   * keep the message from this children:
36035   *
36036   * `<p i18n="meaning|description">{ICU message}</p>` would produce two messages:
36037   * - one for the <p> content with meaning and description,
36038   * - another one for the ICU message.
36039   *
36040   * In this case the last message is discarded as it contains less information (the AST is
36041   * otherwise identical).
36042   *
36043   * Note that we should still keep messages extracted from attributes inside the section (ie in the
36044   * ICU message here)
36045   */
36046  _closeTranslatableSection(node, directChildren) {
36047    if (!this._isInTranslatableSection) {
36048      this._reportError(node, 'Unexpected section end');
36049      return;
36050    }
36051    const startIndex = this._msgCountAtSectionStart;
36052    const significantChildren = directChildren.reduce((count, node) => count + (node instanceof Comment ? 0 : 1), 0);
36053    if (significantChildren == 1) {
36054      for (let i = this._messages.length - 1; i >= startIndex; i--) {
36055        const ast = this._messages[i].nodes;
36056        if (!(ast.length == 1 && ast[0] instanceof Text$2)) {
36057          this._messages.splice(i, 1);
36058          break;
36059        }
36060      }
36061    }
36062    this._msgCountAtSectionStart = undefined;
36063  }
36064  _reportError(node, msg) {
36065    this._errors.push(new I18nError(node.sourceSpan, msg));
36066  }
36067}
36068function _isOpeningComment(n) {
36069  return !!(n instanceof Comment && n.value && n.value.startsWith('i18n'));
36070}
36071function _isClosingComment(n) {
36072  return !!(n instanceof Comment && n.value && n.value === '/i18n');
36073}
36074function _getI18nAttr(p) {
36075  return p.attrs.find(attr => attr.name === _I18N_ATTR) || null;
36076}
36077function _parseMessageMeta(i18n) {
36078  if (!i18n) return {
36079    meaning: '',
36080    description: '',
36081    id: ''
36082  };
36083  const idIndex = i18n.indexOf(ID_SEPARATOR);
36084  const descIndex = i18n.indexOf(MEANING_SEPARATOR);
36085  const [meaningAndDesc, id] = idIndex > -1 ? [i18n.slice(0, idIndex), i18n.slice(idIndex + 2)] : [i18n, ''];
36086  const [meaning, description] = descIndex > -1 ? [meaningAndDesc.slice(0, descIndex), meaningAndDesc.slice(descIndex + 1)] : ['', meaningAndDesc];
36087  return {
36088    meaning,
36089    description,
36090    id: id.trim()
36091  };
36092}
36093class XmlTagDefinition {
36094  constructor() {
36095    this.closedByParent = false;
36096    this.implicitNamespacePrefix = null;
36097    this.isVoid = false;
36098    this.ignoreFirstLf = false;
36099    this.canSelfClose = true;
36100    this.preventNamespaceInheritance = false;
36101  }
36102  requireExtraParent(currentParent) {
36103    return false;
36104  }
36105  isClosedByChild(name) {
36106    return false;
36107  }
36108  getContentType() {
36109    return TagContentType.PARSABLE_DATA;
36110  }
36111}
36112const _TAG_DEFINITION = new XmlTagDefinition();
36113function getXmlTagDefinition(tagName) {
36114  return _TAG_DEFINITION;
36115}
36116class XmlParser extends Parser {
36117  constructor() {
36118    super(getXmlTagDefinition);
36119  }
36120  parse(source, url, options = {}) {
36121    // Blocks aren't supported in an XML context.
36122    return super.parse(source, url, {
36123      ...options,
36124      tokenizeBlocks: false
36125    });
36126  }
36127}
36128const _VERSION$1 = '1.2';
36129const _XMLNS$1 = 'urn:oasis:names:tc:xliff:document:1.2';
36130// TODO(vicb): make this a param (s/_/-/)
36131const _DEFAULT_SOURCE_LANG$1 = 'en';
36132const _PLACEHOLDER_TAG$2 = 'x';
36133const _MARKER_TAG$1 = 'mrk';
36134const _FILE_TAG = 'file';
36135const _SOURCE_TAG$1 = 'source';
36136const _SEGMENT_SOURCE_TAG = 'seg-source';
36137const _ALT_TRANS_TAG = 'alt-trans';
36138const _TARGET_TAG$1 = 'target';
36139const _UNIT_TAG$1 = 'trans-unit';
36140const _CONTEXT_GROUP_TAG = 'context-group';
36141const _CONTEXT_TAG = 'context';
36142// https://docs.oasis-open.org/xliff/v1.2/os/xliff-core.html
36143// https://docs.oasis-open.org/xliff/v1.2/xliff-profile-html/xliff-profile-html-1.2.html
36144class Xliff extends Serializer {
36145  write(messages, locale) {
36146    const visitor = new _WriteVisitor$1();
36147    const transUnits = [];
36148    messages.forEach(message => {
36149      let contextTags = [];
36150      message.sources.forEach(source => {
36151        let contextGroupTag = new Tag(_CONTEXT_GROUP_TAG, {
36152          purpose: 'location'
36153        });
36154        contextGroupTag.children.push(new CR(10), new Tag(_CONTEXT_TAG, {
36155          'context-type': 'sourcefile'
36156        }, [new Text$1(source.filePath)]), new CR(10), new Tag(_CONTEXT_TAG, {
36157          'context-type': 'linenumber'
36158        }, [new Text$1(`${source.startLine}`)]), new CR(8));
36159        contextTags.push(new CR(8), contextGroupTag);
36160      });
36161      const transUnit = new Tag(_UNIT_TAG$1, {
36162        id: message.id,
36163        datatype: 'html'
36164      });
36165      transUnit.children.push(new CR(8), new Tag(_SOURCE_TAG$1, {}, visitor.serialize(message.nodes)), ...contextTags);
36166      if (message.description) {
36167        transUnit.children.push(new CR(8), new Tag('note', {
36168          priority: '1',
36169          from: 'description'
36170        }, [new Text$1(message.description)]));
36171      }
36172      if (message.meaning) {
36173        transUnit.children.push(new CR(8), new Tag('note', {
36174          priority: '1',
36175          from: 'meaning'
36176        }, [new Text$1(message.meaning)]));
36177      }
36178      transUnit.children.push(new CR(6));
36179      transUnits.push(new CR(6), transUnit);
36180    });
36181    const body = new Tag('body', {}, [...transUnits, new CR(4)]);
36182    const file = new Tag('file', {
36183      'source-language': locale || _DEFAULT_SOURCE_LANG$1,
36184      datatype: 'plaintext',
36185      original: 'ng2.template'
36186    }, [new CR(4), body, new CR(2)]);
36187    const xliff = new Tag('xliff', {
36188      version: _VERSION$1,
36189      xmlns: _XMLNS$1
36190    }, [new CR(2), file, new CR()]);
36191    return serialize([new Declaration({
36192      version: '1.0',
36193      encoding: 'UTF-8'
36194    }), new CR(), xliff, new CR()]);
36195  }
36196  load(content, url) {
36197    // xliff to xml nodes
36198    const xliffParser = new XliffParser();
36199    const {
36200      locale,
36201      msgIdToHtml,
36202      errors
36203    } = xliffParser.parse(content, url);
36204    // xml nodes to i18n nodes
36205    const i18nNodesByMsgId = {};
36206    const converter = new XmlToI18n$2();
36207    Object.keys(msgIdToHtml).forEach(msgId => {
36208      const {
36209        i18nNodes,
36210        errors: e
36211      } = converter.convert(msgIdToHtml[msgId], url);
36212      errors.push(...e);
36213      i18nNodesByMsgId[msgId] = i18nNodes;
36214    });
36215    if (errors.length) {
36216      throw new Error(`xliff parse errors:\n${errors.join('\n')}`);
36217    }
36218    return {
36219      locale: locale,
36220      i18nNodesByMsgId
36221    };
36222  }
36223  digest(message) {
36224    return digest$1(message);
36225  }
36226}
36227class _WriteVisitor$1 {
36228  visitText(text, context) {
36229    return [new Text$1(text.value)];
36230  }
36231  visitContainer(container, context) {
36232    const nodes = [];
36233    container.children.forEach(node => nodes.push(...node.visit(this)));
36234    return nodes;
36235  }
36236  visitIcu(icu, context) {
36237    const nodes = [new Text$1(`{${icu.expressionPlaceholder}, ${icu.type}, `)];
36238    Object.keys(icu.cases).forEach(c => {
36239      nodes.push(new Text$1(`${c} {`), ...icu.cases[c].visit(this), new Text$1(`} `));
36240    });
36241    nodes.push(new Text$1(`}`));
36242    return nodes;
36243  }
36244  visitTagPlaceholder(ph, context) {
36245    const ctype = getCtypeForTag(ph.tag);
36246    if (ph.isVoid) {
36247      // void tags have no children nor closing tags
36248      return [new Tag(_PLACEHOLDER_TAG$2, {
36249        id: ph.startName,
36250        ctype,
36251        'equiv-text': `<${ph.tag}/>`
36252      })];
36253    }
36254    const startTagPh = new Tag(_PLACEHOLDER_TAG$2, {
36255      id: ph.startName,
36256      ctype,
36257      'equiv-text': `<${ph.tag}>`
36258    });
36259    const closeTagPh = new Tag(_PLACEHOLDER_TAG$2, {
36260      id: ph.closeName,
36261      ctype,
36262      'equiv-text': `</${ph.tag}>`
36263    });
36264    return [startTagPh, ...this.serialize(ph.children), closeTagPh];
36265  }
36266  visitPlaceholder(ph, context) {
36267    return [new Tag(_PLACEHOLDER_TAG$2, {
36268      id: ph.name,
36269      'equiv-text': `{{${ph.value}}}`
36270    })];
36271  }
36272  visitBlockPlaceholder(ph, context) {
36273    const ctype = `x-${ph.name.toLowerCase().replace(/[^a-z0-9]/g, '-')}`;
36274    const startTagPh = new Tag(_PLACEHOLDER_TAG$2, {
36275      id: ph.startName,
36276      ctype,
36277      'equiv-text': `@${ph.name}`
36278    });
36279    const closeTagPh = new Tag(_PLACEHOLDER_TAG$2, {
36280      id: ph.closeName,
36281      ctype,
36282      'equiv-text': `}`
36283    });
36284    return [startTagPh, ...this.serialize(ph.children), closeTagPh];
36285  }
36286  visitIcuPlaceholder(ph, context) {
36287    const equivText = `{${ph.value.expression}, ${ph.value.type}, ${Object.keys(ph.value.cases).map(value => value + ' {...}').join(' ')}}`;
36288    return [new Tag(_PLACEHOLDER_TAG$2, {
36289      id: ph.name,
36290      'equiv-text': equivText
36291    })];
36292  }
36293  serialize(nodes) {
36294    return [].concat(...nodes.map(node => node.visit(this)));
36295  }
36296}
36297// TODO(vicb): add error management (structure)
36298// Extract messages as xml nodes from the xliff file
36299class XliffParser {
36300  constructor() {
36301    this._locale = null;
36302  }
36303  parse(xliff, url) {
36304    this._unitMlString = null;
36305    this._msgIdToHtml = {};
36306    const xml = new XmlParser().parse(xliff, url);
36307    this._errors = xml.errors;
36308    visitAll(this, xml.rootNodes, null);
36309    return {
36310      msgIdToHtml: this._msgIdToHtml,
36311      errors: this._errors,
36312      locale: this._locale
36313    };
36314  }
36315  visitElement(element, context) {
36316    switch (element.name) {
36317      case _UNIT_TAG$1:
36318        this._unitMlString = null;
36319        const idAttr = element.attrs.find(attr => attr.name === 'id');
36320        if (!idAttr) {
36321          this._addError(element, `<${_UNIT_TAG$1}> misses the "id" attribute`);
36322        } else {
36323          const id = idAttr.value;
36324          if (this._msgIdToHtml.hasOwnProperty(id)) {
36325            this._addError(element, `Duplicated translations for msg ${id}`);
36326          } else {
36327            visitAll(this, element.children, null);
36328            if (typeof this._unitMlString === 'string') {
36329              this._msgIdToHtml[id] = this._unitMlString;
36330            } else {
36331              this._addError(element, `Message ${id} misses a translation`);
36332            }
36333          }
36334        }
36335        break;
36336      // ignore those tags
36337      case _SOURCE_TAG$1:
36338      case _SEGMENT_SOURCE_TAG:
36339      case _ALT_TRANS_TAG:
36340        break;
36341      case _TARGET_TAG$1:
36342        const innerTextStart = element.startSourceSpan.end.offset;
36343        const innerTextEnd = element.endSourceSpan.start.offset;
36344        const content = element.startSourceSpan.start.file.content;
36345        const innerText = content.slice(innerTextStart, innerTextEnd);
36346        this._unitMlString = innerText;
36347        break;
36348      case _FILE_TAG:
36349        const localeAttr = element.attrs.find(attr => attr.name === 'target-language');
36350        if (localeAttr) {
36351          this._locale = localeAttr.value;
36352        }
36353        visitAll(this, element.children, null);
36354        break;
36355      default:
36356        // TODO(vicb): assert file structure, xliff version
36357        // For now only recurse on unhandled nodes
36358        visitAll(this, element.children, null);
36359    }
36360  }
36361  visitAttribute(attribute, context) {}
36362  visitText(text, context) {}
36363  visitComment(comment, context) {}
36364  visitExpansion(expansion, context) {}
36365  visitExpansionCase(expansionCase, context) {}
36366  visitBlock(block, context) {}
36367  visitBlockParameter(parameter, context) {}
36368  _addError(node, message) {
36369    this._errors.push(new I18nError(node.sourceSpan, message));
36370  }
36371}
36372// Convert ml nodes (xliff syntax) to i18n nodes
36373class XmlToI18n$2 {
36374  convert(message, url) {
36375    const xmlIcu = new XmlParser().parse(message, url, {
36376      tokenizeExpansionForms: true
36377    });
36378    this._errors = xmlIcu.errors;
36379    const i18nNodes = this._errors.length > 0 || xmlIcu.rootNodes.length == 0 ? [] : [].concat(...visitAll(this, xmlIcu.rootNodes));
36380    return {
36381      i18nNodes: i18nNodes,
36382      errors: this._errors
36383    };
36384  }
36385  visitText(text, context) {
36386    return new Text$2(text.value, text.sourceSpan);
36387  }
36388  visitElement(el, context) {
36389    if (el.name === _PLACEHOLDER_TAG$2) {
36390      const nameAttr = el.attrs.find(attr => attr.name === 'id');
36391      if (nameAttr) {
36392        return new Placeholder('', nameAttr.value, el.sourceSpan);
36393      }
36394      this._addError(el, `<${_PLACEHOLDER_TAG$2}> misses the "id" attribute`);
36395      return null;
36396    }
36397    if (el.name === _MARKER_TAG$1) {
36398      return [].concat(...visitAll(this, el.children));
36399    }
36400    this._addError(el, `Unexpected tag`);
36401    return null;
36402  }
36403  visitExpansion(icu, context) {
36404    const caseMap = {};
36405    visitAll(this, icu.cases).forEach(c => {
36406      caseMap[c.value] = new Container(c.nodes, icu.sourceSpan);
36407    });
36408    return new Icu(icu.switchValue, icu.type, caseMap, icu.sourceSpan);
36409  }
36410  visitExpansionCase(icuCase, context) {
36411    return {
36412      value: icuCase.value,
36413      nodes: visitAll(this, icuCase.expression)
36414    };
36415  }
36416  visitComment(comment, context) {}
36417  visitAttribute(attribute, context) {}
36418  visitBlock(block, context) {}
36419  visitBlockParameter(parameter, context) {}
36420  _addError(node, message) {
36421    this._errors.push(new I18nError(node.sourceSpan, message));
36422  }
36423}
36424function getCtypeForTag(tag) {
36425  switch (tag.toLowerCase()) {
36426    case 'br':
36427      return 'lb';
36428    case 'img':
36429      return 'image';
36430    default:
36431      return `x-${tag}`;
36432  }
36433}
36434const _VERSION = '2.0';
36435const _XMLNS = 'urn:oasis:names:tc:xliff:document:2.0';
36436// TODO(vicb): make this a param (s/_/-/)
36437const _DEFAULT_SOURCE_LANG = 'en';
36438const _PLACEHOLDER_TAG$1 = 'ph';
36439const _PLACEHOLDER_SPANNING_TAG = 'pc';
36440const _MARKER_TAG = 'mrk';
36441const _XLIFF_TAG = 'xliff';
36442const _SOURCE_TAG = 'source';
36443const _TARGET_TAG = 'target';
36444const _UNIT_TAG = 'unit';
36445// https://docs.oasis-open.org/xliff/xliff-core/v2.0/os/xliff-core-v2.0-os.html
36446class Xliff2 extends Serializer {
36447  write(messages, locale) {
36448    const visitor = new _WriteVisitor();
36449    const units = [];
36450    messages.forEach(message => {
36451      const unit = new Tag(_UNIT_TAG, {
36452        id: message.id
36453      });
36454      const notes = new Tag('notes');
36455      if (message.description || message.meaning) {
36456        if (message.description) {
36457          notes.children.push(new CR(8), new Tag('note', {
36458            category: 'description'
36459          }, [new Text$1(message.description)]));
36460        }
36461        if (message.meaning) {
36462          notes.children.push(new CR(8), new Tag('note', {
36463            category: 'meaning'
36464          }, [new Text$1(message.meaning)]));
36465        }
36466      }
36467      message.sources.forEach(source => {
36468        notes.children.push(new CR(8), new Tag('note', {
36469          category: 'location'
36470        }, [new Text$1(`${source.filePath}:${source.startLine}${source.endLine !== source.startLine ? ',' + source.endLine : ''}`)]));
36471      });
36472      notes.children.push(new CR(6));
36473      unit.children.push(new CR(6), notes);
36474      const segment = new Tag('segment');
36475      segment.children.push(new CR(8), new Tag(_SOURCE_TAG, {}, visitor.serialize(message.nodes)), new CR(6));
36476      unit.children.push(new CR(6), segment, new CR(4));
36477      units.push(new CR(4), unit);
36478    });
36479    const file = new Tag('file', {
36480      'original': 'ng.template',
36481      id: 'ngi18n'
36482    }, [...units, new CR(2)]);
36483    const xliff = new Tag(_XLIFF_TAG, {
36484      version: _VERSION,
36485      xmlns: _XMLNS,
36486      srcLang: locale || _DEFAULT_SOURCE_LANG
36487    }, [new CR(2), file, new CR()]);
36488    return serialize([new Declaration({
36489      version: '1.0',
36490      encoding: 'UTF-8'
36491    }), new CR(), xliff, new CR()]);
36492  }
36493  load(content, url) {
36494    // xliff to xml nodes
36495    const xliff2Parser = new Xliff2Parser();
36496    const {
36497      locale,
36498      msgIdToHtml,
36499      errors
36500    } = xliff2Parser.parse(content, url);
36501    // xml nodes to i18n nodes
36502    const i18nNodesByMsgId = {};
36503    const converter = new XmlToI18n$1();
36504    Object.keys(msgIdToHtml).forEach(msgId => {
36505      const {
36506        i18nNodes,
36507        errors: e
36508      } = converter.convert(msgIdToHtml[msgId], url);
36509      errors.push(...e);
36510      i18nNodesByMsgId[msgId] = i18nNodes;
36511    });
36512    if (errors.length) {
36513      throw new Error(`xliff2 parse errors:\n${errors.join('\n')}`);
36514    }
36515    return {
36516      locale: locale,
36517      i18nNodesByMsgId
36518    };
36519  }
36520  digest(message) {
36521    return decimalDigest(message);
36522  }
36523}
36524class _WriteVisitor {
36525  constructor() {
36526    this._nextPlaceholderId = 0;
36527  }
36528  visitText(text, context) {
36529    return [new Text$1(text.value)];
36530  }
36531  visitContainer(container, context) {
36532    const nodes = [];
36533    container.children.forEach(node => nodes.push(...node.visit(this)));
36534    return nodes;
36535  }
36536  visitIcu(icu, context) {
36537    const nodes = [new Text$1(`{${icu.expressionPlaceholder}, ${icu.type}, `)];
36538    Object.keys(icu.cases).forEach(c => {
36539      nodes.push(new Text$1(`${c} {`), ...icu.cases[c].visit(this), new Text$1(`} `));
36540    });
36541    nodes.push(new Text$1(`}`));
36542    return nodes;
36543  }
36544  visitTagPlaceholder(ph, context) {
36545    const type = getTypeForTag(ph.tag);
36546    if (ph.isVoid) {
36547      const tagPh = new Tag(_PLACEHOLDER_TAG$1, {
36548        id: (this._nextPlaceholderId++).toString(),
36549        equiv: ph.startName,
36550        type: type,
36551        disp: `<${ph.tag}/>`
36552      });
36553      return [tagPh];
36554    }
36555    const tagPc = new Tag(_PLACEHOLDER_SPANNING_TAG, {
36556      id: (this._nextPlaceholderId++).toString(),
36557      equivStart: ph.startName,
36558      equivEnd: ph.closeName,
36559      type: type,
36560      dispStart: `<${ph.tag}>`,
36561      dispEnd: `</${ph.tag}>`
36562    });
36563    const nodes = [].concat(...ph.children.map(node => node.visit(this)));
36564    if (nodes.length) {
36565      nodes.forEach(node => tagPc.children.push(node));
36566    } else {
36567      tagPc.children.push(new Text$1(''));
36568    }
36569    return [tagPc];
36570  }
36571  visitPlaceholder(ph, context) {
36572    const idStr = (this._nextPlaceholderId++).toString();
36573    return [new Tag(_PLACEHOLDER_TAG$1, {
36574      id: idStr,
36575      equiv: ph.name,
36576      disp: `{{${ph.value}}}`
36577    })];
36578  }
36579  visitBlockPlaceholder(ph, context) {
36580    const tagPc = new Tag(_PLACEHOLDER_SPANNING_TAG, {
36581      id: (this._nextPlaceholderId++).toString(),
36582      equivStart: ph.startName,
36583      equivEnd: ph.closeName,
36584      type: 'other',
36585      dispStart: `@${ph.name}`,
36586      dispEnd: `}`
36587    });
36588    const nodes = [].concat(...ph.children.map(node => node.visit(this)));
36589    if (nodes.length) {
36590      nodes.forEach(node => tagPc.children.push(node));
36591    } else {
36592      tagPc.children.push(new Text$1(''));
36593    }
36594    return [tagPc];
36595  }
36596  visitIcuPlaceholder(ph, context) {
36597    const cases = Object.keys(ph.value.cases).map(value => value + ' {...}').join(' ');
36598    const idStr = (this._nextPlaceholderId++).toString();
36599    return [new Tag(_PLACEHOLDER_TAG$1, {
36600      id: idStr,
36601      equiv: ph.name,
36602      disp: `{${ph.value.expression}, ${ph.value.type}, ${cases}}`
36603    })];
36604  }
36605  serialize(nodes) {
36606    this._nextPlaceholderId = 0;
36607    return [].concat(...nodes.map(node => node.visit(this)));
36608  }
36609}
36610// Extract messages as xml nodes from the xliff file
36611class Xliff2Parser {
36612  constructor() {
36613    this._locale = null;
36614  }
36615  parse(xliff, url) {
36616    this._unitMlString = null;
36617    this._msgIdToHtml = {};
36618    const xml = new XmlParser().parse(xliff, url);
36619    this._errors = xml.errors;
36620    visitAll(this, xml.rootNodes, null);
36621    return {
36622      msgIdToHtml: this._msgIdToHtml,
36623      errors: this._errors,
36624      locale: this._locale
36625    };
36626  }
36627  visitElement(element, context) {
36628    switch (element.name) {
36629      case _UNIT_TAG:
36630        this._unitMlString = null;
36631        const idAttr = element.attrs.find(attr => attr.name === 'id');
36632        if (!idAttr) {
36633          this._addError(element, `<${_UNIT_TAG}> misses the "id" attribute`);
36634        } else {
36635          const id = idAttr.value;
36636          if (this._msgIdToHtml.hasOwnProperty(id)) {
36637            this._addError(element, `Duplicated translations for msg ${id}`);
36638          } else {
36639            visitAll(this, element.children, null);
36640            if (typeof this._unitMlString === 'string') {
36641              this._msgIdToHtml[id] = this._unitMlString;
36642            } else {
36643              this._addError(element, `Message ${id} misses a translation`);
36644            }
36645          }
36646        }
36647        break;
36648      case _SOURCE_TAG:
36649        // ignore source message
36650        break;
36651      case _TARGET_TAG:
36652        const innerTextStart = element.startSourceSpan.end.offset;
36653        const innerTextEnd = element.endSourceSpan.start.offset;
36654        const content = element.startSourceSpan.start.file.content;
36655        const innerText = content.slice(innerTextStart, innerTextEnd);
36656        this._unitMlString = innerText;
36657        break;
36658      case _XLIFF_TAG:
36659        const localeAttr = element.attrs.find(attr => attr.name === 'trgLang');
36660        if (localeAttr) {
36661          this._locale = localeAttr.value;
36662        }
36663        const versionAttr = element.attrs.find(attr => attr.name === 'version');
36664        if (versionAttr) {
36665          const version = versionAttr.value;
36666          if (version !== '2.0') {
36667            this._addError(element, `The XLIFF file version ${version} is not compatible with XLIFF 2.0 serializer`);
36668          } else {
36669            visitAll(this, element.children, null);
36670          }
36671        }
36672        break;
36673      default:
36674        visitAll(this, element.children, null);
36675    }
36676  }
36677  visitAttribute(attribute, context) {}
36678  visitText(text, context) {}
36679  visitComment(comment, context) {}
36680  visitExpansion(expansion, context) {}
36681  visitExpansionCase(expansionCase, context) {}
36682  visitBlock(block, context) {}
36683  visitBlockParameter(parameter, context) {}
36684  _addError(node, message) {
36685    this._errors.push(new I18nError(node.sourceSpan, message));
36686  }
36687}
36688// Convert ml nodes (xliff syntax) to i18n nodes
36689class XmlToI18n$1 {
36690  convert(message, url) {
36691    const xmlIcu = new XmlParser().parse(message, url, {
36692      tokenizeExpansionForms: true
36693    });
36694    this._errors = xmlIcu.errors;
36695    const i18nNodes = this._errors.length > 0 || xmlIcu.rootNodes.length == 0 ? [] : [].concat(...visitAll(this, xmlIcu.rootNodes));
36696    return {
36697      i18nNodes,
36698      errors: this._errors
36699    };
36700  }
36701  visitText(text, context) {
36702    return new Text$2(text.value, text.sourceSpan);
36703  }
36704  visitElement(el, context) {
36705    switch (el.name) {
36706      case _PLACEHOLDER_TAG$1:
36707        const nameAttr = el.attrs.find(attr => attr.name === 'equiv');
36708        if (nameAttr) {
36709          return [new Placeholder('', nameAttr.value, el.sourceSpan)];
36710        }
36711        this._addError(el, `<${_PLACEHOLDER_TAG$1}> misses the "equiv" attribute`);
36712        break;
36713      case _PLACEHOLDER_SPANNING_TAG:
36714        const startAttr = el.attrs.find(attr => attr.name === 'equivStart');
36715        const endAttr = el.attrs.find(attr => attr.name === 'equivEnd');
36716        if (!startAttr) {
36717          this._addError(el, `<${_PLACEHOLDER_TAG$1}> misses the "equivStart" attribute`);
36718        } else if (!endAttr) {
36719          this._addError(el, `<${_PLACEHOLDER_TAG$1}> misses the "equivEnd" attribute`);
36720        } else {
36721          const startId = startAttr.value;
36722          const endId = endAttr.value;
36723          const nodes = [];
36724          return nodes.concat(new Placeholder('', startId, el.sourceSpan), ...el.children.map(node =>
36724 node.visit(this, null)), new Placeholder('', endId, el.sourceSpan));
36725        }
36726        break;
36727      case _MARKER_TAG:
36728        return [].concat(...visitAll(this, el.children));
36729      default:
36730        this._addError(el, `Unexpected tag`);
36731    }
36732    return null;
36733  }
36734  visitExpansion(icu, context) {
36735    const caseMap = {};
36736    visitAll(this, icu.cases).forEach(c => {
36737      caseMap[c.value] = new Container(c.nodes, icu.sourceSpan);
36738    });
36739    return new Icu(icu.switchValue, icu.type, caseMap, icu.sourceSpan);
36740  }
36741  visitExpansionCase(icuCase, context) {
36742    return {
36743      value: icuCase.value,
36744      nodes: [].concat(...visitAll(this, icuCase.expression))
36745    };
36746  }
36747  visitComment(comment, context) {}
36748  visitAttribute(attribute, context) {}
36749  visitBlock(block, context) {}
36750  visitBlockParameter(parameter, context) {}
36751  _addError(node, message) {
36752    this._errors.push(new I18nError(node.sourceSpan, message));
36753  }
36754}
36755function getTypeForTag(tag) {
36756  switch (tag.toLowerCase()) {
36757    case 'br':
36758    case 'b':
36759    case 'i':
36760    case 'u':
36761      return 'fmt';
36762    case 'img':
36763      return 'image';
36764    case 'a':
36765      return 'link';
36766    default:
36767      return 'other';
36768  }
36769}
36770const _TRANSLATIONS_TAG = 'translationbundle';
36771const _TRANSLATION_TAG = 'translation';
36772const _PLACEHOLDER_TAG = 'ph';
36773class Xtb extends Serializer {
36774  write(messages, locale) {
36775    throw new Error('Unsupported');
36776  }
36777  load(content, url) {
36778    // xtb to xml nodes
36779    const xtbParser = new XtbParser();
36780    const {
36781      locale,
36782      msgIdToHtml,
36783      errors
36784    } = xtbParser.parse(content, url);
36785    // xml nodes to i18n nodes
36786    const i18nNodesByMsgId = {};
36787    const converter = new XmlToI18n();
36788    // Because we should be able to load xtb files that rely on features not supported by angular,
36789    // we need to delay the conversion of html to i18n nodes so that non angular messages are not
36790    // converted
36791    Object.keys(msgIdToHtml).forEach(msgId => {
36792      const valueFn = function () {
36793        const {
36794          i18nNodes,
36795          errors
36796        } = converter.convert(msgIdToHtml[msgId], url);
36797        if (errors.length) {
36798          throw new Error(`xtb parse errors:\n${errors.join('\n')}`);
36799        }
36800        return i18nNodes;
36801      };
36802      createLazyProperty(i18nNodesByMsgId, msgId, valueFn);
36803    });
36804    if (errors.length) {
36805      throw new Error(`xtb parse errors:\n${errors.join('\n')}`);
36806    }
36807    return {
36808      locale: locale,
36809      i18nNodesByMsgId
36810    };
36811  }
36812  digest(message) {
36813    return digest(message);
36814  }
36815  createNameMapper(message) {
36816    return new SimplePlaceholderMapper(message, toPublicName);
36817  }
36818}
36819function createLazyProperty(messages, id, valueFn) {
36820  Object.defineProperty(messages, id, {
36821    configurable: true,
36822    enumerable: true,
36823    get: function () {
36824      const value = valueFn();
36825      Object.defineProperty(messages, id, {
36826        enumerable: true,
36827        value
36828      });
36829      return value;
36830    },
36831    set: _ => {
36832      throw new Error('Could not overwrite an XTB translation');
36833    }
36834  });
36835}
36836// Extract messages as xml nodes from the xtb file
36837class XtbParser {
36838  constructor() {
36839    this._locale = null;
36840  }
36841  parse(xtb, url) {
36842    this._bundleDepth = 0;
36843    this._msgIdToHtml = {};
36844    // We can not parse the ICU messages at this point as some messages might not originate
36845    // from Angular that could not be lex'd.
36846    const xml = new XmlParser().parse(xtb, url);
36847    this._errors = xml.errors;
36848    visitAll(this, xml.rootNodes);
36849    return {
36850      msgIdToHtml: this._msgIdToHtml,
36851      errors: this._errors,
36852      locale: this._locale
36853    };
36854  }
36855  visitElement(element, context) {
36856    switch (element.name) {
36857      case _TRANSLATIONS_TAG:
36858        this._bundleDepth++;
36859        if (this._bundleDepth > 1) {
36860          this._addError(element, `<${_TRANSLATIONS_TAG}> elements can not be nested`);
36861        }
36862        const langAttr = element.attrs.find(attr => attr.name === 'lang');
36863        if (langAttr) {
36864          this._locale = langAttr.value;
36865        }
36866        visitAll(this, element.children, null);
36867        this._bundleDepth--;
36868        break;
36869      case _TRANSLATION_TAG:
36870        const idAttr = element.attrs.find(attr => attr.name === 'id');
36871        if (!idAttr) {
36872          this._addError(element, `<${_TRANSLATION_TAG}> misses the "id" attribute`);
36873        } else {
36874          const id = idAttr.value;
36875          if (this._msgIdToHtml.hasOwnProperty(id)) {
36876            this._addError(element, `Duplicated translations for msg ${id}`);
36877          } else {
36878            const innerTextStart = element.startSourceSpan.end.offset;
36879            const innerTextEnd = element.endSourceSpan.start.offset;
36880            const content = element.startSourceSpan.start.file.content;
36881            const innerText = content.slice(innerTextStart, innerTextEnd);
36882            this._msgIdToHtml[id] = innerText;
36883          }
36884        }
36885        break;
36886      default:
36887        this._addError(element, 'Unexpected tag');
36888    }
36889  }
36890  visitAttribute(attribute, context) {}
36891  visitText(text, context) {}
36892  visitComment(comment, context) {}
36893  visitExpansion(expansion, context) {}
36894  visitExpansionCase(expansionCase, context) {}
36895  visitBlock(block, context) {}
36896  visitBlockParameter(block, context) {}
36897  _addError(node, message) {
36898    this._errors.push(new I18nError(node.sourceSpan, message));
36899  }
36900}
36901// Convert ml nodes (xtb syntax) to i18n nodes
36902class XmlToI18n {
36903  convert(message, url) {
36904    const xmlIcu = new XmlParser().parse(message, url, {
36905      tokenizeExpansionForms: true
36906    });
36907    this._errors = xmlIcu.errors;
36908    const i18nNodes = this._errors.length > 0 || xmlIcu.rootNodes.length == 0 ? [] : visitAll(this, xmlIcu.rootNodes);
36909    return {
36910      i18nNodes,
36911      errors: this._errors
36912    };
36913  }
36914  visitText(text, context) {
36915    return new Text$2(text.value, text.sourceSpan);
36916  }
36917  visitExpansion(icu, context) {
36918    const caseMap = {};
36919    visitAll(this, icu.cases).forEach(c => {
36920      caseMap[c.value] = new Container(c.nodes, icu.sourceSpan);
36921    });
36922    return new Icu(icu.switchValue, icu.type, caseMap, icu.sourceSpan);
36923  }
36924  visitExpansionCase(icuCase, context) {
36925    return {
36926      value: icuCase.value,
36927      nodes: visitAll(this, icuCase.expression)
36928    };
36929  }
36930  visitElement(el, context) {
36931    if (el.name === _PLACEHOLDER_TAG) {
36932      const nameAttr = el.attrs.find(attr => attr.name === 'name');
36933      if (nameAttr) {
36934        return new Placeholder('', nameAttr.value, el.sourceSpan);
36935      }
36936      this._addError(el, `<${_PLACEHOLDER_TAG}> misses the "name" attribute`);
36937    } else {
36938      this._addError(el, `Unexpected tag`);
36939    }
36940    return null;
36941  }
36942  visitComment(comment, context) {}
36943  visitAttribute(attribute, context) {}
36944  visitBlock(block, context) {}
36945  visitBlockParameter(block, context) {}
36946  _addError(node, message) {
36947    this._errors.push(new I18nError(node.sourceSpan, message));
36948  }
36949}
36950
36951/**
36952 * A container for translated messages
36953 */
36954class TranslationBundle {
36955  constructor(_i18nNodesByMsgId = {}, locale, digest, mapperFactory, missingTranslationStrategy = MissingTranslationStrategy.Warning, console) {
36956    this._i18nNodesByMsgId = _i18nNodesByMsgId;
36957    this.digest = digest;
36958    this.mapperFactory = mapperFactory;
36959    this._i18nToHtml = new I18nToHtmlVisitor(_i18nNodesByMsgId, locale, digest, mapperFactory, missingTranslationStrategy, console);
36960  }
36961  // Creates a `TranslationBundle` by parsing the given `content` with the `serializer`.
36962  static load(content, url, serializer, missingTranslationStrategy, console) {
36963    const {
36964      locale,
36965      i18nNodesByMsgId
36966    } = serializer.load(content, url);
36967    const digestFn = m => serializer.digest(m);
36968    const mapperFactory = m => serializer.createNameMapper(m);
36969    return new TranslationBundle(i18nNodesByMsgId, locale, digestFn, mapperFactory, missingTranslationStrategy, console);
36970  }
36971  // Returns the translation as HTML nodes from the given source message.
36972  get(srcMsg) {
36973    const html = this._i18nToHtml.convert(srcMsg);
36974    if (html.errors.length) {
36975      throw new Error(html.errors.join('\n'));
36976    }
36977    return html.nodes;
36978  }
36979  has(srcMsg) {
36980    return this.digest(srcMsg) in this._i18nNodesByMsgId;
36981  }
36982}
36983class I18nToHtmlVisitor {
36984  constructor(_i18nNodesByMsgId = {}, _locale, _digest, _mapperFactory, _missingTranslationStrategy, _console) {
36985    this._i18nNodesByMsgId = _i18nNodesByMsgId;
36986    this._locale = _locale;
36987    this._digest = _digest;
36988    this._mapperFactory = _mapperFactory;
36989    this._missingTranslationStrategy = _missingTranslationStrategy;
36990    this._console = _console;
36991    this._errors = [];
36992    this._contextStack = [];
36993  }
36994  convert(srcMsg) {
36995    this._contextStack.length = 0;
36996    this._errors.length = 0;
36997    // i18n to text
36998    const text = this._convertToText(srcMsg);
36999    // text to html
37000    const url = srcMsg.nodes[0].sourceSpan.start.file.url;
37001    const html = new HtmlParser().parse(text, url, {
37002      tokenizeExpansionForms: true
37003    });
37004    return {
37005      nodes: html.rootNodes,
37006      errors: [...this._errors, ...html.errors]
37007    };
37008  }
37009  visitText(text, context) {
37010    // `convert()` uses an `HtmlParser` to return `html.Node`s
37011    // we should then make sure that any special characters are escaped
37012    return escapeXml(text.value);
37013  }
37014  visitContainer(container, context) {
37015    return container.children.map(n => n.visit(this)).join('');
37016  }
37017  visitIcu(icu, context) {
37018    const cases = Object.keys(icu.cases).map(k => `${k} {${icu.cases[k].visit(this)}}`);
37019    // TODO(vicb): Once all format switch to using expression placeholders
37020    // we should throw when the placeholder is not in the source message
37021    const exp = this._srcMsg.placeholders.hasOwnProperty(icu.expression) ? this._srcMsg.placeholders[icu.expression].text : icu.expression;
37022    return `{${exp}, ${icu.type}, ${cases.join(' ')}}`;
37023  }
37024  visitPlaceholder(ph, context) {
37025    const phName = this._mapper(ph.name);
37026    if (this._srcMsg.placeholders.hasOwnProperty(phName)) {
37027      return this._srcMsg.placeholders[phName].text;
37028    }
37029    if (this._srcMsg.placeholderToMessage.hasOwnProperty(phName)) {
37030      return this._convertToText(this._srcMsg.placeholderToMessage[phName]);
37031    }
37032    this._addError(ph, `Unknown placeholder "${ph.name}"`);
37033    return '';
37034  }
37035  // Loaded message contains only placeholders (vs tag and icu placeholders).
37036  // However when a translation can not be found, we need to serialize the source message
37037  // which can contain tag placeholders
37038  visitTagPlaceholder(ph, context) {
37039    const tag = `${ph.tag}`;
37040    const attrs = Object.keys(ph.attrs).map(name => `${name}="${ph.attrs[name]}"`).join(' ');
37041    if (ph.isVoid) {
37042      return `<${tag} ${attrs}/>`;
37043    }
37044    const children = ph.children.map(c => c.visit(this)).join('');
37045    return `<${tag} ${attrs}>${children}</${tag}>`;
37046  }
37047  // Loaded message contains only placeholders (vs tag and icu placeholders).
37048  // However when a translation can not be found, we need to serialize the source message
37049  // which can contain tag placeholders
37050  visitIcuPlaceholder(ph, context) {
37051    // An ICU placeholder references the source message to be serialized
37052    return this._convertToText(this._srcMsg.placeholderToMessage[ph.name]);
37053  }
37054  visitBlockPlaceholder(ph, context) {
37055    const params = ph.parameters.length === 0 ? '' : ` (${ph.parameters.join('; ')})`;
37056    const children = ph.children.map(c => c.visit(this)).join('');
37057    return `@${ph.name}${params} {${children}}`;
37058  }
37059  /**
37060   * Convert a source message to a translated text string:
37061   * - text nodes are replaced with their translation,
37062   * - placeholders are replaced with their content,
37063   * - ICU nodes are converted to ICU expressions.
37064   */
37065  _convertToText(srcMsg) {
37066    const id = this._digest(srcMsg);
37067    const mapper = this._mapperFactory ? this._mapperFactory(srcMsg) : null;
37068    let nodes;
37069    this._contextStack.push({
37070      msg: this._srcMsg,
37071      mapper: this._mapper
37072    });
37073    this._srcMsg = srcMsg;
37074    if (this._i18nNodesByMsgId.hasOwnProperty(id)) {
37075      // When there is a translation use its nodes as the source
37076      // And create a mapper to convert serialized placeholder names to internal names
37077      nodes = this._i18nNodesByMsgId[id];
37078      this._mapper = name => mapper ? mapper.toInternalName(name) : name;
37079    } else {
37080      // When no translation has been found
37081      // - report an error / a warning / nothing,
37082      // - use the nodes from the original message
37083      // - placeholders are already internal and need no mapper
37084      if (this._missingTranslationStrategy === MissingTranslationStrategy.Error) {
37085        const ctx = this._locale ? ` for locale "${this._locale}"` : '';
37086        this._addError(srcMsg.nodes[0], `Missing translation for message "${id}"${ctx}`);
37087      } else if (this._console && this._missingTranslationStrategy === MissingTranslationStrategy.Warning) {
37088        const ctx = this._locale ? ` for locale "${this._locale}"` : '';
37089        this._console.warn(`Missing translation for message "${id}"${ctx}`);
37090      }
37091      nodes = srcMsg.nodes;
37092      this._mapper = name => name;
37093    }
37094    const text = nodes.map(node => node.visit(this)).join('');
37095    const context = this._contextStack.pop();
37096    this._srcMsg = context.msg;
37097    this._mapper = context.mapper;
37098    return text;
37099  }
37100  _addError(el, msg) {
37101    this._errors.push(new I18nError(el.sourceSpan, msg));
37102  }
37103}
37104class I18NHtmlParser {
37105  constructor(_htmlParser, translations, translationsFormat, missingTranslation = MissingTranslationStrategy.Warning, console) {
37106    this._htmlParser = _htmlParser;
37107    if (translations) {
37108      const serializer = createSerializer(translationsFormat);
37109      this._translationBundle = TranslationBundle.load(translations, 'i18n', serializer, missingTranslation, console);
37110    } else {
37111      this._translationBundle = new TranslationBundle({}, null, digest$1, undefined, missingTranslation, console);
37112    }
37113  }
37114  parse(source, url, options = {}) {
37115    const interpolationConfig = options.interpolationConfig || DEFAULT_INTERPOLATION_CONFIG;
37116    const parseResult = this._htmlParser.parse(source, url, {
37117      interpolationConfig,
37118      ...options
37119    });
37120    if (parseResult.errors.length) {
37121      return new ParseTreeResult(parseResult.rootNodes, parseResult.errors);
37122    }
37123    return mergeTranslations(parseResult.rootNodes, this._translationBundle, interpolationConfig, [], {});
37124  }
37125}
37126function createSerializer(format) {
37127  format = (format || 'xlf').toLowerCase();
37128  switch (format) {
37129    case 'xmb':
37130      return new Xmb();
37131    case 'xtb':
37132      return new Xtb();
37133    case 'xliff2':
37134    case 'xlf2':
37135      return new Xliff2();
37136    case 'xliff':
37137    case 'xlf':
37138    default:
37139      return new Xliff();
37140  }
37141}
37142
37143/**
37144 * A container for message extracted from the templates.
37145 */
37146class MessageBundle {
37147  constructor(_htmlParser, _implicitTags, _implicitAttrs, _locale = null) {
37148    this._htmlParser = _htmlParser;
37149    this._implicitTags = _implicitTags;
37150    this._implicitAttrs = _implicitAttrs;
37151    this._locale = _locale;
37152    this._messages = [];
37153  }
37154  updateFromTemplate(html, url, interpolationConfig) {
37155    const htmlParserResult = this._htmlParser.parse(html, url, {
37156      tokenizeExpansionForms: true,
37157      interpolationConfig
37158    });
37159    if (htmlParserResult.errors.length) {
37160      return htmlParserResult.errors;
37161    }
37162    const i18nParserResult = extractMessages(htmlParserResult.rootNodes, interpolationConfig, this._implicitTags, this._implicitAttrs);
37163    if (i18nParserResult.errors.length) {
37164      return i18nParserResult.errors;
37165    }
37166    this._messages.push(...i18nParserResult.messages);
37167    return [];
37168  }
37169  // Return the message in the internal format
37170  // The public (serialized) format might be different, see the `write` method.
37171  getMessages() {
37172    return this._messages;
37173  }
37174  write(serializer, filterSources) {
37175    const messages = {};
37176    const mapperVisitor = new MapPlaceholderNames();
37177    // Deduplicate messages based on their ID
37178    this._messages.forEach(message => {
37179      const id = serializer.digest(message);
37180      if (!messages.hasOwnProperty(id)) {
37181        messages[id] = message;
37182      } else {
37183        messages[id].sources.push(...message.sources);
37184      }
37185    });
37186    // Transform placeholder names using the serializer mapping
37187    const msgList = Object.keys(messages).map(id => {
37188      const mapper = serializer.createNameMapper(messages[id]);
37189      const src = messages[id];
37190      const nodes = mapper ? mapperVisitor.convert(src.nodes, mapper) : src.nodes;
37191      let transformedMessage = new Message(nodes, {}, {}, src.meaning, src.description, id);
37192      transformedMessage.sources = src.sources;
37193      if (filterSources) {
37194        transformedMessage.sources.forEach(source => source.filePath = filterSources(source.filePath));
37195      }
37196      return transformedMessage;
37197    });
37198    return serializer.write(msgList, this._locale);
37199  }
37200}
37201// Transform an i18n AST by renaming the placeholder nodes with the given mapper
37202class MapPlaceholderNames extends CloneVisitor {
37203  convert(nodes, mapper) {
37204    return mapper ? nodes.map(n => n.visit(this, mapper)) : nodes;
37205  }
37206  visitTagPlaceholder(ph, mapper) {
37207    const startName = mapper.toPublicName(ph.startName);
37208    const closeName = ph.closeName ? mapper.toPublicName(ph.closeName) : ph.closeName;
37209    const children = ph.children.map(n => n.visit(this, mapper));
37210    return new TagPlaceholder(ph.tag, ph.attrs, startName, closeName, children, ph.isVoid, ph.sourceSpan, ph.startSourceSpan, ph.endSourceSpan);
37211  }
37212  visitBlockPlaceholder(ph, mapper) {
37213    const startName = mapper.toPublicName(ph.startName);
37214    const closeName = ph.closeName ? mapper.toPublicName(ph.closeName) : ph.closeName;
37215    const children = ph.children.map(n => n.visit(this, mapper));
37216    return new BlockPlaceholder(ph.name, ph.parameters, startName, closeName, children, ph.sourceSpan, ph.startSourceSpan, ph.endSourceSpan);
37217  }
37218  visitPlaceholder(ph, mapper) {
37219    return new Placeholder(ph.value, mapper.toPublicName(ph.name), ph.sourceSpan);
37220  }
37221  visitIcuPlaceholder(ph, mapper) {
37222    return new IcuPlaceholder(ph.value, mapper.toPublicName(ph.name), ph.sourceSpan);
37223  }
37224}
37225var FactoryTarget;
37226(function (FactoryTarget) {
37227  FactoryTarget[FactoryTarget["Directive"] = 0] = "Directive";
37228  FactoryTarget[FactoryTarget["Component"] = 1] = "Component";
37229  FactoryTarget[FactoryTarget["Injectable"] = 2] = "Injectable";
37230  FactoryTarget[FactoryTarget["Pipe"] = 3] = "Pipe";
37231  FactoryTarget[FactoryTarget["NgModule"] = 4] = "NgModule";
37232})(FactoryTarget || (FactoryTarget = {}));
37233function compileClassMetadata(metadata) {
37234  // Generate an ngDevMode guarded call to setClassMetadata with the class identifier and its
37235  // metadata.
37236  const fnCall = importExpr(Identifiers.setClassMetadata).callFn([metadata.type, metadata.decorators, metadata.ctorParameters ?? literal(null), metadata.propDecorators ?? literal(null)]);
37237  const iife = arrowFn([], [devOnlyGuardedExpression(fnCall).toStmt()]);
37238  return iife.callFn([]);
37239}
37240/**
37241 * Wraps the `setClassMetadata` function with extra logic that dynamically
37242 * loads dependencies from `@defer` blocks.
37243 *
37244 * Generates a call like this:
37245 * ```
37246 * setClassMetadataAsync(type, () => [
37247 *   import('./cmp-a').then(m => m.CmpA);
37248 *   import('./cmp-b').then(m => m.CmpB);
37249 * ], (CmpA, CmpB) => {
37250 *   setClassMetadata(type, decorators, ctorParameters, propParameters);
37251 * });
37252 * ```
37253 *
37254 * Similar to the `setClassMetadata` call, it's wrapped into the `ngDevMode`
37255 * check to tree-shake away this code in production mode.
37256 */
37257function compileComponentClassMetadata(metadata, deferrableTypes) {
37258  if (deferrableTypes === null || deferrableTypes.size === 0) {
37259    // If there are no deferrable symbols - just generate a regular `setClassMetadata` call.
37260    return compileClassMetadata(metadata);
37261  }
37262  const dynamicImports = [];
37263  const importedSymbols = [];
37264  for (const [symbolName, {
37265    importPath,
37266    isDefaultImport
37267  }] of deferrableTypes) {
37268    // e.g. `(m) => m.CmpA`
37269    const innerFn =
37270    // Default imports are always accessed through the `default` property.
37271    arrowFn([new FnParam('m', DYNAMIC_TYPE)], variable('m').prop(isDefaultImport ? 'default' : symbolName));
37272    // e.g. `import('./cmp-a').then(...)`
37273    const importExpr = new DynamicImportExpr(importPath).prop('then').callFn([innerFn]);
37274    dynamicImports.push(importExpr);
37275    importedSymbols.push(new FnParam(symbolName, DYNAMIC_TYPE));
37276  }
37277  // e.g. `() => [ ... ];`
37278  const dependencyLoadingFn = arrowFn([], literalArr(dynamicImports));
37279  // e.g. `setClassMetadata(...)`
37280  const setClassMetadataCall = importExpr(Identifiers.setClassMetadata).callFn([metadata.type, metadata.decorators, metadata.ctorParameters ?? literal(null), metadata.propDecorators ?? literal(null)]);
37281  // e.g. `(CmpA) => setClassMetadata(...)`
37282  const setClassMetaWrapper = arrowFn(importedSymbols, [setClassMetadataCall.toStmt()]);
37283  // Final `setClassMetadataAsync()` call with all arguments
37284  const setClassMetaAsync = importExpr(Identifiers.setClassMetadataAsync).callFn([metadata.type, dependencyLoadingFn, setClassMetaWrapper]);
37285  // Generate an ngDevMode guarded call to `setClassMetadataAsync` with
37286  // the class identifier and its metadata, so that this call can be tree-shaken.
37287  const iife = arrowFn([], [devOnlyGuardedExpression(setClassMetaAsync).toStmt()]);
37288  return iife.callFn([]);
37289}
37290
37291/**
37292 * Generate an ngDevMode guarded call to setClassDebugInfo with the debug info about the class
37293 * (e.g., the file name in which the class is defined)
37294 */
37295function compileClassDebugInfo(debugInfo) {
37296  const debugInfoObject = {
37297    className: debugInfo.className
37298  };
37299  // Include file path and line number only if the file relative path is calculated successfully.
37300  if (debugInfo.filePath) {
37301    debugInfoObject.filePath = debugInfo.filePath;
37302    debugInfoObject.lineNumber = debugInfo.lineNumber;
37303  }
37304  // Include forbidOrphanRendering only if it's set to true (to reduce generated code)
37305  if (debugInfo.forbidOrphanRendering) {
37306    debugInfoObject.forbidOrphanRendering = literal(true);
37307  }
37308  const fnCall = importExpr(Identifiers.setClassDebugInfo).callFn([debugInfo.type, mapLiteral(debugInfoObject)]);
37309  const iife = arrowFn([], [devOnlyGuardedExpression(fnCall).toStmt()]);
37310  return iife.callFn([]);
37311}
37312
37313/**
37314 * Every time we make a breaking change to the declaration interface or partial-linker behavior, we
37315 * must update this constant to prevent old partial-linkers from incorrectly processing the
37316 * declaration.
37317 *
37318 * Do not include any prerelease in these versions as they are ignored.
37319 */
37320const MINIMUM_PARTIAL_LINKER_VERSION$5 = '12.0.0';
37321function compileDeclareClassMetadata(metadata) {
37322  const definitionMap = new DefinitionMap();
37323  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$5));
37324  definitionMap.set('version', literal('17.3.9'));
37325  definitionMap.set('ngImport', importExpr(Identifiers.core));
37326  definitionMap.set('type', metadata.type);
37327  definitionMap.set('decorators', metadata.decorators);
37328  definitionMap.set('ctorParameters', metadata.ctorParameters);
37329  definitionMap.set('propDecorators', metadata.propDecorators);
37330  return importExpr(Identifiers.declareClassMetadata).callFn([definitionMap.toLiteralMap()]);
37331}
37332
37333/**
37334 * Creates an array literal expression from the given array, mapping all values to an expression
37335 * using the provided mapping function. If the array is empty or null, then null is returned.
37336 *
37337 * @param values The array to transfer into literal array expression.
37338 * @param mapper The logic to use for creating an expression for the array's values.
37339 * @returns An array literal expression representing `values`, or null if `values` is empty or
37340 * is itself null.
37341 */
37342function toOptionalLiteralArray(values, mapper) {
37343  if (values === null || values.length === 0) {
37344    return null;
37345  }
37346  return literalArr(values.map(value => mapper(value)));
37347}
37348/**
37349 * Creates an object literal expression from the given object, mapping all values to an expression
37350 * using the provided mapping function. If the object has no keys, then null is returned.
37351 *
37352 * @param object The object to transfer into an object literal expression.
37353 * @param mapper The logic to use for creating an expression for the object's values.
37354 * @returns An object literal expression representing `object`, or null if `object` does not have
37355 * any keys.
37356 */
37357function toOptionalLiteralMap(object, mapper) {
37358  const entries = Object.keys(object).map(key => {
37359    const value = object[key];
37360    return {
37361      key,
37362      value: mapper(value),
37363      quoted: true
37364    };
37365  });
37366  if (entries.length > 0) {
37367    return literalMap(entries);
37368  } else {
37369    return null;
37370  }
37371}
37372function compileDependencies(deps) {
37373  if (deps === 'invalid') {
37374    // The `deps` can be set to the string "invalid"  by the `unwrapConstructorDependencies()`
37375    // function, which tries to convert `ConstructorDeps` into `R3DependencyMetadata[]`.
37376    return literal('invalid');
37377  } else if (deps === null) {
37378    return literal(null);
37379  } else {
37380    return literalArr(deps.map(compileDependency));
37381  }
37382}
37383function compileDependency(dep) {
37384  const depMeta = new DefinitionMap();
37385  depMeta.set('token', dep.token);
37386  if (dep.attributeNameType !== null) {
37387    depMeta.set('attribute', literal(true));
37388  }
37389  if (dep.host) {
37390    depMeta.set('host', literal(true));
37391  }
37392  if (dep.optional) {
37393    depMeta.set('optional', literal(true));
37394  }
37395  if (dep.self) {
37396    depMeta.set('self', literal(true));
37397  }
37398  if (dep.skipSelf) {
37399    depMeta.set('skipSelf', literal(true));
37400  }
37401  return depMeta.toLiteralMap();
37402}
37403
37404/**
37405 * Compile a directive declaration defined by the `R3DirectiveMetadata`.
37406 */
37407function compileDeclareDirectiveFromMetadata(meta) {
37408  const definitionMap = createDirectiveDefinitionMap(meta);
37409  const expression = importExpr(Identifiers.declareDirective).callFn([definitionMap.toLiteralMap()]);
37410  const type = createDirectiveType(meta);
37411  return {
37412    expression,
37413    type,
37414    statements: []
37415  };
37416}
37417/**
37418 * Gathers the declaration fields for a directive into a `DefinitionMap`. This allows for reusing
37419 * this logic for components, as they extend the directive metadata.
37420 */
37421function createDirectiveDefinitionMap(meta) {
37422  const definitionMap = new DefinitionMap();
37423  const minVersion = getMinimumVersionForPartialOutput(meta);
37424  definitionMap.set('minVersion', literal(minVersion));
37425  definitionMap.set('version', literal('17.3.9'));
37426  // e.g. `type: MyDirective`
37427  definitionMap.set('type', meta.type.value);
37428  if (meta.isStandalone) {
37429    definitionMap.set('isStandalone', literal(meta.isStandalone));
37430  }
37431  if (meta.isSignal) {
37432    definitionMap.set('isSignal', literal(meta.isSignal));
37433  }
37434  // e.g. `selector: 'some-dir'`
37435  if (meta.selector !== null) {
37436    definitionMap.set('selector', literal(meta.selector));
37437  }
37438  definitionMap.set('inputs', needsNewInputPartialOutput(meta) ? createInputsPartialMetadata(meta.inputs) : legacyInputsPartialMetadata(meta.inputs));
37439  definitionMap.set('outputs', conditionallyCreateDirectiveBindingLiteral(meta.outputs));
37440  definitionMap.set('host', compileHostMetadata(meta.host));
37441  definitionMap.set('providers', meta.providers);
37442  if (meta.queries.length > 0) {
37443    definitionMap.set('queries', literalArr(meta.queries.map(compileQuery)));
37444  }
37445  if (meta.viewQueries.length > 0) {
37446    definitionMap.set('viewQueries', literalArr(meta.viewQueries.map(compileQuery)));
37447  }
37448  if (meta.exportAs !== null) {
37449    definitionMap.set('exportAs', asLiteral(meta.exportAs));
37450  }
37451  if (meta.usesInheritance) {
37452    definitionMap.set('usesInheritance', literal(true));
37453  }
37454  if (meta.lifecycle.usesOnChanges) {
37455    definitionMap.set('usesOnChanges', literal(true));
37456  }
37457  if (meta.hostDirectives?.length) {
37458    definitionMap.set('hostDirectives', createHostDirectives(meta.hostDirectives));
37459  }
37460  definitionMap.set('ngImport', importExpr(Identifiers.core));
37461  return definitionMap;
37462}
37463/**
37464 * Determines the minimum linker version for the partial output
37465 * generated for this directive.
37466 *
37467 * Every time we make a breaking change to the declaration interface or partial-linker
37468 * behavior, we must update the minimum versions to prevent old partial-linkers from
37469 * incorrectly processing the declaration.
37470 *
37471 * NOTE: Do not include any prerelease in these versions as they are ignored.
37472 */
37473function getMinimumVersionForPartialOutput(meta) {
37474  // We are starting with the oldest minimum version that can work for common
37475  // directive partial compilation output. As we discover usages of new features
37476  // that require a newer partial output emit, we bump the `minVersion`. Our goal
37477  // is to keep libraries as much compatible with older linker versions as possible.
37478  let minVersion = '14.0.0';
37479  // Note: in order to allow consuming Angular libraries that have been compiled with 16.1+ in
37480  // Angular 16.0, we only force a minimum version of 16.1 if input transform feature as introduced
37481  // in 16.1 is actually used.
37482  const hasDecoratorTransformFunctions = Object.values(meta.inputs).some(input => input.transformFunction !== null);
37483  if (hasDecoratorTransformFunctions) {
37484    minVersion = '16.1.0';
37485  }
37486  // If there are input flags and we need the new emit, use the actual minimum version,
37487  // where this was introduced. i.e. in 17.1.0
37488  // TODO(legacy-partial-output-inputs): Remove in v18.
37489  if (needsNewInputPartialOutput(meta)) {
37490    minVersion = '17.1.0';
37491  }
37492  // If there are signal-based queries, partial output generates an extra field
37493  // that should be parsed by linkers. Ensure a proper minimum linker version.
37494  if (meta.queries.some(q => q.isSignal) || meta.viewQueries.some(q => q.isSignal)) {
37495    minVersion = '17.2.0';
37496  }
37497  return minVersion;
37498}
37499/**
37500 * Gets whether the given directive needs the new input partial output structure
37501 * that can hold additional metadata like `isRequired`, `isSignal` etc.
37502 */
37503function needsNewInputPartialOutput(meta) {
37504  return Object.values(meta.inputs).some(input => input.isSignal);
37505}
37506/**
37507 * Compiles the metadata of a single query into its partial declaration form as declared
37508 * by `R3DeclareQueryMetadata`.
37509 */
37510function compileQuery(query) {
37511  const meta = new DefinitionMap();
37512  meta.set('propertyName', literal(query.propertyName));
37513  if (query.first) {
37514    meta.set('first', literal(true));
37515  }
37516  meta.set('predicate', Array.isArray(query.predicate) ? asLiteral(query.predicate) : convertFromMaybeForwardRefExpression(query.predicate));
37517  if (!query.emitDistinctChangesOnly) {
37518    // `emitDistinctChangesOnly` is special because we expect it to be `true`.
37519    // Therefore we explicitly emit the field, and explicitly place it only when it's `false`.
37520    meta.set('emitDistinctChangesOnly', literal(false));
37521  } else {
37522    // The linker will assume that an absent `emitDistinctChangesOnly` flag is by default `true`.
37523  }
37524  if (query.descendants) {
37525    meta.set('descendants', literal(true));
37526  }
37527  meta.set('read', query.read);
37528  if (query.static) {
37529    meta.set('static', literal(true));
37530  }
37531  if (query.isSignal) {
37532    meta.set('isSignal', literal(true));
37533  }
37534  return meta.toLiteralMap();
37535}
37536/**
37537 * Compiles the host metadata into its partial declaration form as declared
37538 * in `R3DeclareDirectiveMetadata['host']`
37539 */
37540function compileHostMetadata(meta) {
37541  const hostMetadata = new DefinitionMap();
37542  hostMetadata.set('attributes', toOptionalLiteralMap(meta.attributes, expression => expression));
37543  hostMetadata.set('listeners', toOptionalLiteralMap(meta.listeners, literal));
37544  hostMetadata.set('properties', toOptionalLiteralMap(meta.properties, literal));
37545  if (meta.specialAttributes.styleAttr) {
37546    hostMetadata.set('styleAttribute', literal(meta.specialAttributes.styleAttr));
37547  }
37548  if (meta.specialAttributes.classAttr) {
37549    hostMetadata.set('classAttribute', literal(meta.specialAttributes.classAttr));
37550  }
37551  if (hostMetadata.values.length > 0) {
37552    return hostMetadata.toLiteralMap();
37553  } else {
37554    return null;
37555  }
37556}
37557function createHostDirectives(hostDirectives) {
37558  const expressions = hostDirectives.map(current => {
37559    const keys = [{
37560      key: 'directive',
37561      value: current.isForwardReference ? generateForwardRef(current.directive.type) : current.directive.type,
37562      quoted: false
37563    }];
37564    const inputsLiteral = current.inputs ? createHostDirectivesMappingArray(current.inputs) : null;
37565    const outputsLiteral = current.outputs ? createHostDirectivesMappingArray(current.outputs) : null;
37566    if (inputsLiteral) {
37567      keys.push({
37568        key: 'inputs',
37569        value: inputsLiteral,
37570        quoted: false
37571      });
37572    }
37573    if (outputsLiteral) {
37574      keys.push({
37575        key: 'outputs',
37576        value: outputsLiteral,
37577        quoted: false
37578      });
37579    }
37580    return literalMap(keys);
37581  });
37582  // If there's a forward reference, we generate a `function() { return [{directive: HostDir}] }`,
37583  // otherwise we can save some bytes by using a plain array, e.g. `[{directive: HostDir}]`.
37584  return literalArr(expressions);
37585}
37586/**
37587 * Generates partial output metadata for inputs of a directive.
37588 *
37589 * The generated structure is expected to match `R3DeclareDirectiveFacade['inputs']`.
37590 */
37591function createInputsPartialMetadata(inputs) {
37592  const keys = Object.getOwnPropertyNames(inputs);
37593  if (keys.length === 0) {
37594    return null;
37595  }
37596  return literalMap(keys.map(declaredName => {
37597    const value = inputs[declaredName];
37598    return {
37599      key: declaredName,
37600      // put quotes around keys that contain potentially unsafe characters
37601      quoted: UNSAFE_OBJECT_KEY_NAME_REGEXP.test(declaredName),
37602      value: literalMap([{
37603        key: 'classPropertyName',
37604        quoted: false,
37605        value: asLiteral(value.classPropertyName)
37606      }, {
37607        key: 'publicName',
37608        quoted: false,
37609        value: asLiteral(value.bindingPropertyName)
37610      }, {
37611        key: 'isSignal',
37612        quoted: false,
37613        value: asLiteral(value.isSignal)
37614      }, {
37615        key: 'isRequired',
37616        quoted: false,
37617        value: asLiteral(value.required)
37618      }, {
37619        key: 'transformFunction',
37620        quoted: false,
37621        value: value.transformFunction ?? NULL_EXPR
37622      }])
37623    };
37624  }));
37625}
37626/**
37627 * Pre v18 legacy partial output for inputs.
37628 *
37629 * Previously, inputs did not capture metadata like `isSignal` in the partial compilation output.
37630 * To enable capturing such metadata, we restructured how input metadata is communicated in the
37631 * partial output. This would make libraries incompatible with older Angular FW versions where the
37632 * linker would not know how to handle this new "format". For this reason, if we know this metadata
37633 * does not need to be captured- we fall back to the old format. This is what this function
37634 * generates.
37635 *
37636 * See:
37637 * https://github.com/angular/angular/blob/d4b423690210872b5c32a322a6090beda30b05a3/packages/core/src/compiler/compiler_facade_interface.ts#L197-L199
37638 */
37639function legacyInputsPartialMetadata(inputs) {
37640  // TODO(legacy-partial-output-inputs): Remove function in v18.
37641  const keys = Object.getOwnPropertyNames(inputs);
37642  if (keys.length === 0) {
37643    return null;
37644  }
37645  return literalMap(keys.map(declaredName => {
37646    const value = inputs[declaredName];
37647    const publicName = value.bindingPropertyName;
37648    const differentDeclaringName = publicName !== declaredName;
37649    let result;
37650    if (differentDeclaringName || value.transformFunction !== null) {
37651      const values = [asLiteral(publicName), asLiteral(declaredName)];
37652      if (value.transformFunction !== null) {
37653        values.push(value.transformFunction);
37654      }
37655      result = literalArr(values);
37656    } else {
37657      result = asLiteral(publicName);
37658    }
37659    return {
37660      key: declaredName,
37661      // put quotes around keys that contain potentially unsafe characters
37662      quoted: UNSAFE_OBJECT_KEY_NAME_REGEXP.test(declaredName),
37663      value: result
37664    };
37665  }));
37666}
37667
37668/**
37669 * Compile a component declaration defined by the `R3ComponentMetadata`.
37670 */
37671function compileDeclareComponentFromMetadata(meta, template, additionalTemplateInfo) {
37672  const definitionMap = createComponentDefinitionMap(meta, template, additionalTemplateInfo);
37673  const expression = importExpr(Identifiers.declareComponent).callFn([definitionMap.toLiteralMap()]);
37674  const type = createComponentType(meta);
37675  return {
37676    expression,
37677    type,
37678    statements: []
37679  };
37680}
37681/**
37682 * Gathers the declaration fields for a component into a `DefinitionMap`.
37683 */
37684function createComponentDefinitionMap(meta, template, templateInfo) {
37685  const definitionMap = createDirectiveDefinitionMap(meta);
37686  const blockVisitor = new BlockPresenceVisitor();
37687  visitAll$1(blockVisitor, template.nodes);
37688  definitionMap.set('template', getTemplateExpression(template, templateInfo));
37689  if (templateInfo.isInline) {
37690    definitionMap.set('isInline', literal(true));
37691  }
37692  // Set the minVersion to 17.0.0 if the component is using at least one block in its template.
37693  // We don't do this for templates without blocks, in order to preserve backwards compatibility.
37694  if (blockVisitor.hasBlocks) {
37695    definitionMap.set('minVersion', literal('17.0.0'));
37696  }
37697  definitionMap.set('styles', toOptionalLiteralArray(meta.styles, literal));
37698  definitionMap.set('dependencies', compileUsedDependenciesMetadata(meta));
37699  definitionMap.set('viewProviders', meta.viewProviders);
37700  definitionMap.set('animations', meta.animations);
37701  if (meta.changeDetection !== null) {
37702    if (typeof meta.changeDetection === 'object') {
37703      throw new Error('Impossible state! Change detection flag is not resolved!');
37704    }
37705    definitionMap.set('changeDetection', importExpr(Identifiers.ChangeDetectionStrategy).prop(ChangeDetectionStrategy[meta.changeDetection]));
37706  }
37707  if (meta.encapsulation !== ViewEncapsulation.Emulated) {
37708    definitionMap.set('encapsulation', importExpr(Identifiers.ViewEncapsulation).prop(ViewEncapsulation[meta.encapsulation]));
37709  }
37710  if (meta.interpolation !== DEFAULT_INTERPOLATION_CONFIG) {
37711    definitionMap.set('interpolation', literalArr([literal(meta.interpolation.start), literal(meta.interpolation.end)]));
37712  }
37713  if (template.preserveWhitespaces === true) {
37714    definitionMap.set('preserveWhitespaces', literal(true));
37715  }
37716  return definitionMap;
37717}
37718function getTemplateExpression(template, templateInfo) {
37719  // If the template has been defined using a direct literal, we use that expression directly
37720  // without any modifications. This is ensures proper source mapping from the partially
37721  // compiled code to the source file declaring the template. Note that this does not capture
37722  // template literals referenced indirectly through an identifier.
37723  if (templateInfo.inlineTemplateLiteralExpression !== null) {
37724    return templateInfo.inlineTemplateLiteralExpression;
37725  }
37726  // If the template is defined inline but not through a literal, the template has been resolved
37727  // through static interpretation. We create a literal but cannot provide any source span. Note
37728  // that we cannot use the expression defining the template because the linker expects the template
37729  // to be defined as a literal in the declaration.
37730  if (templateInfo.isInline) {
37731    return literal(templateInfo.content, null, null);
37732  }
37733  // The template is external so we must synthesize an expression node with
37734  // the appropriate source-span.
37735  const contents = templateInfo.content;
37736  const file = new ParseSourceFile(contents, templateInfo.sourceUrl);
37737  const start = new ParseLocation(file, 0, 0, 0);
37738  const end = computeEndLocation(file, contents);
37739  const span = new ParseSourceSpan(start, end);
37740  return literal(contents, null, span);
37741}
37742function computeEndLocation(file, contents) {
37743  const length = contents.length;
37744  let lineStart = 0;
37745  let lastLineStart = 0;
37746  let line = 0;
37747  do {
37748    lineStart = contents.indexOf('\n', lastLineStart);
37749    if (lineStart !== -1) {
37750      lastLineStart = lineStart + 1;
37751      line++;
37752    }
37753  } while (lineStart !== -1);
37754  return new ParseLocation(file, length, line, length - lastLineStart);
37755}
37756function compileUsedDependenciesMetadata(meta) {
37757  const wrapType = meta.declarationListEmitMode !== 0 /* DeclarationListEmitMode.Direct */ ? generateForwardRef : expr => expr;
37758  if (meta.declarationListEmitMode === 3 /* DeclarationListEmitMode.RuntimeResolved */) {
37759    throw new Error(`Unsupported emit mode`);
37760  }
37761  return toOptionalLiteralArray(meta.declarations, decl => {
37762    switch (decl.kind) {
37763      case R3TemplateDependencyKind.Directive:
37764        const dirMeta = new DefinitionMap();
37765        dirMeta.set('kind', literal(decl.isComponent ? 'component' : 'directive'));
37766        dirMeta.set('type', wrapType(decl.type));
37767        dirMeta.set('selector', literal(decl.selector));
37768        dirMeta.set('inputs', toOptionalLiteralArray(decl.inputs, literal));
37769        dirMeta.set('outputs', toOptionalLiteralArray(decl.outputs, literal));
37770        dirMeta.set('exportAs', toOptionalLiteralArray(decl.exportAs, literal));
37771        return dirMeta.toLiteralMap();
37772      case R3TemplateDependencyKind.Pipe:
37773        const pipeMeta = new DefinitionMap();
37774        pipeMeta.set('kind', literal('pipe'));
37775        pipeMeta.set('type', wrapType(decl.type));
37776        pipeMeta.set('name', literal(decl.name));
37777        return pipeMeta.toLiteralMap();
37778      case R3TemplateDependencyKind.NgModule:
37779        const ngModuleMeta = new DefinitionMap();
37780        ngModuleMeta.set('kind', literal('ngmodule'));
37781        ngModuleMeta.set('type', wrapType(decl.type));
37782        return ngModuleMeta.toLiteralMap();
37783    }
37784  });
37785}
37786class BlockPresenceVisitor extends RecursiveVisitor$1 {
37787  constructor() {
37788    super(...arguments);
37789    this.hasBlocks = false;
37790  }
37791  visitDeferredBlock() {
37792    this.hasBlocks = true;
37793  }
37794  visitDeferredBlockPlaceholder() {
37795    this.hasBlocks = true;
37796  }
37797  visitDeferredBlockLoading() {
37798    this.hasBlocks = true;
37799  }
37800  visitDeferredBlockError() {
37801    this.hasBlocks = true;
37802  }
37803  visitIfBlock() {
37804    this.hasBlocks = true;
37805  }
37806  visitIfBlockBranch() {
37807    this.hasBlocks = true;
37808  }
37809  visitForLoopBlock() {
37810    this.hasBlocks = true;
37811  }
37812  visitForLoopBlockEmpty() {
37813    this.hasBlocks = true;
37814  }
37815  visitSwitchBlock() {
37816    this.hasBlocks = true;
37817  }
37818  visitSwitchBlockCase() {
37819    this.hasBlocks = true;
37820  }
37821}
37822
37823/**
37824 * Every time we make a breaking change to the declaration interface or partial-linker behavior, we
37825 * must update this constant to prevent old partial-linkers from incorrectly processing the
37826 * declaration.
37827 *
37828 * Do not include any prerelease in these versions as they are ignored.
37829 */
37830const MINIMUM_PARTIAL_LINKER_VERSION$4 = '12.0.0';
37831function compileDeclareFactoryFunction(meta) {
37832  const definitionMap = new DefinitionMap();
37833  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$4));
37834  definitionMap.set('version', literal('17.3.9'));
37835  definitionMap.set('ngImport', importExpr(Identifiers.core));
37836  definitionMap.set('type', meta.type.value);
37837  definitionMap.set('deps', compileDependencies(meta.deps));
37838  definitionMap.set('target', importExpr(Identifiers.FactoryTarget).prop(FactoryTarget$1[meta.target]));
37839  return {
37840    expression: importExpr(Identifiers.declareFactory).callFn([definitionMap.toLiteralMap()]),
37841    statements: [],
37842    type: createFactoryType(meta)
37843  };
37844}
37845
37846/**
37847 * Every time we make a breaking change to the declaration interface or partial-linker behavior, we
37848 * must update this constant to prevent old partial-linkers from incorrectly processing the
37849 * declaration.
37850 *
37851 * Do not include any prerelease in these versions as they are ignored.
37852 */
37853const MINIMUM_PARTIAL_LINKER_VERSION$3 = '12.0.0';
37854/**
37855 * Compile a Injectable declaration defined by the `R3InjectableMetadata`.
37856 */
37857function compileDeclareInjectableFromMetadata(meta) {
37858  const definitionMap = createInjectableDefinitionMap(meta);
37859  const expression = importExpr(Identifiers.declareInjectable).callFn([definitionMap.toLiteralMap()]);
37860  const type = createInjectableType(meta);
37861  return {
37862    expression,
37863    type,
37864    statements: []
37865  };
37866}
37867/**
37868 * Gathers the declaration fields for a Injectable into a `DefinitionMap`.
37869 */
37870function createInjectableDefinitionMap(meta) {
37871  const definitionMap = new DefinitionMap();
37872  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$3));
37873  definitionMap.set('version', literal('17.3.9'));
37874  definitionMap.set('ngImport', importExpr(Identifiers.core));
37875  definitionMap.set('type', meta.type.value);
37876  // Only generate providedIn property if it has a non-null value
37877  if (meta.providedIn !== undefined) {
37878    const providedIn = convertFromMaybeForwardRefExpression(meta.providedIn);
37879    if (providedIn.value !== null) {
37880      definitionMap.set('providedIn', providedIn);
37881    }
37882  }
37883  if (meta.useClass !== undefined) {
37884    definitionMap.set('useClass', convertFromMaybeForwardRefExpression(meta.useClass));
37885  }
37886  if (meta.useExisting !== undefined) {
37887    definitionMap.set('useExisting', convertFromMaybeForwardRefExpression(meta.useExisting));
37888  }
37889  if (meta.useValue !== undefined) {
37890    definitionMap.set('useValue', convertFromMaybeForwardRefExpression(meta.useValue));
37891  }
37892  // Factories do not contain `ForwardRef`s since any types are already wrapped in a function call
37893  // so the types will not be eagerly evaluated. Therefore we do not need to process this expression
37894  // with `convertFromProviderExpression()`.
37895  if (meta.useFactory !== undefined) {
37896    definitionMap.set('useFactory', meta.useFactory);
37897  }
37898  if (meta.deps !== undefined) {
37899    definitionMap.set('deps', literalArr(meta.deps.map(compileDependency)));
37900  }
37901  return definitionMap;
37902}
37903
37904/**
37905 * Every time we make a breaking change to the declaration interface or partial-linker behavior, we
37906 * must update this constant to prevent old partial-linkers from incorrectly processing the
37907 * declaration.
37908 *
37909 * Do not include any prerelease in these versions as they are ignored.
37910 */
37911const MINIMUM_PARTIAL_LINKER_VERSION$2 = '12.0.0';
37912function compileDeclareInjectorFromMetadata(meta) {
37913  const definitionMap = createInjectorDefinitionMap(meta);
37914  const expression = importExpr(Identifiers.declareInjector).callFn([definitionMap.toLiteralMap()]);
37915  const type = createInjectorType(meta);
37916  return {
37917    expression,
37918    type,
37919    statements: []
37920  };
37921}
37922/**
37923 * Gathers the declaration fields for an Injector into a `DefinitionMap`.
37924 */
37925function createInjectorDefinitionMap(meta) {
37926  const definitionMap = new DefinitionMap();
37927  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$2));
37928  definitionMap.set('version', literal('17.3.9'));
37929  definitionMap.set('ngImport', importExpr(Identifiers.core));
37930  definitionMap.set('type', meta.type.value);
37931  definitionMap.set('providers', meta.providers);
37932  if (meta.imports.length > 0) {
37933    definitionMap.set('imports', literalArr(meta.imports));
37934  }
37935  return definitionMap;
37936}
37937
37938/**
37939 * Every time we make a breaking change to the declaration interface or partial-linker behavior, we
37940 * must update this constant to prevent old partial-linkers from incorrectly processing the
37941 * declaration.
37942 *
37943 * Do not include any prerelease in these versions as they are ignored.
37944 */
37945const MINIMUM_PARTIAL_LINKER_VERSION$1 = '14.0.0';
37946function compileDeclareNgModuleFromMetadata(meta) {
37947  const definitionMap = createNgModuleDefinitionMap(meta);
37948  const expression = importExpr(Identifiers.declareNgModule).callFn([definitionMap.toLiteralMap()]);
37949  const type = createNgModuleType(meta);
37950  return {
37951    expression,
37952    type,
37953    statements: []
37954  };
37955}
37956/**
37957 * Gathers the declaration fields for an NgModule into a `DefinitionMap`.
37958 */
37959function createNgModuleDefinitionMap(meta) {
37960  const definitionMap = new DefinitionMap();
37961  if (meta.kind === R3NgModuleMetadataKind.Local) {
37962    throw new Error('Invalid path! Local compilation mode should not get into the partial compilation path');
37963  }
37964  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$1));
37965  definitionMap.set('version', literal('17.3.9'));
37966  definitionMap.set('ngImport', importExpr(Identifiers.core));
37967  definitionMap.set('type', meta.type.value);
37968  // We only generate the keys in the metadata if the arrays contain values.
37969  // We must wrap the arrays inside a function if any of the values are a forward reference to a
37970  // not-yet-declared class. This is to support JIT execution of the `ɵɵngDeclareNgModule(
37970)` call.
37971  // In the linker these wrappers are stripped and then reapplied for the `ɵɵdefineNgModule()` call.
37972  if (meta.bootstrap.length > 0) {
37973    definitionMap.set('bootstrap', refsToArray(meta.bootstrap, meta.containsForwardDecls));
37974  }
37975  if (meta.declarations.length > 0) {
37976    definitionMap.set('declarations', refsToArray(meta.declarations, meta.containsForwardDecls));
37977  }
37978  if (meta.imports.length > 0) {
37979    definitionMap.set('imports', refsToArray(meta.imports, meta.containsForwardDecls));
37980  }
37981  if (meta.exports.length > 0) {
37982    definitionMap.set('exports', refsToArray(meta.exports, meta.containsForwardDecls));
37983  }
37984  if (meta.schemas !== null && meta.schemas.length > 0) {
37985    definitionMap.set('schemas', literalArr(meta.schemas.map(ref => ref.value)));
37986  }
37987  if (meta.id !== null) {
37988    definitionMap.set('id', meta.id);
37989  }
37990  return definitionMap;
37991}
37992
37993/**
37994 * Every time we make a breaking change to the declaration interface or partial-linker behavior, we
37995 * must update this constant to prevent old partial-linkers from incorrectly processing the
37996 * declaration.
37997 *
37998 * Do not include any prerelease in these versions as they are ignored.
37999 */
38000const MINIMUM_PARTIAL_LINKER_VERSION = '14.0.0';
38001/**
38002 * Compile a Pipe declaration defined by the `R3PipeMetadata`.
38003 */
38004function compileDeclarePipeFromMetadata(meta) {
38005  const definitionMap = createPipeDefinitionMap(meta);
38006  const expression = importExpr(Identifiers.declarePipe).callFn([definitionMap.toLiteralMap()]);
38007  const type = createPipeType(meta);
38008  return {
38009    expression,
38010    type,
38011    statements: []
38012  };
38013}
38014/**
38015 * Gathers the declaration fields for a Pipe into a `DefinitionMap`.
38016 */
38017function createPipeDefinitionMap(meta) {
38018  const definitionMap = new DefinitionMap();
38019  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION));
38020  definitionMap.set('version', literal('17.3.9'));
38021  definitionMap.set('ngImport', importExpr(Identifiers.core));
38022  // e.g. `type: MyPipe`
38023  definitionMap.set('type', meta.type.value);
38024  if (meta.isStandalone) {
38025    definitionMap.set('isStandalone', literal(meta.isStandalone));
38026  }
38027  // e.g. `name: "myPipe"`
38028  definitionMap.set('name', literal(meta.pipeName));
38029  if (meta.pure === false) {
38030    // e.g. `pure: false`
38031    definitionMap.set('pure', literal(meta.pure));
38032  }
38033  return definitionMap;
38034}
38035
38036//////////////////////////////////////
38037// This file only reexports content of the `src` folder. Keep it that way.
38038// This function call has a global side effects and publishes the compiler into global namespace for
38039// the late binding of the Compiler to the @angular/core for jit compilation.
38040publishFacade(_global);
38041
38042/**
38043 * @module
38044 * @description
38045 * Entry point for all public APIs of this package.
38046 */
38047// This file only reexports content of the `src` folder. Keep it that way.
38048
38049// This file is not used to build this module. It is only used during editing
38050
38051// This file is not used to build this module. It is only used during editing
38052
38053
38054
38055/***/ }),
38056
38057/***/ 1643:
38058/*!**********************************************************!*\
38059  !*** ./node_modules/@angular/localize/fesm2022/init.mjs ***!
38060  \**********************************************************/
38061/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
38062
38063__webpack_require__.r(__webpack_exports__);
38064/* harmony export */ __webpack_require__.d(__webpack_exports__, {
38065/* harmony export */   $localize: () => (/* reexport safe */ _angular_localize__WEBPACK_IMPORTED_MODULE_0__["ɵ$localize"])
38066/* harmony export */ });
38067/* harmony import */ var _angular_localize__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/localize */ 95116);
38068/**
38069 * @license Angular v17.3.9
38070 * (c) 2010-2024 Google LLC. https://angular.io/
38071 * License: MIT
38072 */
38073
38074
38075
38076
38077// Attach $localize to the global context, as a side-effect of this module.
38078globalThis.$localize = _angular_localize__WEBPACK_IMPORTED_MODULE_0__["ɵ$localize"];
38079
38080/***/ }),
38081
38082/***/ 95116:
38083/*!**************************************************************!*\
38084  !*** ./node_modules/@angular/localize/fesm2022/localize.mjs ***!
38085  \**************************************************************/
38086/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
38087
38088__webpack_require__.r(__webpack_exports__);
38089/* harmony export */ __webpack_require__.d(__webpack_exports__, {
38090/* harmony export */   clearTranslations: () => (/* binding */ clearTranslations),
38091/* harmony export */   loadTranslations: () => (/* binding */ loadTranslations),
38092/* harmony export */   "ɵ$localize": () => (/* binding */ $localize$1),
38093/* harmony export */   "ɵMissingTranslationError": () => (/* binding */ MissingTranslationError),
38094/* harmony export */   "ɵcomputeMsgId": () => (/* binding */ computeMsgId),
38095/* harmony export */   "ɵfindEndOfBlock": () =>
38095 (/* binding */ findEndOfBlock),
38096/* harmony export */   "ɵisMissingTranslationError": () => (/* binding */ isMissingTranslationError),
38097/* harmony export */   "ɵmakeParsedTranslation": () => (/* binding */ makeParsedTranslation),
38098/* harmony export */   "ɵmakeTemplateObject": () => (/* binding */ makeTemplateObject),
38099/* harmony export */   "ɵparseMessage": () => (/* binding */ parseMessage),
38100/* harmony export */   "ɵparseMetadata": () => (/* binding */ parseMetadata),
38101/* harmony export */   "ɵparseTranslation": () => (/* binding */ parseTranslation),
38102/* harmony export */   "ɵsplitBlock": () => (/* binding */ splitBlock),
38103/* harmony export */   "ɵtranslate": () => (/* binding */ translate$1)
38104/* harmony export */ });
38105/**
38106 * @license Angular v17.3.9
38107 * (c) 2010-2024 Google LLC. https://angular.io/
38108 * License: MIT
38109 */
38110
38111/**
38112 * The character used to mark the start and end of a "block" in a `$localize` tagged string.
38113 * A block can indicate metadata about the message or specify a name of a placeholder for a
38114 * substitution expressions.
38115 *
38116 * For example:
38117 *
38118 * ```ts
38119 * $localize`Hello, ${title}:title:!`;
38120 * $localize`:meaning|description@@id:source message text`;
38121 * ```
38122 */
38123const BLOCK_MARKER$1 = ':';
38124/**
38125 * The marker used to separate a message's "meaning" from its "description" in a metadata block.
38126 *
38127 * For example:
38128 *
38129 * ```ts
38130 * $localize `:correct|Indicates that the user got the answer correct: Right!`;
38131 * $localize `:movement|Button label for moving to the right: Right!`;
38132 * ```
38133 */
38134const MEANING_SEPARATOR = '|';
38135/**
38136 * The marker used to separate a message's custom "id" from its "description" in a metadata block.
38137 *
38138 * For example:
38139 *
38140 * ```ts
38141 * $localize `:A welcome message on the home page@@myApp-homepage-welcome: Welcome!`;
38142 * ```
38143 */
38144const ID_SEPARATOR = '@@';
38145/**
38146 * The marker used to separate legacy message ids from the rest of a metadata block.
38147 *
38148 * For example:
38149 *
38150 * ```ts
38151 * $localize `:@@custom-id␟2df64767cd895a8fabe3e18b94b5b6b6f9e2e3f0: Welcome!`;
38152 * ```
38153 *
38154 * Note that this character is the "symbol for the unit separator" (␟) not the "unit separator
38155 * character" itself, since that has no visual representation. See https://graphemica.com/%E2%90%9F.
38156 *
38157 * Here is some background for the original "unit separator character":
38158 * https://stackoverflow.com/questions/8695118/whats-the-file-group-record-unit-separator-control-characters-and-its-usage
38159 */
38160const LEGACY_ID_INDICATOR = '\u241F';
38161
38162/**
38163 * A lazily created TextEncoder instance for converting strings into UTF-8 bytes
38164 */
38165let textEncoder;
38166/**
38167 * Return the message id or compute it using the XLIFF1 digest.
38168 */
38169function digest(message) {
38170  return message.id || computeDigest(message);
38171}
38172/**
38173 * Compute the message id using the XLIFF1 digest.
38174 */
38175function computeDigest(message) {
38176  return sha1(serializeNodes(message.nodes).join('') + `[${message.meaning}]`);
38177}
38178/**
38179 * Return the message id or compute it using the XLIFF2/XMB/$localize digest.
38180 */
38181function decimalDigest(message) {
38182  return message.id || computeDecimalDigest(message);
38183}
38184/**
38185 * Compute the message id using the XLIFF2/XMB/$localize digest.
38186 */
38187function computeDecimalDigest(message) {
38188  const visitor = new _SerializerIgnoreIcuExpVisitor();
38189  const parts = message.nodes.map(a => a.visit(visitor, null));
38190  return computeMsgId(parts.join(''), message.meaning);
38191}
38192/**
38193 * Serialize the i18n ast to something xml-like in order to generate an UID.
38194 *
38195 * The visitor is also used in the i18n parser tests
38196 *
38197 * @internal
38198 */
38199class _SerializerVisitor {
38200  visitText(text, context) {
38201    return text.value;
38202  }
38203  visitContainer(container, context) {
38204    return `[${container.children.map(child => child.visit(this)).join(', ')}]`;
38205  }
38206  visitIcu(icu, context) {
38207    const strCases = Object.keys(icu.cases).map(k => `${k} {${icu.cases[k].visit(this)}}`);
38208    return `{${icu.expression}, ${icu.type}, ${strCases.join(', ')}}`;
38209  }
38210  visitTagPlaceholder(ph, context) {
38211    return ph.isVoid ? `<ph tag name="${ph.startName}"/>` : `<ph tag name="${ph.startName}">${ph.children.map(child => child.visit(this)).join(', ')}</ph name="${ph.closeName}">`;
38212  }
38213  visitPlaceholder(ph, context) {
38214    return ph.value ? `<ph name="${ph.name}">${ph.value}</ph>` : `<ph name="${ph.name}"/>`;
38215  }
38216  visitIcuPlaceholder(ph, context) {
38217    return `<ph icu name="${ph.name}">${ph.value.visit(this)}</ph>`;
38218  }
38219  visitBlockPlaceholder(ph, context) {
38220    return `<ph block name="${ph.startName}">${ph.children.map(child => child.visit(this)).join(', ')}</ph name="${ph.closeName}">`;
38221  }
38222}
38223const serializerVisitor = new _SerializerVisitor();
38224function serializeNodes(nodes) {
38225  return nodes.map(a => a.visit(serializerVisitor, null));
38226}
38227/**
38228 * Serialize the i18n ast to something xml-like in order to generate an UID.
38229 *
38230 * Ignore the ICU expressions so that message IDs stays identical if only the expression changes.
38231 *
38232 * @internal
38233 */
38234class _SerializerIgnoreIcuExpVisitor extends _SerializerVisitor {
38235  visitIcu(icu, context) {
38236    let strCases = Object.keys(icu.cases).map(k => `${k} {${icu.cases[k].visit(this)}}`);
38237    // Do not take the expression into account
38238    return `{${icu.type}, ${strCases.join(', ')}}`;
38239  }
38240}
38241/**
38242 * Compute the SHA1 of the given string
38243 *
38244 * see https://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf
38245 *
38246 * WARNING: this function has not been designed not tested with security in mind.
38247 *          DO NOT USE IT IN A SECURITY SENSITIVE CONTEXT.
38248 */
38249function sha1(str) {
38250  textEncoder ??= new TextEncoder();
38251  const utf8 = [...textEncoder.encode(str)];
38252  const words32 = bytesToWords32(utf8, Endian.Big);
38253  const len = utf8.length * 8;
38254  const w = new Uint32Array(80);
38255  let a = 0x67452301,
38256    b = 0xefcdab89,
38257    c = 0x98badcfe,
38258    d = 0x10325476,
38259    e = 0xc3d2e1f0;
38260  words32[len >> 5] |= 0x80 << 24 - len % 32;
38261  words32[(len + 64 >> 9 << 4) + 15] = len;
38262  for (let i = 0; i < words32.length; i += 16) {
38263    const h0 = a,
38264      h1 = b,
38265      h2 = c,
38266      h3 = d,
38267      h4 = e;
38268    for (let j = 0; j < 80; j++) {
38269      if (j < 16) {
38270        w[j] = words32[i + j];
38271      } else {
38272        w[j] = rol32(w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16], 1);
38273      }
38274      const fkVal = fk(j, b, c, d);
38275      const f = fkVal[0];
38276      const k = fkVal[1];
38277      const temp = [rol32(a, 5), f, e, k, w[j]].reduce(add32);
38278      e = d;
38279      d = c;
38280      c = rol32(b, 30);
38281      b = a;
38282      a = temp;
38283    }
38284    a = add32(a, h0);
38285    b = add32(b, h1);
38286    c = add32(c, h2);
38287    d = add32(d, h3);
38288    e = add32(e, h4);
38289  }
38290  // Convert the output parts to a 160-bit hexadecimal string
38291  return toHexU32(a) + toHexU32(b) + toHexU32(c) + toHexU32(d) + toHexU32(e);
38292}
38293/**
38294 * Convert and format a number as a string representing a 32-bit unsigned hexadecimal number.
38295 * @param value The value to format as a string.
38296 * @returns A hexadecimal string representing the value.
38297 */
38298function toHexU32(value) {
38299  // unsigned right shift of zero ensures an unsigned 32-bit number
38300  return (value >>> 0).toString(16).padStart(8, '0');
38301}
38302function fk(index, b, c, d) {
38303  if (index < 20) {
38304    return [b & c | ~b & d, 0x5a827999];
38305  }
38306  if (index < 40) {
38307    return [b ^ c ^ d, 0x6ed9eba1];
38308  }
38309  if (index < 60) {
38310    return [b & c | b & d | c & d, 0x8f1bbcdc];
38311  }
38312  return [b ^ c ^ d, 0xca62c1d6];
38313}
38314/**
38315 * Compute the fingerprint of the given string
38316 *
38317 * The output is 64 bit number encoded as a decimal string
38318 *
38319 * based on:
38320 * https://github.com/google/closure-compiler/blob/master/src/com/google/javascript/jscomp/GoogleJsMessageIdGenerator.java
38321 */
38322function fingerprint(str) {
38323  textEncoder ??= new TextEncoder();
38324  const utf8 = textEncoder.encode(str);
38325  const view = new DataView(utf8.buffer, utf8.byteOffset, utf8.byteLength);
38326  let hi = hash32(view, utf8.length, 0);
38327  let lo = hash32(view, utf8.length, 102072);
38328  if (hi == 0 && (lo == 0 || lo == 1)) {
38329    hi = hi ^ 0x130f9bef;
38330    lo = lo ^ -0x6b5f56d8;
38331  }
38332  return BigInt.asUintN(32, BigInt(hi)) << BigInt(32) | BigInt.asUintN(32, BigInt(lo));
38333}
38334function computeMsgId(msg, meaning = '') {
38335  let msgFingerprint = fingerprint(msg);
38336  if (meaning) {
38337    // Rotate the 64-bit message fingerprint one bit to the left and then add the meaning
38338    // fingerprint.
38339    msgFingerprint = BigInt.asUintN(64, msgFingerprint << BigInt(1)) | msgFingerprint >> BigInt(63) & BigInt(1);
38340    msgFingerprint += fingerprint(meaning);
38341  }
38342  return BigInt.asUintN(63, msgFingerprint).toString();
38343}
38344function hash32(view, length, c) {
38345  let a = 0x9e3779b9,
38346    b = 0x9e3779b9;
38347  let index = 0;
38348  const end = length - 12;
38349  for (; index <= end; index += 12) {
38350    a += view.getUint32(index, true);
38351    b += view.getUint32(index + 4, true);
38352    c += view.getUint32(index + 8, true);
38353    const res = mix(a, b, c);
38354    a = res[0], b = res[1], c = res[2];
38355  }
38356  const remainder = length - index;
38357  // the first byte of c is reserved for the length
38358  c += length;
38359  if (remainder >= 4) {
38360    a += view.getUint32(index, true);
38361    index += 4;
38362    if (remainder >= 8) {
38363      b += view.getUint32(index, true);
38364      index += 4;
38365      // Partial 32-bit word for c
38366      if (remainder >= 9) {
38367        c += view.getUint8(index++) << 8;
38368      }
38369      if (remainder >= 10) {
38370        c += view.getUint8(index++) << 16;
38371      }
38372      if (remainder === 11) {
38373        c += view.getUint8(index++) << 24;
38374      }
38375    } else {
38376      // Partial 32-bit word for b
38377      if (remainder >= 5) {
38378        b += view.getUint8(index++);
38379      }
38380      if (remainder >= 6) {
38381        b += view.getUint8(index++) << 8;
38382      }
38383      if (remainder === 7) {
38384        b += view.getUint8(index++) << 16;
38385      }
38386    }
38387  } else {
38388    // Partial 32-bit word for a
38389    if (remainder >= 1) {
38390      a += view.getUint8(index++);
38391    }
38392    if (remainder >= 2) {
38393      a += view.getUint8(index++) << 8;
38394    }
38395    if (remainder === 3) {
38396      a += view.getUint8(index++) << 16;
38397    }
38398  }
38399  return mix(a, b, c)[2];
38400}
38401// clang-format off
38402function mix(a, b, c) {
38403  a -= b;
38404  a -= c;
38405  a ^= c >>> 13;
38406  b -= c;
38407  b -= a;
38408  b ^= a << 8;
38409  c -= a;
38410  c -= b;
38411  c ^= b >>> 13;
38412  a -= b;
38413  a -= c;
38414  a ^= c >>> 12;
38415  b -= c;
38416  b -= a;
38417  b ^= a << 16;
38418  c -= a;
38419  c -= b;
38420  c ^= b >>> 5;
38421  a -= b;
38422  a -= c;
38423  a ^= c >>> 3;
38424  b -= c;
38425  b -= a;
38426  b ^= a << 10;
38427  c -= a;
38428  c -= b;
38429  c ^= b >>> 15;
38430  return [a, b, c];
38431}
38432// clang-format on
38433// Utils
38434var Endian;
38435(function (Endian) {
38436  Endian[Endian["Little"] = 0] = "Little";
38437  Endian[Endian["Big"] = 1] = "Big";
38438})(Endian || (Endian = {}));
38439function add32(a, b) {
38440  return add32to64(a, b)[1];
38441}
38442function add32to64(a, b) {
38443  const low = (a & 0xffff) + (b & 0xffff);
38444  const high = (a >>> 16) + (b >>> 16) + (low >>> 16);
38445  return [high >>> 16, high << 16 | low & 0xffff];
38446}
38447// Rotate a 32b number left `count` position
38448function rol32(a, count) {
38449  return a << count | a >>> 32 - count;
38450}
38451function bytesToWords32(bytes, endian) {
38452  const size = bytes.length + 3 >>> 2;
38453  const words32 = [];
38454  for (let i = 0; i < size; i++) {
38455    words32[i] = wordAt(bytes, i * 4, endian);
38456  }
38457  return words32;
38458}
38459function byteAt(bytes, index) {
38460  return index >= bytes.length ? 0 : bytes[index];
38461}
38462function wordAt(bytes, index, endian) {
38463  let word = 0;
38464  if (endian === Endian.Big) {
38465    for (let i = 0; i < 4; i++) {
38466      word += byteAt(bytes, index + i) << 24 - 8 * i;
38467    }
38468  } else {
38469    for (let i = 0; i < 4; i++) {
38470      word += byteAt(bytes, index + i) << 8 * i;
38471    }
38472  }
38473  return word;
38474}
38475
38476// This module specifier is intentionally a relative path to allow bundling the code directly
38477/**
38478 * Parse a `$localize` tagged string into a structure that can be used for translation or
38479 * extraction.
38480 *
38481 * See `ParsedMessage` for an example.
38482 */
38483function parseMessage(messageParts, expressions, location, messagePartLocations, expressionLocations = []) {
38484  const substitutions = {};
38485  const substitutionLocations = {};
38486  const associatedMessageIds = {};
38487  const metadata = parseMetadata(messageParts[0], messageParts.raw[0]);
38488  const cleanedMessageParts = [metadata.text];
38489  const placeholderNames = [];
38490  let messageString = metadata.text;
38491  for (let i = 1; i < messageParts.length; i++) {
38492    const {
38493      messagePart,
38494      placeholderName = computePlaceholderName(i),
38495      associatedMessageId
38496    } = parsePlaceholder(messageParts[i], messageParts.raw[i]);
38497    messageString += `{$${placeholderName}}${messagePart}`;
38498    if (expressions !== undefined) {
38499      substitutions[placeholderName] = expressions[i - 1];
38500      substitutionLocations[placeholderName] = expressionLocations[i - 1];
38501    }
38502    placeholderNames.push(placeholderName);
38503    if (associatedMessageId !== undefined) {
38504      associatedMessageIds[placeholderName] = associatedMessageId;
38505    }
38506    cleanedMessageParts.push(messagePart);
38507  }
38508  const messageId = metadata.customId || computeMsgId(messageString, metadata.meaning || '');
38509  const legacyIds = metadata.legacyIds ? metadata.legacyIds.filter(id => id !== messageId) : [];
38510  return {
38511    id: messageId,
38512    legacyIds,
38513    substitutions,
38514    substitutionLocations,
38515    text: messageString,
38516    customId: metadata.customId,
38517    meaning: metadata.meaning || '',
38518    description: metadata.description || '',
38519    messageParts: cleanedMessageParts,
38520    messagePartLocations,
38521    placeholderNames,
38522    associatedMessageIds,
38523    location
38524  };
38525}
38526/**
38527 * Parse the given message part (`cooked` + `raw`) to extract the message metadata from the text.
38528 *
38529 * If the message part has a metadata block this function will extract the `meaning`,
38530 * `description`, `customId` and `legacyId` (if provided) from the block. These metadata properties
38531 * are serialized in the string delimited by `|`, `@@` and `␟` respectively.
38532 *
38533 * (Note that `␟` is the `LEGACY_ID_INDICATOR` - see `constants.ts`.)
38534 *
38535 * For example:
38536 *
38537 * ```ts
38538 * `:meaning|description@@custom-id:`
38539 * `:meaning|@@custom-id:`
38540 * `:meaning|description:`
38541 * `:description@@custom-id:`
38542 * `:meaning|:`
38543 * `:description:`
38544 * `:@@custom-id:`
38545 * `:meaning|description@@custom-id␟legacy-id-1␟legacy-id-2:`
38546 * ```
38547 *
38548 * @param cooked The cooked version of the message part to parse.
38549 * @param raw The raw version of the message part to parse.
38550 * @returns A object containing any metadata that was parsed from the message part.
38551 */
38552function parseMetadata(cooked, raw) {
38553  const {
38554    text: messageString,
38555    block
38556  } = splitBlock(cooked, raw);
38557  if (block === undefined) {
38558    return {
38559      text: messageString
38560    };
38561  } else {
38562    const [meaningDescAndId, ...legacyIds] = block.split(LEGACY_ID_INDICATOR);
38563    const [meaningAndDesc, customId] = meaningDescAndId.split(ID_SEPARATOR, 2);
38564    let [meaning, description] = meaningAndDesc.split(MEANING_SEPARATOR, 2);
38565    if (description === undefined) {
38566      description = meaning;
38567      meaning = undefined;
38568    }
38569    if (description === '') {
38570      description = undefined;
38571    }
38572    return {
38573      text: messageString,
38574      meaning,
38575      description,
38576      customId,
38577      legacyIds
38578    };
38579  }
38580}
38581/**
38582 * Parse the given message part (`cooked` + `raw`) to extract any placeholder metadata from the
38583 * text.
38584 *
38585 * If the message part has a metadata block this function will extract the `placeholderName` and
38586 * `associatedMessageId` (if provided) from the block.
38587 *
38588 * These metadata properties are serialized in the string delimited by `@@`.
38589 *
38590 * For example:
38591 *
38592 * ```ts
38593 * `:placeholder-name@@associated-id:`
38594 * ```
38595 *
38596 * @param cooked The cooked version of the message part to parse.
38597 * @param raw The raw version of the message part to parse.
38598 * @returns A object containing the metadata (`placeholderName` and `associatedMessageId`) of the
38599 *     preceding placeholder, along with the static text that follows.
38600 */
38601function parsePlaceholder(cooked, raw) {
38602  const {
38603    text: messagePart,
38604    block
38605  } = splitBlock(cooked, raw);
38606  if (block === undefined) {
38607    return {
38608      messagePart
38609    };
38610  } else {
38611    const [placeholderName, associatedMessageId] = block.split(ID_SEPARATOR);
38612    return {
38613      messagePart,
38614      placeholderName,
38615      associatedMessageId
38616    };
38617  }
38618}
38619/**
38620 * Split a message part (`cooked` + `raw`) into an optional delimited "block" off the front and the
38621 * rest of the text of the message part.
38622 *
38623 * Blocks appear at the start of message parts. They are delimited by a colon `:` character at the
38624 * start and end of the block.
38625 *
38626 * If the block is in the first message part then it will be metadata about the whole message:
38627 * meaning, description, id.  Otherwise it will be metadata about the immediately preceding
38628 * substitution: placeholder name.
38629 *
38630 * Since blocks are optional, it is possible that the content of a message block actually starts
38631 * with a block marker. In this case the marker must be escaped `\:`.
38632 *
38633 * @param cooked The cooked version of the message part to parse.
38634 * @param raw The raw version of the message part to parse.
38635 * @returns An object containing the `text` of the message part and the text of the `block`, if it
38636 * exists.
38637 * @throws an error if the `block` is unterminated
38638 */
38639function splitBlock(cooked, raw) {
38640  if (raw.charAt(0) !== BLOCK_MARKER$1) {
38641    return {
38642      text: cooked
38643    };
38644  } else {
38645    const endOfBlock = findEndOfBlock(cooked, raw);
38646    return {
38647      block: cooked.substring(1, endOfBlock),
38648      text: cooked.substring(endOfBlock + 1)
38649    };
38650  }
38651}
38652function computePlaceholderName(index) {
38653  return index === 1 ? 'PH' : `PH_${index - 1}`;
38654}
38655/**
38656 * Find the end of a "marked block" indicated by the first non-escaped colon.
38657 *
38658 * @param cooked The cooked string (where escaped chars have been processed)
38659 * @param raw The raw string (where escape sequences are still in place)
38660 *
38661 * @returns the index of the end of block marker
38662 * @throws an error if the block is unterminated
38663 */
38664function findEndOfBlock(cooked, raw) {
38665  for (let cookedIndex = 1, rawIndex = 1; cookedIndex < cooked.length; cookedIndex++, rawIndex++) {
38666    if (raw[rawIndex] === '\\') {
38667      rawIndex++;
38668    } else if (cooked[cookedIndex] === BLOCK_MARKER$1) {
38669      return cookedIndex;
38670    }
38671  }
38672  throw new Error(`Unterminated $localize metadata block in "${raw}".`);
38673}
38674class MissingTranslationError extends Error {
38675  constructor(parsedMessage) {
38676    super(`No translation found for ${describeMessage(parsedMessage)}.`);
38677    this.parsedMessage = parsedMessage;
38678    this.type = 'MissingTranslationError';
38679  }
38680}
38681function isMissingTranslationError(e) {
38682  return e.type === 'MissingTranslationError';
38683}
38684/**
38685 * Translate the text of the `$localize` tagged-string (i.e. `messageParts` and
38686 * `substitutions`) using the given `translations`.
38687 *
38688 * The tagged-string is parsed to extract its `messageId` which is used to find an appropriate
38689 * `ParsedTranslation`. If this doesn't match and there are legacy ids then try matching a
38690 * translation using those.
38691 *
38692 * If one is found then it is used to translate the message into a 
38692new set of `messageParts` and
38693 * `substitutions`.
38694 * The translation may reorder (or remove) substitutions as appropriate.
38695 *
38696 * If there is no translation with a matching message id then an error is thrown.
38697 * If a translation contains a placeholder that is not found in the message being translated then an
38698 * error is thrown.
38699 */
38700function translate$1(translations, messageParts, substitutions) {
38701  const message = parseMessage(messageParts, substitutions);
38702  // Look up the translation using the messageId, and then the legacyId if available.
38703  let translation = translations[message.id];
38704  // If the messageId did not match a translation, try matching the legacy ids instead
38705  if (message.legacyIds !== undefined) {
38706    for (let i = 0; i < message.legacyIds.length && translation === undefined; i++) {
38707      translation = translations[message.legacyIds[i]];
38708    }
38709  }
38710  if (translation === undefined) {
38711    throw new MissingTranslationError(message);
38712  }
38713  return [translation.messageParts, translation.placeholderNames.map(placeholder => {
38714    if (message.substitutions.hasOwnProperty(placeholder)) {
38715      return message.substitutions[placeholder];
38716    } else {
38717      throw new Error(`There is a placeholder name mismatch with the translation provided for the message ${describeMessage(message)}.\n` + `The translation contains a placeholder with name ${placeholder}, which does not exist in the message.`);
38718    }
38719  })];
38720}
38721/**
38722 * Parse the `messageParts` and `placeholderNames` out of a target `message`.
38723 *
38724 * Used by `loadTranslations()` to convert target message strings into a structure that is more
38725 * appropriate for doing translation.
38726 *
38727 * @param message the message to be parsed.
38728 */
38729function parseTranslation(messageString) {
38730  const parts = messageString.split(/{\$([^}]*)}/);
38731  const messageParts = [parts[0]];
38732  const placeholderNames = [];
38733  for (let i = 1; i < parts.length - 1; i += 2) {
38734    placeholderNames.push(parts[i]);
38735    messageParts.push(`${parts[i + 1]}`);
38736  }
38737  const rawMessageParts = messageParts.map(part => part.charAt(0) === BLOCK_MARKER$1 ? '\\' + part : part);
38738  return {
38739    text: messageString,
38740    messageParts: makeTemplateObject(messageParts, rawMessageParts),
38741    placeholderNames
38742  };
38743}
38744/**
38745 * Create a `ParsedTranslation` from a set of `messageParts` and `placeholderNames`.
38746 *
38747 * @param messageParts The message parts to appear in the ParsedTranslation.
38748 * @param placeholderNames The names of the placeholders to intersperse between the `messageParts`.
38749 */
38750function makeParsedTranslation(messageParts, placeholderNames = []) {
38751  let messageString = messageParts[0];
38752  for (let i = 0; i < placeholderNames.length; i++) {
38753    messageString += `{$${placeholderNames[i]}}${messageParts[i + 1]}`;
38754  }
38755  return {
38756    text: messageString,
38757    messageParts: makeTemplateObject(messageParts, messageParts),
38758    placeholderNames
38759  };
38760}
38761/**
38762 * Create the specialized array that is passed to tagged-string tag functions.
38763 *
38764 * @param cooked The message parts with their escape codes processed.
38765 * @param raw The message parts with their escaped codes as-is.
38766 */
38767function makeTemplateObject(cooked, raw) {
38768  Object.defineProperty(cooked, 'raw', {
38769    value: raw
38770  });
38771  return cooked;
38772}
38773function describeMessage(message) {
38774  const meaningString = message.meaning && ` - "${message.meaning}"`;
38775  const legacy = message.legacyIds && message.legacyIds.length > 0 ? ` [${message.legacyIds.map(l => `"${l}"`).join(', ')}]` : '';
38776  return `"${message.id}"${legacy} ("${message.text}"${meaningString})`;
38777}
38778
38779/**
38780 * Load translations for use by `$localize`, if doing runtime translation.
38781 *
38782 * If the `$localize` tagged strings are not going to be replaced at compiled time, it is possible
38783 * to load a set of translations that will be applied to the `$localize` tagged strings at runtime,
38784 * in the browser.
38785 *
38786 * Loading a new translation will overwrite a previous translation if it has the same `MessageId`.
38787 *
38788 * Note that `$localize` messages are only processed once, when the tagged string is first
38789 * encountered, and does not provide dynamic language changing without refreshing the browser.
38790 * Loading new translations later in the application life-cycle will not change the translated text
38791 * of messages that have already been translated.
38792 *
38793 * The message IDs and translations are in the same format as that rendered to "simple JSON"
38794 * translation files when extracting messages. In particular, placeholders in messages are rendered
38795 * using the `{$PLACEHOLDER_NAME}` syntax. For example the message from the following template:
38796 *
38797 * ```html
38798 * <div i18n>pre<span>inner-pre<b>bold</b>inner-post</span>post</div>
38799 * ```
38800 *
38801 * would have the following form in the `translations` map:
38802 *
38803 * ```ts
38804 * {
38805 *   "2932901491976224757":
38806 *      "pre{$START_TAG_SPAN}inner-pre{$START_BOLD_TEXT}bold{$CLOSE_BOLD_TEXT}inner-post{$CLOSE_TAG_SPAN}post"
38807 * }
38808 * ```
38809 *
38810 * @param translations A map from message ID to translated message.
38811 *
38812 * These messages are processed and added to a lookup based on their `MessageId`.
38813 *
38814 * @see {@link clearTranslations} for removing translations loaded using this function.
38815 * @see {@link $localize} for tagging messages as needing to be translated.
38816 * @publicApi
38817 */
38818function loadTranslations(translations) {
38819  // Ensure the translate function exists
38820  if (!$localize.translate) {
38821    $localize.translate = translate;
38822  }
38823  if (!$localize.TRANSLATIONS) {
38824    $localize.TRANSLATIONS = {};
38825  }
38826  Object.keys(translations).forEach(key => {
38827    $localize.TRANSLATIONS[key] = parseTranslation(translations[key]);
38828  });
38829}
38830/**
38831 * Remove all translations for `$localize`, if doing runtime translation.
38832 *
38833 * All translations that had been loading into memory using `loadTranslations()` will be removed.
38834 *
38835 * @see {@link loadTranslations} for loading translations at runtime.
38836 * @see {@link $localize} for tagging messages as needing to be translated.
38837 *
38838 * @publicApi
38839 */
38840function clearTranslations() {
38841  $localize.translate = undefined;
38842  $localize.TRANSLATIONS = {};
38843}
38844/**
38845 * Translate the text of the given message, using the loaded translations.
38846 *
38847 * This function may reorder (or remove) substitutions as indicated in the matching translation.
38848 */
38849function translate(messageParts, substitutions) {
38850  try {
38851    return translate$1($localize.TRANSLATIONS, messageParts, substitutions);
38852  } catch (e) {
38853    console.warn(e.message);
38854    return [messageParts, substitutions];
38855  }
38856}
38857
38858/**
38859 * Tag a template literal string for localization.
38860 *
38861 * For example:
38862 *
38863 * ```ts
38864 * $localize `some string to localize`
38865 * ```
38866 *
38867 * **Providing meaning, description and id**
38868 *
38869 * You can optionally specify one or more of `meaning`, `description` and `id` for a localized
38870 * string by pre-pending it with a colon delimited block of the form:
38871 *
38872 * ```ts
38873 * $localize`:meaning|description@@id:source message text`;
38874 *
38875 * $localize`:meaning|:source message text`;
38876 * $localize`:description:source message text`;
38877 * $localize`:@@id:source message text`;
38878 * ```
38879 *
38880 * This format is the same as that used for `i18n` markers in Angular templates. See the
38881 * [Angular i18n guide](guide/i18n-common-prepare#mark-text-in-component-template).
38882 *
38883 * **Naming placeholders**
38884 *
38885 * If the template literal string contains expressions, then the expressions will be automatically
38886 * associated with placeholder names for you.
38887 *
38888 * For example:
38889 *
38890 * ```ts
38891 * $localize `Hi ${name}! There are ${items.length} items.`;
38892 * ```
38893 *
38894 * will generate a message-source of `Hi {$PH}! There are {$PH_1} items`.
38895 *
38896 * The recommended practice is to name the placeholder associated with each expression though.
38897 *
38898 * Do this by providing the placeholder name wrapped in `:` characters directly after the
38899 * expression. These placeholder names are stripped out of the rendered localized string.
38900 *
38901 * For example, to name the `items.length` expression placeholder `itemCount` you write:
38902 *
38903 * ```ts
38904 * $localize `There are ${items.length}:itemCount: items`;
38905 * ```
38906 *
38907 * **Escaping colon markers**
38908 *
38909 * If you need to use a `:` character directly at the start of a tagged string that has no
38910 * metadata block, or directly after a substitution expression that has no name you must escape
38911 * the `:` by preceding it with a backslash:
38912 *
38913 * For example:
38914 *
38915 * ```ts
38916 * // message has a metadata block so no need to escape colon
38917 * $localize `:some description::this message starts with a colon (:)`;
38918 * // no metadata block so the colon must be escaped
38919 * $localize `\:this message starts with a colon (:)`;
38920 * ```
38921 *
38922 * ```ts
38923 * // named substitution so no need to escape colon
38924 * $localize `${label}:label:: ${}`
38925 * // anonymous substitution so colon must be escaped
38926 * $localize `${label}\: ${}`
38927 * ```
38928 *
38929 * **Processing localized strings:**
38930 *
38931 * There are three scenarios:
38932 *
38933 * * **compile-time inlining**: the `$localize` tag is transformed at compile time by a
38934 * transpiler, removing the tag and replacing the template literal string with a translated
38935 * literal string from a collection of translations provided to the transpilation tool.
38936 *
38937 * * **run-time evaluation**: the `$localize` tag is a run-time function that replaces and
38938 * reorders the parts (static strings and expressions) of the template literal string with strings
38939 * from a collection of translations loaded at run-time.
38940 *
38941 * * **pass-through evaluation**: the `$localize` tag is a run-time function that simply evaluates
38942 * the original template literal string without applying any translations to the parts. This
38943 * version is used during development or where there is no need to translate the localized
38944 * template literals.
38945 *
38946 * @param messageParts a collection of the static parts of the template string.
38947 * @param expressions a collection of the values of each placeholder in the template string.
38948 * @returns the translated string, with the `messageParts` and `expressions` interleaved together.
38949 *
38950 * @globalApi
38951 * @publicApi
38952 */
38953const $localize$1 = function (messageParts, ...expressions) {
38954  if ($localize$1.translate) {
38955    // Don't use array expansion here to avoid the compiler adding `__read()` helper unnecessarily.
38956    const translation = $localize$1.translate(messageParts, expressions);
38957    messageParts = translation[0];
38958    expressions = translation[1];
38959  }
38960  let message = stripBlock(messageParts[0], messageParts.raw[0]);
38961  for (let i = 1; i < messageParts.length; i++) {
38962    message += expressions[i - 1] + stripBlock(messageParts[i], messageParts.raw[i]);
38963  }
38964  return message;
38965};
38966const BLOCK_MARKER = ':';
38967/**
38968 * Strip a delimited "block" from the start of the `messagePart`, if it is found.
38969 *
38970 * If a marker character (:) actually appears in the content at the start of a tagged string or
38971 * after a substitution expression, where a block has not been provided the character must be
38972 * escaped with a backslash, `\:`. This function checks for this by looking at the `raw`
38973 * messagePart, which should still contain the backslash.
38974 *
38975 * @param messagePart The cooked message part to process.
38976 * @param rawMessagePart The raw message part to check.
38977 * @returns the message part with the placeholder name stripped, if found.
38978 * @throws an error if the block is unterminated
38979 */
38980function stripBlock(messagePart, rawMessagePart) {
38981  return rawMessagePart.charAt(0) === BLOCK_MARKER ? messagePart.substring(findEndOfBlock(messagePart, rawMessagePart) + 1) : messagePart;
38982}
38983
38984// This file exports all the `utils` as private exports so that other parts of `@angular/localize`
38985
38986// This file contains the public API of the `@angular/localize` entry-point
38987
38988// DO NOT ADD public exports to this file.
38989
38990
38991
38992/***/ })
38993
38994},
38995/******/ __webpack_require__ => { // webpackRuntimeModules
38996/******/ var __webpack_exec__ = (moduleId) => (__webpack_require__(__webpack_require__.s = moduleId))
38997/******/ var __webpack_exports__ = (__webpack_exec__(24050), __webpack_exec__(45568));
38998/******/ }
38999]);
39000//# sourceMappingURL=polyfills.js.map

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.