UNPKG

@angular/compiler

Version:

Angular - the compiler library

33,187 lines 1.18 MB
/**
 * @license Angular v22.1.7
 * (c) 2010-2026 Google LLC. https://angular.dev/
 * License: MIT
 */

const _SELECTOR_REGEXP = new RegExp('(\\:not\\()|' + '(([\\.\\#]?)[-\\w]+)|' + '(?:\\[([-.\\w*\\\\$]+)(?:=(["\']?)([^\\]"\']*)\\5)?\\])|' + '(\\))|' + '(\\s*,\\s*)', 'g');
class CssSelector {
  element = null;
  classNames = [];
  attrs = [];
  notSelectors = [];
  static parse(selector) {
    const results = [];
    const _addResult = (res, cssSel) => {
      if (cssSel.notSelectors.length > 0 && !cssSel.element && cssSel.classNames.length == 0 && cssSel.attrs.length == 0) {
        cssSel.element = '*';
      }
      res.push(cssSel);
    };
    let cssSelector = new CssSelector();
    let match;
    let current = cssSelector;
    let inNot = false;
    _SELECTOR_REGEXP.lastIndex = 0;
    while (match = _SELECTOR_REGEXP.exec(selector)) {
      if (match[1]) {
        if (inNot) {
          throw new Error('Nesting :not in a selector is not allowed');
        }
        inNot = true;
        current = new CssSelector();
        cssSelector.notSelectors.push(current);
      }
      const tag = match[2];
      if (tag) {
        const prefix = match[3];
        if (prefix === '#') {
          current.addAttribute('id', tag.slice(1));
        } else if (prefix === '.') {
          current.addClassName(tag.slice(1));
        } else {
          current.setElement(tag);
        }
      }
      const attribute = match[4];
      if (attribute) {
        current.addAttribute(current.unescapeAttribute(attribute), match[6]);
      }
      if (match[7]) {
        inNot = false;
        current = cssSelector;
      }
      if (match[8]) {
        if (inNot) {
          throw new Error('Multiple selectors in :not are not supported');
        }
        _addResult(results, cssSelector);
        cssSelector = current = new CssSelector();
      }
    }
    _addResult(results, cssSelector);
    return results;
  }
  unescapeAttribute(attr) {
    let result = '';
    let escaping = false;
    for (let i = 0; i < attr.length; i++) {
      const char = attr.charAt(i);
      if (char === '\\') {
        escaping = true;
        continue;
      }
      if (char === '$' && !escaping) {
        throw new Error(`Error in attribute selector "${attr}". ` + `Unescaped "$" is not supported. Please escape with "\\$".`);
      }
      escaping = false;
      result += char;
    }
    return result;
  }
  escapeAttribute(attr) {
    return attr.replace(/\\/g, '\\\\').replace(/\$/g, '\\$');
  }
  isElementSelector() {
    return this.hasElementSelector() && this.classNames.length == 0 && this.attrs.length == 0 && this.notSelectors.length === 0;
  }
  hasElementSelector() {
    return !!this.element;
  }
  setElement(element = null) {
    this.element = element;
  }
  getAttrs() {
    const result = [];
    if (this.classNames.length > 0) {
      result.push('class', this.classNames.join(' '));
    }
    return result.concat(this.attrs);
  }
  addAttribute(name, value = '') {
    this.attrs.push(name, value && value.toLowerCase() || '');
  }
  addClassName(name) {
    this.classNames.push(name.toLowerCase());
  }
  toString() {
    let res = this.element || '';
    if (this.classNames) {
      this.classNames.forEach(klass => res += `.${klass}`);
    }
    if (this.attrs) {
      for (let i = 0; i < this.attrs.length; i += 2) {
        const name = this.escapeAttribute(this.attrs[i]);
        const value = this.attrs[i + 1];
        res += `[${name}${value ? '=' + value : ''}]`;
      }
    }
    this.notSelectors.forEach(notSelector => res += `:not(${notSelector})`);
    return res;
  }
}
class SelectorMatcher {
  static createNotMatcher(notSelectors) {
    const notMatcher = new SelectorMatcher();
    notMatcher.addSelectables(notSelectors, null);
    return notMatcher;
  }
  _elementMap = new Map();
  _elementPartialMap = new Map();
  _classMap = new Map();
  _classPartialMap = new Map();
  _attrValueMap = new Map();
  _attrValuePartialMap = new Map();
  _listContexts = [];
  addSelectables(cssSelectors, callbackCtxt) {
    let listContext = null;
    if (cssSelectors.length > 1) {
      listContext = new SelectorListContext(cssSelectors);
      this._listContexts.push(listContext);
    }
    for (let i = 0; i < cssSelectors.length; i++) {
      this._addSelectable(cssSelectors[i], callbackCtxt, listContext);
    }
  }
  _addSelectable(cssSelector, callbackCtxt, listContext) {
    let matcher = this;
    const element = cssSelector.element;
    const classNames = cssSelector.classNames;
    const attrs = cssSelector.attrs;
    const selectable = new SelectorContext(cssSelector, callbackCtxt, listContext);
    if (element) {
      const isTerminal = attrs.length === 0 && classNames.length === 0;
      if (isTerminal) {
        this._addTerminal(matcher._elementMap, element, selectable);
      } else {
        matcher = this._addPartial(matcher._elementPartialMap, element);
      }
    }
    if (classNames) {
      for (let i = 0; i < classNames.length; i++) {
        const isTerminal = attrs.length === 0 && i === classNames.length - 1;
        const className = classNames[i];
        if (isTerminal) {
          this._addTerminal(matcher._classMap, className, selectable);
        } else {
          matcher = this._addPartial(matcher._classPartialMap, className);
        }
      }
    }
    if (attrs) {
      for (let i = 0; i < attrs.length; i += 2) {
        const isTerminal = i === attrs.length - 2;
        const name = attrs[i];
        const value = attrs[i + 1];
        if (isTerminal) {
          const terminalMap = matcher._attrValueMap;
          let terminalValuesMap = terminalMap.get(name);
          if (!terminalValuesMap) {
            terminalValuesMap = new Map();
            terminalMap.set(name, terminalValuesMap);
          }
          this._addTerminal(terminalValuesMap, value, selectable);
        } else {
          const partialMap = matcher._attrValuePartialMap;
          let partialValuesMap = partialMap.get(name);
          if (!partialValuesMap) {
            partialValuesMap = new Map();
            partialMap.set(name, partialValuesMap);
          }
          matcher = this._addPartial(partialValuesMap, value);
        }
      }
    }
  }
  _addTerminal(map, name, selectable) {
    let terminalList = map.get(name);
    if (!terminalList) {
      terminalList = [];
      map.set(name, terminalList);
    }
    terminalList.push(selectable);
  }
  _addPartial(map, name) {
    let matcher = map.get(name);
    if (!matcher) {
      matcher = new SelectorMatcher();
      map.set(name, matcher);
    }
    return matcher;
  }
  match(cssSelector, matchedCallback) {
    let result = false;
    const element = cssSelector.element;
    const classNames = cssSelector.classNames;
    const attrs = cssSelector.attrs;
    for (let i = 0; i < this._listContexts.length; i++) {
      this._listContexts[i].alreadyMatched = false;
    }
    result = this._matchTerminal(this._elementMap, element, cssSelector, matchedCallback) || result;
    result = this._matchPartial(this._elementPartialMap, element, cssSelector, matchedCallback) || result;
    if (classNames) {
      for (let i = 0; i < classNames.length; i++) {
        const className = classNames[i];
        result = this._matchTerminal(this._classMap, className, cssSelector, matchedCallback) || result;
        result = this._matchPartial(this._classPartialMap, className, cssSelector, matchedCallback) || result;
      }
    }
    if (attrs) {
      for (let i = 0; i < attrs.length; i += 2) {
        const name = attrs[i];
        const value = attrs[i + 1];
        const terminalValuesMap = this._attrValueMap.get(name);
        if (value) {
          result = this._matchTerminal(terminalValuesMap, '', cssSelector, matchedCallback) || result;
        }
        result = this._matchTerminal(terminalValuesMap, value, cssSelector, matchedCallback) || result;
        const partialValuesMap = this._attrValuePartialMap.get(name);
        if (value) {
          result = this._matchPartial(partialValuesMap, '', cssSelector, matchedCallback) || result;
        }
        result = this._matchPartial(partialValuesMap, value, cssSelector, matchedCallback) || result;
      }
    }
    return result;
  }
  _matchTerminal(map, name, cssSelector, matchedCallback) {
    if (!map || typeof name !== 'string') {
      return false;
    }
    let selectables = map.get(name) || [];
    const starSelectables = map.get('*');
    if (starSelectables) {
      selectables = selectables.concat(starSelectables);
    }
    if (selectables.length === 0) {
      return false;
    }
    let selectable;
    let result = false;
    for (let i = 0; i < selectables.length; i++) {
      selectable = selectables[i];
      result = selectable.finalize(cssSelector, matchedCallback) || result;
    }
    return result;
  }
  _matchPartial(map, name, cssSelector, matchedCallback) {
    if (!map || typeof name !== 'string') {
      return false;
    }
    const nestedSelector = map.get(name);
    if (!nestedSelector) {
      return false;
    }
    return nestedSelector.match(cssSelector, matchedCallback);
  }
}
class SelectorListContext {
  selectors;
  alreadyMatched = false;
  constructor(selectors) {
    this.selectors = selectors;
  }
}
class SelectorContext {
  selector;
  cbContext;
  listContext;
  notSelectors;
  constructor(selector, cbContext, listContext) {
    this.selector = selector;
    this.cbContext = cbContext;
    this.listContext = listContext;
    this.notSelectors = selector.notSelectors;
  }
  finalize(cssSelector, callback) {
    let result = true;
    if (this.notSelectors.length > 0 && (!this.listContext || !this.listContext.alreadyMatched)) {
      const notMatcher = SelectorMatcher.createNotMatcher(this.notSelectors);
      result = !notMatcher.match(cssSelector, null);
    }
    if (result && callback && (!this.listContext || !this.listContext.alreadyMatched)) {
      if (this.listContext) {
        this.listContext.alreadyMatched = true;
      }
      callback(this.selector, this.cbContext);
    }
    return result;
  }
}
class SelectorlessMatcher {
  registry;
  constructor(registry) {
    this.registry = registry;
  }
  match(name) {
    return this.registry.has(name) ? this.registry.get(name) : [];
  }
}

var SecurityContext;
(function (SecurityContext) {
  SecurityContext[SecurityContext["NONE"] = 0] = "NONE";
  SecurityContext[SecurityContext["HTML"] = 1] = "HTML";
  SecurityContext[SecurityContext["STYLE"] = 2] = "STYLE";
  SecurityContext[SecurityContext["SCRIPT"] = 3] = "SCRIPT";
  SecurityContext[SecurityContext["URL"] = 4] = "URL";
  SecurityContext[SecurityContext["RESOURCE_URL"] = 5] = "RESOURCE_URL";
  SecurityContext[SecurityContext["ATTRIBUTE_NO_BINDING"] = 6] = "ATTRIBUTE_NO_BINDING";
})(SecurityContext || (SecurityContext = {}));
let _SECURITY_SCHEMA;
const SVG_NAMESPACE$1 = 'svg';
const MATH_ML_NAMESPACE$1 = 'math';
const NO_NAMESPACE = '';
const MATCH_ALL_ELEMENTS = '*';
const createNullObj = () => Object.create(null);
function SECURITY_SCHEMA() {
  if (_SECURITY_SCHEMA) {
    return _SECURITY_SCHEMA;
  }
  _SECURITY_SCHEMA = createNullObj();
  registerContext(SecurityContext.HTML, undefined, [['iframe', ['srcdoc']], ['*', ['innerHTML', 'outerHTML']]]);
  registerContext(SecurityContext.STYLE, undefined, [['*', ['style']]]);
  registerContext(SecurityContext.URL, undefined, [['*', ['formAction']], ['area', ['href']], ['a', ['href', 'xlink:href']], ['form', ['action']], ['img', ['src']], ['video', ['src']]]);
  registerContext(SecurityContext.URL, MATH_ML_NAMESPACE$1, [['*', ['href', 'xlink:href']]]);
  registerContext(SecurityContext.RESOURCE_URL, undefined, [['base', ['href']], ['embed', ['src']], ['frame', ['src']], ['iframe', ['src']], ['link', ['href']], ['object', ['codebase', 'data']]]);
  registerContext(SecurityContext.URL, SVG_NAMESPACE$1, [['a', ['href', 'xlink:href']]]);
  registerContext(SecurityContext.ATTRIBUTE_NO_BINDING, SVG_NAMESPACE$1, [['animate', ['attributeName', 'values', 'to', 'from']], ['set', ['to', 'attributeName']], ['animateMotion', ['attributeName']], ['animateTransform', ['attributeName']]]);
  registerContext(SecurityContext.ATTRIBUTE_NO_BINDING, undefined, [['unknown', ['attributeName', 'values', 'to', 'from', 'sandbox', 'allow', 'allowFullscreen', 'referrerPolicy', 'csp', 'fetchPriority', 'credentialless']], ['iframe', ['sandbox', 'allow', 'allowFullscreen', 'referrerPolicy', 'csp', 'fetchPriority', 'credentialless']]]);
  return _SECURITY_SCHEMA;
}
function registerContext(ctx, namespace, specs) {
  const nsKey = namespace ?? NO_NAMESPACE;
  for (const [element, attributeNames] of specs) {
    const tagName = element.toLowerCase();
    for (const attr of attributeNames) {
      const attrLower = attr.toLowerCase();
      const attrSchema = _SECURITY_SCHEMA[attrLower] ??= createNullObj();
      const nsSchema = attrSchema[nsKey] ??= createNullObj();
      nsSchema[tagName] = ctx;
    }
  }
}
function checkSecurityContext(tagName, propName, namespace) {
  const securitySchema = SECURITY_SCHEMA();
  const attrSchema = securitySchema[propName.toLowerCase()];
  if (!attrSchema) {
    return SecurityContext.NONE;
  }
  const tagLower = tagName.toLowerCase();
  let context;
  if (namespace) {
    const nsSchema = attrSchema[namespace];
    if (nsSchema) {
      context = nsSchema[tagLower] ?? nsSchema[MATCH_ALL_ELEMENTS];
    }
  }
  if (context === undefined) {
    const defaultSchema = attrSchema[NO_NAMESPACE];
    if (defaultSchema) {
      context = defaultSchema[tagLower] ?? defaultSchema[MATCH_ALL_ELEMENTS];
    }
  }
  if (context === undefined && (!namespace || namespace === NO_NAMESPACE)) {
    const svgSchema = attrSchema[SVG_NAMESPACE$1];
    if (svgSchema) {
      context = svgSchema[tagLower];
    }
  }
  return context ?? SecurityContext.NONE;
}

const emitDistinctChangesOnlyDefaultValue = true;
var ViewEncapsulation$1;
(function (ViewEncapsulation) {
  ViewEncapsulation[ViewEncapsulation["Emulated"] = 0] = "Emulated";
  ViewEncapsulation[ViewEncapsulation["None"] = 2] = "None";
  ViewEncapsulation[ViewEncapsulation["ShadowDom"] = 3] = "ShadowDom";
  ViewEncapsulation[ViewEncapsulation["ExperimentalIsolatedShadowDom"] = 4] = "ExperimentalIsolatedShadowDom";
})(ViewEncapsulation$1 || (ViewEncapsulation$1 = {}));
var ChangeDetectionStrategy;
(function (ChangeDetectionStrategy) {
  ChangeDetectionStrategy[ChangeDetectionStrategy["OnPush"] = 0] = "OnPush";
  ChangeDetectionStrategy[ChangeDetectionStrategy["Default"] = 1] = "Default";
  ChangeDetectionStrategy[ChangeDetectionStrategy["Eager"] = 1] = "Eager";
})(ChangeDetectionStrategy || (ChangeDetectionStrategy = {}));
var InputFlags;
(function (InputFlags) {
  InputFlags[InputFlags["None"] = 0] = "None";
  InputFlags[InputFlags["SignalBased"] = 1] = "SignalBased";
  InputFlags[InputFlags["HasDecoratorInputTransform"] = 2] = "HasDecoratorInputTransform";
})(InputFlags || (InputFlags = {}));
const CUSTOM_ELEMENTS_SCHEMA = {
  name: 'custom-elements'
};
const NO_ERRORS_SCHEMA = {
  name: 'no-errors-schema'
};
const Type$1 = Function;
var MissingTranslationStrategy;
(function (MissingTranslationStrategy) {
  MissingTranslationStrategy[MissingTranslationStrategy["Error"] = 0] = "Error";
  MissingTranslationStrategy[MissingTranslationStrategy["Warning"] = 1] = "Warning";
  MissingTranslationStrategy[MissingTranslationStrategy["Ignore"] = 2] = "Ignore";
})(MissingTranslationStrategy || (MissingTranslationStrategy = {}));
function parserSelectorToSimpleSelector(selector) {
  const classes = selector.classNames && selector.classNames.length ? [8, ...selector.classNames] : [];
  const elementName = selector.element && selector.element !== '*' ? selector.element : '';
  return [elementName, ...selector.attrs, ...classes];
}
function parserSelectorToNegativeSelector(selector) {
  const classes = selector.classNames && selector.classNames.length ? [8, ...selector.classNames] : [];
  if (selector.element) {
    return [1 | 4, selector.element, ...selector.attrs, ...classes];
  } else if (selector.attrs.length) {
    return [1 | 2, ...selector.attrs, ...classes];
  } else {
    return selector.classNames && selector.classNames.length ? [1 | 8, ...selector.classNames] : [];
  }
}
function parserSelectorToR3Selector(selector) {
  const positive = parserSelectorToSimpleSelector(selector);
  const negative = selector.notSelectors && selector.notSelectors.length ? selector.notSelectors.map(notSelector => parserSelectorToNegativeSelector(notSelector)) : [];
  return positive.concat(...negative);
}
function parseSelectorToR3Selector(selector) {
  return selector ? CssSelector.parse(selector).map(parserSelectorToR3Selector) : [];
}

var core = /*#__PURE__*/Object.freeze({
    __proto__: null,
    CUSTOM_ELEMENTS_SCHEMA: CUSTOM_ELEMENTS_SCHEMA,
    get ChangeDetectionStrategy () { return ChangeDetectionStrategy; },
    get InputFlags () { return InputFlags; },
    get MissingTranslationStrategy () { return MissingTranslationStrategy; },
    NO_ERRORS_SCHEMA: NO_ERRORS_SCHEMA,
    get SecurityContext () { return SecurityContext; },
    Type: Type$1,
    get ViewEncapsulation () { return ViewEncapsulation$1; },
    emitDistinctChangesOnlyDefaultValue: emitDistinctChangesOnlyDefaultValue,
    parseSelectorToR3Selector: parseSelectorToR3Selector
});

var FactoryTarget;
(function (FactoryTarget) {
  FactoryTarget[FactoryTarget["Directive"] = 0] = "Directive";
  FactoryTarget[FactoryTarget["Component"] = 1] = "Component";
  FactoryTarget[FactoryTarget["Injectable"] = 2] = "Injectable";
  FactoryTarget[FactoryTarget["Pipe"] = 3] = "Pipe";
  FactoryTarget[FactoryTarget["NgModule"] = 4] = "NgModule";
  FactoryTarget[FactoryTarget["Service"] = 5] = "Service";
})(FactoryTarget || (FactoryTarget = {}));
var R3TemplateDependencyKind$1;
(function (R3TemplateDependencyKind) {
  R3TemplateDependencyKind[R3TemplateDependencyKind["Directive"] = 0] = "Directive";
  R3TemplateDependencyKind[R3TemplateDependencyKind["Pipe"] = 1] = "Pipe";
  R3TemplateDependencyKind[R3TemplateDependencyKind["NgModule"] = 2] = "NgModule";
})(R3TemplateDependencyKind$1 || (R3TemplateDependencyKind$1 = {}));
var ViewEncapsulation;
(function (ViewEncapsulation) {
  ViewEncapsulation[ViewEncapsulation["Emulated"] = 0] = "Emulated";
  ViewEncapsulation[ViewEncapsulation["None"] = 2] = "None";
  ViewEncapsulation[ViewEncapsulation["ShadowDom"] = 3] = "ShadowDom";
  ViewEncapsulation[ViewEncapsulation["ExperimentalIsolatedShadowDom"] = 4] = "ExperimentalIsolatedShadowDom";
})(ViewEncapsulation || (ViewEncapsulation = {}));

let textEncoder;
function digest$1(message) {
  return message.id || computeDigest(message);
}
function computeDigest(message) {
  return sha1(serializeNodes(message.nodes).join('') + `[${message.meaning}]`);
}
function decimalDigest(message) {
  return message.id || computeDecimalDigest(message);
}
function computeDecimalDigest(message) {
  const visitor = new _SerializerIgnoreIcuExpVisitor();
  const parts = message.nodes.map(a => a.visit(visitor, null));
  return computeMsgId(parts.join(''), message.meaning);
}
class _SerializerVisitor {
  visitText(text, context) {
    return text.value;
  }
  visitContainer(container, context) {
    return `[${container.children.map(child => child.visit(this)).join(', ')}]`;
  }
  visitIcu(icu, context) {
    const strCases = Object.keys(icu.cases).map(k => `${k} {${icu.cases[k].visit(this)}}`);
    return `{${icu.expression}, ${icu.type}, ${strCases.join(', ')}}`;
  }
  visitTagPlaceholder(ph, context) {
    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}">`;
  }
  visitPlaceholder(ph, context) {
    return ph.value ? `<ph name="${ph.name}">${ph.value}</ph>` : `<ph name="${ph.name}"/>`;
  }
  visitIcuPlaceholder(ph, context) {
    return `<ph icu name="${ph.name}">${ph.value.visit(this)}</ph>`;
  }
  visitBlockPlaceholder(ph, context) {
    return `<ph block name="${ph.startName}">${ph.children.map(child => child.visit(this)).join(', ')}</ph name="${ph.closeName}">`;
  }
}
const serializerVisitor$1 = new _SerializerVisitor();
function serializeNodes(nodes) {
  return nodes.map(a => a.visit(serializerVisitor$1, null));
}
class _SerializerIgnoreIcuExpVisitor extends _SerializerVisitor {
  visitIcu(icu) {
    let strCases = Object.keys(icu.cases).map(k => `${k} {${icu.cases[k].visit(this)}}`);
    return `{${icu.type}, ${strCases.join(', ')}}`;
  }
}
function sha1(str) {
  textEncoder ??= new TextEncoder();
  const utf8 = [...textEncoder.encode(str)];
  const words32 = bytesToWords32(utf8, Endian.Big);
  const len = utf8.length * 8;
  const w = new Uint32Array(80);
  let a = 0x67452301,
    b = 0xefcdab89,
    c = 0x98badcfe,
    d = 0x10325476,
    e = 0xc3d2e1f0;
  words32[len >> 5] |= 0x80 << 24 - len % 32;
  words32[(len + 64 >> 9 << 4) + 15] = len;
  for (let i = 0; i < words32.length; i += 16) {
    const h0 = a,
      h1 = b,
      h2 = c,
      h3 = d,
      h4 = e;
    for (let j = 0; j < 80; j++) {
      if (j < 16) {
        w[j] = words32[i + j];
      } else {
        w[j] = rol32(w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16], 1);
      }
      const fkVal = fk(j, b, c, d);
      const f = fkVal[0];
      const k = fkVal[1];
      const temp = [rol32(a, 5), f, e, k, w[j]].reduce(add32);
      e = d;
      d = c;
      c = rol32(b, 30);
      b = a;
      a = temp;
    }
    a = add32(a, h0);
    b = add32(b, h1);
    c = add32(c, h2);
    d = add32(d, h3);
    e = add32(e, h4);
  }
  return toHexU32(a) + toHexU32(b) + toHexU32(c) + toHexU32(d) + toHexU32(e);
}
function toHexU32(value) {
  return (value >>> 0).toString(16).padStart(8, '0');
}
function fk(index, b, c, d) {
  if (index < 20) {
    return [b & c | ~b & d, 0x5a827999];
  }
  if (index < 40) {
    return [b ^ c ^ d, 0x6ed9eba1];
  }
  if (index < 60) {
    return [b & c | b & d | c & d, 0x8f1bbcdc];
  }
  return [b ^ c ^ d, 0xca62c1d6];
}
function fingerprint(str) {
  textEncoder ??= new TextEncoder();
  const utf8 = textEncoder.encode(str);
  const view = new DataView(utf8.buffer, utf8.byteOffset, utf8.byteLength);
  let hi = hash32(view, utf8.length, 0);
  let lo = hash32(view, utf8.length, 102072);
  if (hi == 0 && (lo == 0 || lo == 1)) {
    hi = hi ^ 0x130f9bef;
    lo = lo ^ -1801410264;
  }
  return BigInt.asUintN(32, BigInt(hi)) << BigInt(32) | BigInt.asUintN(32, BigInt(lo));
}
function computeMsgId(msg, meaning = '') {
  let msgFingerprint = fingerprint(msg);
  if (meaning) {
    msgFingerprint = BigInt.asUintN(64, msgFingerprint << BigInt(1)) | msgFingerprint >> BigInt(63) & BigInt(1);
    msgFingerprint += fingerprint(meaning);
  }
  return BigInt.asUintN(63, msgFingerprint).toString();
}
function hash32(view, length, c) {
  let a = 0x9e3779b9,
    b = 0x9e3779b9;
  let index = 0;
  const end = length - 12;
  for (; index <= end; index += 12) {
    a += view.getUint32(index, true);
    b += view.getUint32(index + 4, true);
    c += view.getUint32(index + 8, true);
    const res = mix(a, b, c);
    a = res[0], b = res[1], c = res[2];
  }
  const remainder = length - index;
  c += length;
  if (remainder >= 4) {
    a += view.getUint32(index, true);
    index += 4;
    if (remainder >= 8) {
      b += view.getUint32(index, true);
      index += 4;
      if (remainder >= 9) {
        c += view.getUint8(index++) << 8;
      }
      if (remainder >= 10) {
        c += view.getUint8(index++) << 16;
      }
      if (remainder === 11) {
        c += view.getUint8(index++) << 24;
      }
    } else {
      if (remainder >= 5) {
        b += view.getUint8(index++);
      }
      if (remainder >= 6) {
        b += view.getUint8(index++) << 8;
      }
      if (remainder === 7) {
        b += view.getUint8(index++) << 16;
      }
    }
  } else {
    if (remainder >= 1) {
      a += view.getUint8(index++);
    }
    if (remainder >= 2) {
      a += view.getUint8(index++) << 8;
    }
    if (remainder === 3) {
      a += view.getUint8(index++) << 16;
    }
  }
  return mix(a, b, c)[2];
}
function mix(a, b, c) {
  a -= b;
  a -= c;
  a ^= c >>> 13;
  b -= c;
  b -= a;
  b ^= a << 8;
  c -= a;
  c -= b;
  c ^= b >>> 13;
  a -= b;
  a -= c;
  a ^= c >>> 12;
  b -= c;
  b -= a;
  b ^= a << 16;
  c -= a;
  c -= b;
  c ^= b >>> 5;
  a -= b;
  a -= c;
  a ^= c >>> 3;
  b -= c;
  b -= a;
  b ^= a << 10;
  c -= a;
  c -= b;
  c ^= b >>> 15;
  return [a, b, c];
}
var Endian;
(function (Endian) {
  Endian[Endian["Little"] = 0] = "Little";
  Endian[Endian["Big"] = 1] = "Big";
})(Endian || (Endian = {}));
function add32(a, b) {
  return add32to64(a, b)[1];
}
function add32to64(a, b) {
  const low = (a & 0xffff) + (b & 0xffff);
  const high = (a >>> 16) + (b >>> 16) + (low >>> 16);
  return [high >>> 16, high << 16 | low & 0xffff];
}
function rol32(a, count) {
  return a << count | a >>> 32 - count;
}
function bytesToWords32(bytes, endian) {
  const size = bytes.length + 3 >>> 2;
  const words32 = [];
  for (let i = 0; i < size; i++) {
    words32[i] = wordAt(bytes, i * 4, endian);
  }
  return words32;
}
function byteAt(bytes, index) {
  return index >= bytes.length ? 0 : bytes[index];
}
function wordAt(bytes, index, endian) {
  let word = 0;
  if (endian === Endian.Big) {
    for (let i = 0; i < 4; i++) {
      word += byteAt(bytes, index + i) << 24 - 8 * i;
    }
  } else {
    for (let i = 0; i < 4; i++) {
      word += byteAt(bytes, index + i) << 8 * i;
    }
  }
  return word;
}

var TypeModifier;
(function (TypeModifier) {
  TypeModifier[TypeModifier["None"] = 0] = "None";
  TypeModifier[TypeModifier["Const"] = 1] = "Const";
})(TypeModifier || (TypeModifier = {}));
class Type {
  modifiers;
  constructor(modifiers = TypeModifier.None) {
    this.modifiers = modifiers;
  }
  hasModifier(modifier) {
    return (this.modifiers & modifier) !== 0;
  }
}
var BuiltinTypeName;
(function (BuiltinTypeName) {
  BuiltinTypeName[BuiltinTypeName["Dynamic"] = 0] = "Dynamic";
  BuiltinTypeName[BuiltinTypeName["Bool"] = 1] = "Bool";
  BuiltinTypeName[BuiltinTypeName["String"] = 2] = "String";
  BuiltinTypeName[BuiltinTypeName["Int"] = 3] = "Int";
  BuiltinTypeName[BuiltinTypeName["Number"] = 4] = "Number";
  BuiltinTypeName[BuiltinTypeName["Function"] = 5] = "Function";
  BuiltinTypeName[BuiltinTypeName["Inferred"] = 6] = "Inferred";
  BuiltinTypeName[BuiltinTypeName["None"] = 7] = "None";
})(BuiltinTypeName || (BuiltinTypeName = {}));
class BuiltinType extends Type {
  name;
  constructor(name, modifiers) {
    super(modifiers);
    this.name = name;
  }
  visitType(visitor, context) {
    return visitor.visitBuiltinType(this, context);
  }
}
class ExpressionType extends Type {
  value;
  typeParams;
  constructor(value, modifiers, typeParams = null) {
    super(modifiers);
    this.value = value;
    this.typeParams = typeParams;
  }
  visitType(visitor, context) {
    return visitor.visitExpressionType(this, context);
  }
}
class ArrayType extends Type {
  of;
  constructor(of, modifiers) {
    super(modifiers);
    this.of = of;
  }
  visitType(visitor, context) {
    return visitor.visitArrayType(this, context);
  }
}
class MapType extends Type {
  valueType;
  constructor(valueType, modifiers) {
    super(modifiers);
    this.valueType = valueType || null;
  }
  visitType(visitor, context) {
    return visitor.visitMapType(this, context);
  }
}
class TransplantedType extends Type {
  type;
  constructor(type, modifiers) {
    super(modifiers);
    this.type = type;
  }
  visitType(visitor, context) {
    return visitor.visitTransplantedType(this, context);
  }
}
const DYNAMIC_TYPE = new BuiltinType(BuiltinTypeName.Dynamic);
const INFERRED_TYPE = new BuiltinType(BuiltinTypeName.Inferred);
const BOOL_TYPE = new BuiltinType(BuiltinTypeName.Bool);
const INT_TYPE = new BuiltinType(BuiltinTypeName.Int);
const NUMBER_TYPE = new BuiltinType(BuiltinTypeName.Number);
const STRING_TYPE = new BuiltinType(BuiltinTypeName.String);
const FUNCTION_TYPE = new BuiltinType(BuiltinTypeName.Function);
const NONE_TYPE = new BuiltinType(BuiltinTypeName.None);
var UnaryOperator;
(function (UnaryOperator) {
  UnaryOperator[UnaryOperator["Minus"] = 0] = "Minus";
  UnaryOperator[UnaryOperator["Plus"] = 1] = "Plus";
})(UnaryOperator || (UnaryOperator = {}));
var BinaryOperator;
(function (BinaryOperator) {
  BinaryOperator[BinaryOperator["Equals"] = 0] = "Equals";
  BinaryOperator[BinaryOperator["NotEquals"] = 1] = "NotEquals";
  BinaryOperator[BinaryOperator["Assign"] = 2] = "Assign";
  BinaryOperator[BinaryOperator["Identical"] = 3] = "Identical";
  BinaryOperator[BinaryOperator["NotIdentical"] = 4] = "NotIdentical";
  BinaryOperator[BinaryOperator["Minus"] = 5] = "Minus";
  BinaryOperator[BinaryOperator["Plus"] = 6] = "Plus";
  BinaryOperator[BinaryOperator["Divide"] = 7] = "Divide";
  BinaryOperator[BinaryOperator["Multiply"] = 8] = "Multiply";
  BinaryOperator[BinaryOperator["Modulo"] = 9] = "Modulo";
  BinaryOperator[BinaryOperator["And"] = 10] = "And";
  BinaryOperator[BinaryOperator["Or"] = 11] = "Or";
  BinaryOperator[BinaryOperator["BitwiseOr"] = 12] = "BitwiseOr";
  BinaryOperator[BinaryOperator["BitwiseAnd"] = 13] = "BitwiseAnd";
  BinaryOperator[BinaryOperator["Lower"] = 14] = "Lower";
  BinaryOperator[BinaryOperator["LowerEquals"] = 15] = "LowerEquals";
  BinaryOperator[BinaryOperator["Bigger"] = 16] = "Bigger";
  BinaryOperator[BinaryOperator["BiggerEquals"] = 17] = "BiggerEquals";
  BinaryOperator[BinaryOperator["NullishCoalesce"] = 18] = "NullishCoalesce";
  BinaryOperator[BinaryOperator["Exponentiation"] = 19] = "Exponentiation";
  BinaryOperator[BinaryOperator["In"] = 20] = "In";
  BinaryOperator[BinaryOperator["InstanceOf"] = 21] = "InstanceOf";
  BinaryOperator[BinaryOperator["AdditionAssignment"] = 22] = "AdditionAssignment";
  BinaryOperator[BinaryOperator["SubtractionAssignment"] = 23] = "SubtractionAssignment";
  BinaryOperator[BinaryOperator["MultiplicationAssignment"] = 24] = "MultiplicationAssignment";
  BinaryOperator[BinaryOperator["DivisionAssignment"] = 25] = "DivisionAssignment";
  BinaryOperator[BinaryOperator["RemainderAssignment"] = 26] = "RemainderAssignment";
  BinaryOperator[BinaryOperator["ExponentiationAssignment"] = 27] = "ExponentiationAssignment";
  BinaryOperator[BinaryOperator["AndAssignment"] = 28] = "AndAssignment";
  BinaryOperator[BinaryOperator["OrAssignment"] = 29] = "OrAssignment";
  BinaryOperator[BinaryOperator["NullishCoalesceAssignment"] = 30] = "NullishCoalesceAssignment";
})(BinaryOperator || (BinaryOperator = {}));
function nullSafeIsEquivalent(base, other) {
  if (base == null || other == null) {
    return base == other;
  }
  return base.isEquivalent(other);
}
function areAllEquivalentPredicate(base, other, equivalentPredicate) {
  const len = base.length;
  if (len !== other.length) {
    return false;
  }
  for (let i = 0; i < len; i++) {
    if (!equivalentPredicate(base[i], other[i])) {
      return false;
    }
  }
  return true;
}
function areAllEquivalent(base, other) {
  return areAllEquivalentPredicate(base, other, (baseElement, otherElement) => baseElement.isEquivalent(otherElement));
}
class Expression {
  leadingComments;
  type;
  sourceSpan;
  constructor(type, sourceSpan, leadingComments) {
    this.leadingComments = leadingComments;
    this.type = type || null;
    this.sourceSpan = sourceSpan || null;
  }
  prop(name, sourceSpan) {
    return new ReadPropExpr(this, name, null, sourceSpan);
  }
  key(index, type, sourceSpan) {
    return new ReadKeyExpr(this, index, type, sourceSpan);
  }
  callFn(params, sourceSpan, pure, leadingComments) {
    return new InvokeFunctionExpr(this, params, null, sourceSpan, pure, leadingComments);
  }
  instantiate(params, type, sourceSpan, leadingComments) {
    return new InstantiateExpr(this, params, type, sourceSpan);
  }
  conditional(trueCase, falseCase = null, sourceSpan, leadingComments) {
    return new ConditionalExpr(this, trueCase, falseCase, null, sourceSpan);
  }
  equals(rhs, sourceSpan) {
    return new BinaryOperatorExpr(BinaryOperator.Equals, this, rhs, null, sourceSpan);
  }
  notEquals(rhs, sourceSpan) {
    return new BinaryOperatorExpr(BinaryOperator.NotEquals, this, rhs, null, sourceSpan);
  }
  identical(rhs, sourceSpan) {
    return new BinaryOperatorExpr(BinaryOperator.Identical, this, rhs, null, sourceSpan);
  }
  notIdentical(rhs, sourceSpan) {
    return new BinaryOperatorExpr(BinaryOperator.NotIdentical, this, rhs, null, sourceSpan);
  }
  minus(rhs, sourceSpan) {
    return new BinaryOperatorExpr(BinaryOperator.Minus, this, rhs, null, sourceSpan);
  }
  plus(rhs, sourceSpan) {
    return new BinaryOperatorExpr(BinaryOperator.Plus, this, rhs, null, sourceSpan);
  }
  divide(rhs, sourceSpan) {
    return new BinaryOperatorExpr(BinaryOperator.Divide, this, rhs, null, sourceSpan);
  }
  multiply(rhs, sourceSpan) {
    return new BinaryOperatorExpr(BinaryOperator.Multiply, this, rhs, null, sourceSpan);
  }
  modulo(rhs, sourceSpan) {
    return new BinaryOperatorExpr(BinaryOperator.Modulo, this, rhs, null, sourceSpan);
  }
  power(rhs, sourceSpan) {
    return new BinaryOperatorExpr(BinaryOperator.Exponentiation, this, rhs, null, sourceSpan);
  }
  and(rhs, sourceSpan) {
    return new BinaryOperatorExpr(BinaryOperator.And, this, rhs, null, sourceSpan);
  }
  bitwiseOr(rhs, sourceSpan) {
    return new BinaryOperatorExpr(BinaryOperator.BitwiseOr, this, rhs, null, sourceSpan);
  }
  bitwiseAnd(rhs, sourceSpan) {
    return new BinaryOperatorExpr(BinaryOperator.BitwiseAnd, this, rhs, null, sourceSpan);
  }
  or(rhs, sourceSpan) {
    return new BinaryOperatorExpr(BinaryOperator.Or, this, rhs, null, sourceSpan);
  }
  lower(rhs, sourceSpan) {
    return new BinaryOperatorExpr(BinaryOperator.Lower, this, rhs, null, sourceSpan);
  }
  lowerEquals(rhs, sourceSpan) {
    return new BinaryOperatorExpr(BinaryOperator.LowerEquals, this, rhs, null, sourceSpan);
  }
  bigger(rhs, sourceSpan) {
    return new BinaryOperatorExpr(BinaryOperator.Bigger, this, rhs, null, sourceSpan);
  }
  biggerEquals(rhs, sourceSpan) {
    return new BinaryOperatorExpr(BinaryOperator.BiggerEquals, this, rhs, null, sourceSpan);
  }
  isBlank(sourceSpan) {
    return this.equals(TYPED_NULL_EXPR, sourceSpan);
  }
  nullishCoalesce(rhs, sourceSpan) {
    return new BinaryOperatorExpr(BinaryOperator.NullishCoalesce, this, rhs, null, sourceSpan);
  }
  toStmt(leadingComments) {
    return new ExpressionStatement(this, null, leadingComments);
  }
}
class ReadVarExpr extends Expression {
  name;
  constructor(name, type, sourceSpan, leadingComments) {
    super(type, sourceSpan, leadingComments);
    this.name = name;
  }
  isEquivalent(e) {
    return e instanceof ReadVarExpr && this.name === e.name;
  }
  isConstant() {
    return false;
  }
  visitExpression(visitor, context) {
    return visitor.visitReadVarExpr(this, context);
  }
  clone() {
    return new ReadVarExpr(this.name, this.type, this.sourceSpan);
  }
  set(value) {
    return new BinaryOperatorExpr(BinaryOperator.Assign, this, value, null, this.sourceSpan);
  }
}
class TypeofExpr extends Expression {
  expr;
  constructor(expr, type, sourceSpan, leadingComments) {
    super(type, sourceSpan, leadingComments);
    this.expr = expr;
  }
  visitExpression(visitor, context) {
    return visitor.visitTypeofExpr(this, context);
  }
  isEquivalent(e) {
    return e instanceof TypeofExpr && e.expr.isEquivalent(this.expr);
  }
  isConstant() {
    return this.expr.isConstant();
  }
  clone() {
    return new TypeofExpr(this.expr.clone());
  }
}
class VoidExpr extends Expression {
  expr;
  constructor(expr, type, sourceSpan, leadingComments) {
    super(type, sourceSpan, leadingComments);
    this.expr = expr;
  }
  visitExpression(visitor, context) {
    return visitor.visitVoidExpr(this, context);
  }
  isEquivalent(e) {
    return e instanceof VoidExpr && e.expr.isEquivalent(this.expr);
  }
  isConstant() {
    return this.expr.isConstant();
  }
  clone() {
    return new VoidExpr(this.expr.clone());
  }
}
class WrappedNodeExpr extends Expression {
  node;
  constructor(node, type, sourceSpan, leadingComments) {
    super(type, sourceSpan, leadingComments);
    this.node = node;
  }
  isEquivalent(e) {
    return e instanceof WrappedNodeExpr && this.node === e.node;
  }
  isConstant() {
    return false;
  }
  visitExpression(visitor, context) {
    return visitor.visitWrappedNodeExpr(this, context);
  }
  clone() {
    return new WrappedNodeExpr(this.node, this.type, this.sourceSpan);
  }
}
class InvokeFunctionExpr extends Expression {
  fn;
  args;
  pure;
  isOptional;
  constructor(fn, args, type, sourceSpan, pure = false, leadingComments, isOptional = false) {
    super(type, sourceSpan, leadingComments);
    this.fn = fn;
    this.args = args;
    this.pure = pure;
    this.isOptional = isOptional;
  }
  get receiver() {
    return this.fn;
  }
  isEquivalent(e) {
    return e instanceof InvokeFunctionExpr && this.fn.isEquivalent(e.fn) && areAllEquivalent(this.args, e.args) && this.pure === e.pure;
  }
  isConstant() {
    return false;
  }
  visitExpression(visitor, context) {
    return visitor.visitInvokeFunctionExpr(this, context);
  }
  clone() {
    return new InvokeFunctionExpr(this.fn.clone(), this.args.map(arg => arg.clone()), this.type, this.sourceSpan, this.pure, [], this.isOptional);
  }
}
class TaggedTemplateLiteralExpr extends Expression {
  tag;
  template;
  constructor(tag, template, type, sourceSpan, leadingComments) {
    super(type, sourceSpan, leadingComments);
    this.tag = tag;
    this.template = template;
  }
  isEquivalent(e) {
    return e instanceof TaggedTemplateLiteralExpr && this.tag.isEquivalent(e.tag) && this.template.isEquivalent(e.template);
  }
  isConstant() {
    return false;
  }
  visitExpression(visitor, context) {
    return visitor.visitTaggedTemplateLiteralExpr(this, context);
  }
  clone() {
    return new TaggedTemplateLiteralExpr(this.tag.clone(), this.template.clone(), this.type, this.sourceSpan);
  }
}
class InstantiateExpr extends Expression {
  classExpr;
  args;
  constructor(classExpr, args, type, sourceSpan, leadingComments) {
    super(type, sourceSpan, leadingComments);
    this.classExpr = classExpr;
    this.args = args;
  }
  isEquivalent(e) {
    return e instanceof InstantiateExpr && this.classExpr.isEquivalent(e.classExpr) && areAllEquivalent(this.args, e.args);
  }
  isConstant() {
    return false;
  }
  visitExpression(visitor, context) {
    return visitor.visitInstantiateExpr(this, context);
  }
  clone() {
    return new InstantiateExpr(this.classExpr.clone(), this.args.map(arg => arg.clone()), this.type, this.sourceSpan);
  }
}
class RegularExpressionLiteralExpr extends Expression {
  body;
  flags;
  constructor(body, flags, sourceSpan, leadingComments) {
    super(null, sourceSpan, leadingComments);
    this.body = body;
    this.flags = flags;
  }
  isEquivalent(e) {
    return e instanceof RegularExpressionLiteralExpr && this.body === e.body && this.flags === e.flags;
  }
  isConstant() {
    return true;
  }
  visitExpression(visitor, context) {
    return visitor.visitRegularExpressionLiteral(this, context);
  }
  clone() {
    return new RegularExpressionLiteralExpr(this.body, this.flags, this.sourceSpan);
  }
}
class LiteralExpr extends Expression {
  value;
  constructor(value, type, sourceSpan, leadingComments) {
    super(type, sourceSpan, leadingComments);
    this.value = value;
  }
  isEquivalent(e) {
    return e instanceof LiteralExpr && this.value === e.value;
  }
  isConstant() {
    return true;
  }
  visitExpression(visitor, context) {
    return visitor.visitLiteralExpr(this, context);
  }
  clone() {
    return new LiteralExpr(this.value, this.type, this.sourceSpan);
  }
}
class TemplateLiteralExpr extends Expression {
  elements;
  expressions;
  constructor(elements, expressions, sourceSpan, leadingComments) {
    super(null, sourceSpan, leadingComments);
    this.elements = elements;
    this.expressions = expressions;
  }
  isEquivalent(e) {
    return e instanceof TemplateLiteralExpr && areAllEquivalentPredicate(this.elements, e.elements, (a, b) => a.text === b.text) && areAllEquivalent(this.expressions, e.expressions);
  }
  isConstant() {
    return false;
  }
  visitExpression(visitor, context) {
    return visitor.visitTemplateLiteralExpr(this, context);
  }
  clone() {
    return new TemplateLiteralExpr(this.elements.map(el => el.clone()), this.expressions.map(expr => expr.clone()));
  }
}
class TemplateLiteralElementExpr extends Expression {
  text;
  rawText;
  constructor(text, sourceSpan, rawText, leadingComments) {
    super(STRING_TYPE, sourceSpan, leadingComments);
    this.text = text;
    this.rawText = rawText ?? escapeForTemplateLiteral(escapeSlashes(text));
  }
  visitExpression(visitor, context) {
    return visitor.visitTemplateLiteralElementExpr(this, context);
  }
  isEquivalent(e) {
    return e instanceof TemplateLiteralElementExpr && e.text === this.text && e.rawText === this.rawText;
  }
  isConstant() {
    return true;
  }
  clone() {
    return new TemplateLiteralElementExpr(this.text, this.sourceSpan, this.rawText);
  }
}
class LiteralPiece {
  text;
  sourceSpan;
  constructor(text, sourceSpan) {
    this.text = text;
    this.sourceSpan = sourceSpan;
  }
}
class PlaceholderPiece {
  text;
  sourceSpan;
  associatedMessage;
  constructor(text, sourceSpan, associatedMessage) {
    this.text = text;
    this.sourceSpan = sourceSpan;
    this.associatedMessage = associatedMessage;
  }
}
const MEANING_SEPARATOR$1 = '|';
const ID_SEPARATOR$1 = '@@';
const LEGACY_ID_INDICATOR = '␟';
class LocalizedString extends Expression {
  metaBlock;
  messageParts;
  placeHolderNames;
  expressions;
  constructor(metaBlock, messageParts, placeHolderNames, expressions, sourceSpan, leadingComments) {
    super(STRING_TYPE, sourceSpan, leadingComments);
    this.metaBlock = metaBlock;
    this.messageParts = messageParts;
    this.placeHolderNames = placeHolderNames;
    this.expressions = expressions;
  }
  isEquivalent(e) {
    return false;
  }
  isConstant() {
    return false;
  }
  visitExpression(visitor, context) {
    return visitor.visitLocalizedString(this, context);
  }
  clone() {
    return new LocalizedString(this.metaBlock, this.messageParts, this.placeHolderNames, this.expressions.map(expr => expr.clone()), this.sourceSpan);
  }
  serializeI18nHead() {
    let metaBlock = this.metaBlock.description || '';
    if (this.metaBlock.meaning) {
      metaBlock = `${this.metaBlock.meaning}${MEANING_SEPARATOR$1}${metaBlock}`;
    }
    if (this.metaBlock.customId) {
      metaBlock = `${metaBlock}${ID_SEPARATOR$1}${this.metaBlock.customId}`;
    }
    if (this.metaBlock.legacyIds) {
      this.metaBlock.legacyIds.forEach(legacyId => {
        metaBlock = `${metaBlock}${LEGACY_ID_INDICATOR}${legacyId}`;
      });
    }
    return createCookedRawString(metaBlock, this.messageParts[0].text, this.getMessagePartSourceSpan(0));
  }
  getMessagePartSourceSpan(i) {
    return this.messageParts[i]?.sourceSpan ?? this.sourceSpan;
  }
  getPlaceholderSourceSpan(i) {
    return this.placeHolderNames[i]?.sourceSpan ?? this.expressions[i]?.sourceSpan ?? this.sourceSpan;
  }
  serializeI18nTemplatePart(partIndex) {
    const placeholder = this.placeHolderNames[partIndex - 1];
    const messagePart = this.messageParts[partIndex];
    let metaBlock = placeholder.text;
    if (placeholder.associatedMessage?.legacyIds.length === 0) {
      metaBlock += `${ID_SEPARATOR$1}${computeMsgId(placeholder.associatedMessage.messageString, placeholder.associatedMessage.meaning)}`;
    }
    return createCookedRawString(metaBlock, messagePart.text, this.getMessagePartSourceSpan(partIndex));
  }
}
const escapeSlashes = str => str.replace(/\\/g, '\\\\');
const escapeStartingColon = str => str.replace(/^:/, '\\:');
const escapeColons = str => str.replace(/:/g, '\\:');
const escapeForTemplateLiteral = str => str.replace(/`/g, '\\`').replace(/\${/g, '$\\{');
function createCookedRawString(metaBlock, messagePart, range) {
  if (metaBlock === '') {
    return {
      cooked: messagePart,
      raw: escapeForTemplateLiteral(escapeStartingColon(escapeSlashes(messagePart))),
      range
    };
  } else {
    return {
      cooked: `:${metaBlock}:${messagePart}`,
      raw: escapeForTemplateLiteral(`:${escapeColons(escapeSlashes(metaBlock))}:${escapeSlashes(messagePart)}`),
      range
    };
  }
}
class ExternalExpr extends Expression {
  value;
  typeParams;
  constructor(value, type, typeParams = null, sourceSpan, leadingComments) {
    super(type, sourceSpan, leadingComments);
    this.value = value;
    this.typeParams = typeParams;
  }
  isEquivalent(e) {
    return e instanceof ExternalExpr && this.value.name === e.value.name && this.value.moduleName === e.value.moduleName;
  }
  isConstant() {
    return false;
  }
  visitExpression(visitor, context) {
    return visitor.visitExternalExpr(this, context);
  }
  clone() {
    return new ExternalExpr(this.value, this.type, this.typeParams, this.sourceSpan);
  }
}
class ExternalReference {
  moduleName;
  name;
  constructor(moduleName, name) {
    this.moduleName = moduleName;
    this.name = name;
  }
}
class ConditionalExpr extends Expression {
  condition;
  falseCase;
  trueCase;
  constructor(condition, trueCase, falseCase = null, type, sourceSpan, leadingComments) {
    super(type || trueCase.type, sourceSpan, leadingComments);
    this.condition = condition;
    this.falseCase = falseCase;
    this.trueCase = trueCase;
  }
  isEquivalent(e) {
    return e instanceof ConditionalExpr && this.condition.isEquivalent(e.condition) && this.trueCase.isEquivalent(e.trueCase) && nullSafeIsEquivalent(this.falseCase, e.falseCase);
  }
  isConstant() {
    return false;
  }
  visitExpression(visitor, context) {
    return visitor.visitConditionalExpr(this, context);
  }
  clone() {
    return new ConditionalExpr(this.condition.clone(), this.trueCase.clone(), this.falseCase?.clone(), this.type, this.sourceSpan);
  }
}
class DynamicImportExpr extends Expression {
  url;
  urlComment;
  constructor(url, sourceSpan, urlComment, leadingComments) {
    super(null, sourceSpan, leadingComments);
    this.url = url;
    this.urlComment = urlComment;
  }
  isEquivalent(e) {
    return e instanceof DynamicImportExpr && this.url === e.url && this.urlComment === e.urlComment;
  }
  isConstant() {
    return false;
  }
  visitExpression(visitor, context) {
    return visitor.visitDynamicImportExpr(this, context);
  }
  clone() {
    return new DynamicImportExpr(typeof this.url === 'string' ? this.url : this.url.clone(), this.sourceSpan, this.urlComment);
  }
}
class NotExpr extends Expression {
  condition;
  constructor(condition, sourceSpan, leadingComments) {
    super(BOOL_TYPE, sourceSpan, leadingComments);
    this.condition = condition;
  }
  isEquivalent(e) {
    return e instanceof NotExpr && this.condition.isEquivalent(e.condition);
  }
  isConstant() {
    return false;
  }
  visitExpression(visitor, context) {
    return visitor.visitNotExpr(this, context);
  }
  clone() {
    return new NotExpr(this.condition.clone(), this.sourceSpan);
  }
}
class FnParam {
  name;
  type;
  constructor(name, type = null) {
    this.name = name;
    this.type = type;
  }
  isEquivalent(param) {
    return this.name === param.name;
  }
  clone() {
    return new FnParam(this.name, this.type);
  }
}
class FunctionExpr extends Expression {
  params;
  statements;
  name;
  constructor(params, statements, type, sourceSpan, name, leadingComments) {
    super(type, sourceSpan, leadingComments);
    this.params = params;
    this.statements = statements;
    this.name = name;
  }
  isEquivalent(e) {
    return (e instanceof FunctionExpr || e instanceof DeclareFunctionStmt) && areAllEquivalent(this.params, e.params) && areAllEquivalent(this.statements, e.statements);
  }
  isConstant() {
    return false;
  }
  visitExpression(visitor, context) {
    return visitor.visitFunctionExpr(this, context);
  }
  toDeclStmt(name, modifiers) {
    return new DeclareFunctionStmt(name, this.params, this.statements, this.type, modifiers, this.sourceSpan);
  }
  clone() {
    return new FunctionExpr(this.params.map(p => p.clone()), this.statements, this.type, this.sourceSpan, this.name);
  }
}
let ArrowFunctionExpr$1 = class ArrowFunctionExpr extends Expression {
  params;
  body;
  constructor(params, body, type, sourceSpan, leadingComments) {
    super(type, sourceSpan, leadingComments);
    this.params = params;
    this.body = body;
  }
  isEquivalent(e) {
    if (!(e instanceof ArrowFunctionExpr) || !areAllEquivalent(this.params, e.params)) {
      return false;
    }
    if (this.body instanceof Expression && e.body instanceof Expression) {
      return this.body.isEquivalent(e.body);
    }
    if (Array.isArray(this.body) && Array.isArray(e.body)) {
      return areAllEquivalent(this.body, e.body);
    }
    return false;
  }
  isConstant() {
    return false;
  }
  visitExpression(visitor, context) {
    return visitor.visitArrowFunctionExpr(this, context);
  }
  clone() {
    return new ArrowFunctionExpr(this.params.map(p => p.clone()), Array.isArray(this.body) ? this.body : this.body.clone(), this.type, this.sourceSpan);
  }
  toDeclStmt(name, modifiers) {
    return new DeclareVarStmt(name, this, INFERRED_TYPE, modifiers, this.sourceSpan);
  }
};
class UnaryOperatorExpr extends Expression {
  operator;
  expr;
  parens;
  constructor(operator, expr, type, sourceSpan, parens = true, leadingComments) {
    super(type || NUMBER_TYPE, sourceSpan, leadingComments);
    this.operator = operator;
    this.expr = expr;
    this.parens = parens;
  }
  isEquivalent(e) {
    return e instanceof UnaryOperatorExpr && this.operator === e.operator && this.expr.isEquivalent(e.expr);
  }
  isConstant() {
    return false;
  }
  visitExpression(visitor, context) {
    return visitor.visitUnaryOperatorExpr(this, context);
  }
  clone() {
    return new UnaryOperatorExpr(this.operator, this.expr.clone(), this.type, this.sourceSpan, this.parens);
  }
}
class ParenthesizedExpr extends Expression {
  expr;
  constructor(expr, type, sourceSpan, leadingComments) {
    super(type, sourceSpan, leadingComments);
    this.expr = expr;
  }
  visitExpression(visitor, context) {
    return visitor.visitParenthesizedExpr(this, context);
  }
  isEquivalent(e) {
    return e instanceof ParenthesizedExpr && e.expr.isEquivalent(this.expr);
  }
  isConstant() {
    return this.expr.isConstant();
  }
  clone() {
    return new ParenthesizedExpr(this.expr.clone());
  }
}
class BinaryOperatorExpr extends Expression {
  operator;
  rhs;
  lhs;
  constructor(operator, lhs, rhs, type, sourceSpan, leadingComments) {
    super(type || lhs.type, sourceSpan, leadingComments);
    this.operator = operator;
    this.rhs = rhs;
    this.lhs = lhs;
  }
  isEquivalent(e) {
    return e instanceof BinaryOperatorExpr && this.operator === e.operator && this.lhs.isEquivalent(e.lhs) && this.rhs.isEquivalent(e.rhs);
  }
  isConstant() {
    return false;
  }
  visitExpression(visitor, context) {
    return visitor.visitBinaryOperatorExpr(this, context);
  }
  clone() {
    return new BinaryOperatorExpr(this.operator, this.lhs.clone(), this.rhs.clone(), this.type, this.sourceSpan);
  }
  isAssignment() {
    const op = this.operator;
    return op === BinaryOperator.Assign || op === BinaryOperator.AdditionAssignment || op === BinaryOperator.SubtractionAssignment || op === BinaryOperator.MultiplicationAssignment || op === BinaryOperator.DivisionAssignment || op === BinaryOperator.RemainderAssignment || op === BinaryOperator.ExponentiationAssignment || op === BinaryOperator.AndAssignment || op === BinaryOperator.OrAssignment || op === BinaryOperator.NullishCoalesceAssignment;
  }
}
class ReadPropExpr extends Expression {
  receiver;
  name;
  isOptional;
  constructor(receiver, name, type, sourceSpan, leadingComments, isOptional = false) {
    super(type, sourceSpan, leadingComments);
    this.receiver = receiver;
    this.name = name;
    this.isOptional = isOptional;
  }
  get index() {
    return this.name;
  }
  isEquivalent(e) {
    return e instanceof ReadPropExpr && this.receiver.isEquivalent(e.receiver) && this.name === e.name && this.isOptional === e.isOptional;
  }
  isConstant() {
    return false;
  }
  visitExpression(visitor, context) {
    return visitor.visitReadPropExpr(this, context);
  }
  set(value) {
    return new BinaryOperatorExpr(BinaryOperator.Assign, this.receiver.prop(this.name), value, null, this.sourceSpan);
  }
  clone() {
    return new ReadPropExpr(this.receiver.clone(), this.name, this.type, this.sourceSpan, [], this.isOptional);
  }
}
class ReadKeyExpr extends Expression {
  receiver;
  index;
  isOptional;
  constructor(receiver, index, type, sourceSpan, leadingComments, isOptional = false) {
    super(type, sourceSpan, leadingComments);
    this.receiver = receiver;
    this.index = index;
    this.isOptional = isOptional;
  }
  isEquivalent(e) {
    return e instanceof ReadKeyExpr && this.receiver.isEquivalent(e.receiver) && this.index.isEquivalent(e.index) && this.isOptional === e.isOptional;
  }
  isConstant() {
    return false;
  }
  visitExpression(visitor, context) {
    return visitor.visitReadKeyExpr(this, context);
  }
  set(value) {
    return new BinaryOperatorExpr(BinaryOperator.Assign, this.receiver.key(this.index), value, null, this.sourceSpan);
  }
  clone() {
    return new ReadKeyExpr(this.receiver.clone(), this.index.clone(), this.type, this.sourceSpan, [], this.isOptional);
  }
}
class LiteralArrayExpr extends Expression {
  entries;
  constructor(entries, type, sourceSpan, leadingComments) {
    super(type, sourceSpan, leadingComments);
    this.entries = entries;
  }
  isConstant() {
    return this.entries.every(e => e.isConstant());
  }
  isEquivalent(e) {
    return e instanceof LiteralArrayExpr && areAllEquivalent(this.entries, e.entries);
  }
  visitExpression(visitor, context) {
    return visitor.visitLiteralArrayExpr(this, context);
  }
  clone() {
    return new LiteralArrayExpr(this.entries.map(e => e.clone()), this.type, this.sourceSpan);
  }
}
class LiteralMapPropertyAssignment {
  key;
  value;
  quoted;
  constructor(key, value, quoted) {
    this.key = key;
    this.value = value;
    this.quoted = quoted;
  }
  isEquivalent(e) {
    return this.key === e.key && this.value.isEquivalent(e.value);
  }
  clone() {
    return new LiteralMapPropertyAssignment(this.key, this.value.clone(), this.quoted);
  }
  isConstant() {
    return this.value.isConstant();
  }
}
class LiteralMapSpreadAssignment {
  expression;
  constructor(expression) {
    this.expression = expression;
  }
  isEquivalent(e) {
    return e instanceof LiteralMapSpreadAssignment && this.expression.isEquivalent(e.expression);
  }
  clone() {
    return new LiteralMapSpreadAssignment(this.expression.clone());
  }
  isConstant() {
    return this.expression.isConstant();
  }
}
class LiteralMapExpr extends Expression {
  entries;
  valueType = null;
  constructor(entries, type, sourceSpan, leadingComments) {
    super(type, sourceSpan, leadingComments);
    this.entries = entries;
    if (type) {
      this.valueType = type.valueType;
    }
  }
  isEquivalent(e) {
    return e instanceof LiteralMapExpr && areAllEquivalent(this.entries, e.entries);
  }
  isConstant() {
    return this.entries.every(e => e.isConstant());
  }
  visitExpression(visitor, context) {
    return visitor.visitLiteralMapExpr(this, context);
  }
  clone() {
    const entriesClone = this.entries.map(entry => entry.clone());
    return new LiteralMapExpr(entriesClone, this.type, this.sourceSpan);
  }
}
class CommaExpr extends Expression {
  parts;
  constructor(parts, sourceSpan, leadingComments) {
    super(parts[parts.length - 1].type, sourceSpan, leadingComments);
    this.parts = parts;
  }
  isEquivalent(e) {
    return e instanceof CommaExpr && areAllEquivalent(this.parts, e.parts);
  }
  isConstant() {
    return false;
  }
  visitExpression(visitor, context) {
    return visitor.visitCommaExpr(this, context);
  }
  clone() {
    return new CommaExpr(this.parts.map(p => p.clone()));
  }
}
class SpreadElementExpr extends Expression {
  expression;
  constructor(expression, sourceSpan, leadingComments) {
    super(null, sourceSpan, leadingComments);
    this.expression = expression;
  }
  isEquivalent(e) {
    return e instanceof SpreadElementExpr && this.expression.isEquivalent(e.expression);
  }
  isConstant() {
    return this.expression.isConstant();
  }
  visitExpression(visitor, context) {
    return visitor.visitSpreadElementExpr(this, context);
  }
  clone() {
    return new SpreadElementExpr(this.expression.clone(), this.sourceSpan);
  }
}
const NULL_EXPR = new LiteralExpr(null, null, null);
const TYPED_NULL_EXPR = new LiteralExpr(null, INFERRED_TYPE, null);
var StmtModifier;
(function (StmtModifier) {
  StmtModifier[StmtModifier["None"] = 0] = "None";
  StmtModifier[StmtModifier["Final"] = 1] = "Final";
  StmtModifier[StmtModifier["Private"] = 2] = "Private";
  StmtModifier[StmtModifier["Exported"] = 4] = "Exported";
  StmtModifier[StmtModifier["Static"] = 8] = "Static";
})(StmtModifier || (StmtModifier = {}));
class LeadingComment {
  text;
  multiline;
  trailingNewline;
  constructor(text, multiline, trailingNewline) {
    this.text = text;
    this.multiline = multiline;
    this.trailingNewline = trailingNewline;
  }
  toString() {
    return this.multiline ? ` ${this.text} ` : this.text;
  }
}
class JSDocComment extends LeadingComment {
  tags;
  constructor(tags) {
    super('', true, true);
    this.tags = tags;
  }
  toString() {
    return serializeTags(this.tags);
  }
}
class Statement {
  modifiers;
  sourceSpan;
  leadingComments;
  constructor(modifiers = StmtModifier.None, sourceSpan = null, leadingComments) {
    this.modifiers = modifiers;
    this.sourceSpan = sourceSpan;
    this.leadingComments = leadingComments;
  }
  hasModifier(modifier) {
    return (this.modifiers & modifier) !== 0;
  }
  addLeadingComment(leadingComment) {
    this.leadingComments = this.leadingComments ?? [];
    this.leadingComments.push(leadingComment);
  }
}
class DeclareVarStmt extends Statement {
  name;
  value;
  type;
  constructor(name, value, type, modifiers, sourceSpan, leadingComments) {
    super(modifiers, sourceSpan, leadingComments);
    this.name = name;
    this.value = value;
    this.type = type || value && value.type || null;
  }
  isEquivalent(stmt) {
    return stmt instanceof DeclareVarStmt && this.name === stmt.name && (this.value ? !!stmt.value && this.value.isEquivalent(stmt.value) : !stmt.value);
  }
  visitStatement(visitor, context) {
    return visitor.visitDeclareVarStmt(this, context);
  }
}
class DeclareFunctionStmt extends Statement {
  name;
  params;
  statements;
  type;
  constructor(name, params, statements, type, modifiers, sourceSpan, leadingComments) {
    super(modifiers, sourceSpan, leadingComments);
    this.name = name;
    this.params = params;
    this.statements = statements;
    this.type = type || null;
  }
  isEquivalent(stmt) {
    return stmt instanceof DeclareFunctionStmt && areAllEquivalent(this.params, stmt.params) && areAllEquivalent(this.statements, stmt.statements);
  }
  visitStatement(visitor, context) {
    return visitor.visitDeclareFunctionStmt(this, context);
  }
}
class ExpressionStatement extends Statement {
  expr;
  constructor(expr, sourceSpan, leadingComments) {
    super(StmtModifier.None, sourceSpan, leadingComments);
    this.expr = expr;
  }
  isEquivalent(stmt) {
    return stmt instanceof ExpressionStatement && this.expr.isEquivalent(stmt.expr);
  }
  visitStatement(visitor, context) {
    return visitor.visitExpressionStmt(this, context);
  }
}
class ReturnStatement extends Statement {
  value;
  constructor(value, sourceSpan = null, leadingComments) {
    super(StmtModifier.None, sourceSpan, leadingComments);
    this.value = value;
  }
  isEquivalent(stmt) {
    return stmt instanceof ReturnStatement && this.value.isEquivalent(stmt.value);
  }
  visitStatement(visitor, context) {
    return visitor.visitReturnStmt(this, context);
  }
}
class IfStmt extends Statement {
  condition;
  trueCase;
  falseCase;
  constructor(condition, trueCase, falseCase = [], sourceSpan, leadingComments) {
    super(StmtModifier.None, sourceSpan, leadingComments);
    this.condition = condition;
    this.trueCase = trueCase;
    this.falseCase = falseCase;
  }
  isEquivalent(stmt) {
    return stmt instanceof IfStmt && this.condition.isEquivalent(stmt.condition) && areAllEquivalent(this.trueCase, stmt.trueCase) && areAllEquivalent(this.falseCase, stmt.falseCase);
  }
  visitStatement(visitor, context) {
    return visitor.visitIfStmt(this, context);
  }
}
let RecursiveAstVisitor$1 = class RecursiveAstVisitor {
  visitType(ast, context) {
    return ast;
  }
  visitExpression(ast, context) {
    if (ast.type) {
      ast.type.visitType(this, context);
    }
    return ast;
  }
  visitBuiltinType(type, context) {
    return this.visitType(type, context);
  }
  visitExpressionType(type, context) {
    type.value.visitExpression(this, context);
    if (type.typeParams !== null) {
      type.typeParams.forEach(param => this.visitType(param, context));
    }
    return this.visitType(type, context);
  }
  visitArrayType(type, context) {
    return this.visitType(type, context);
  }
  visitMapType(type, context) {
    return this.visitType(type, context);
  }
  visitTransplantedType(type, context) {
    return type;
  }
  visitWrappedNodeExpr(ast, context) {
    return ast;
  }
  visitReadVarExpr(ast, context) {
    return this.visitExpression(ast, context);
  }
  visitDynamicImportExpr(ast, context) {
    return this.visitExpression(ast, context);
  }
  visitInvokeFunctionExpr(ast, context) {
    ast.fn.visitExpression(this, context);
    this.visitAllExpressions(ast.args, context);
    return this.visitExpression(ast, context);
  }
  visitTaggedTemplateLiteralExpr(ast, context) {
    ast.tag.visitExpression(this, context);
    ast.template.visitExpression(this, context);
    return this.visitExpression(ast, context);
  }
  visitInstantiateExpr(ast, context) {
    ast.classExpr.visitExpression(this, context);
    this.visitAllExpressions(ast.args, context);
    return this.visitExpression(ast, context);
  }
  visitLiteralExpr(ast, context) {
    return this.visitExpression(ast, context);
  }
  visitRegularExpressionLiteral(ast, context) {
    return this.visitExpression(ast, context);
  }
  visitLocalizedString(ast, context) {
    return this.visitExpression(ast, context);
  }
  visitExternalExpr(ast, context) {
    if (ast.typeParams) {
      ast.typeParams.forEach(type => type.visitType(this, context));
    }
    return this.visitExpression(ast, context);
  }
  visitConditionalExpr(ast, context) {
    ast.condition.visitExpression(this, context);
    ast.trueCase.visitExpression(this, context);
    ast.falseCase.visitExpression(this, context);
    return this.visitExpression(ast, context);
  }
  visitNotExpr(ast, context) {
    ast.condition.visitExpression(this, context);
    return this.visitExpression(ast, context);
  }
  visitFunctionExpr(ast, context) {
    this.visitAllStatements(ast.statements, context);
    return this.visitExpression(ast, context);
  }
  visitArrowFunctionExpr(ast, context) {
    if (Array.isArray(ast.body)) {
      this.visitAllStatements(ast.body, context);
    } else {
      ast.body.visitExpression(this, context);
    }
    return this.visitExpression(ast, context);
  }
  visitUnaryOperatorExpr(ast, context) {
    ast.expr.visitExpression(this, context);
    return this.visitExpression(ast, context);
  }
  visitTypeofExpr(ast, context) {
    ast.expr.visitExpression(this, context);
    return this.visitExpression(ast, context);
  }
  visitVoidExpr(ast, context) {
    ast.expr.visitExpression(this, context);
    return this.visitExpression(ast, context);
  }
  visitBinaryOperatorExpr(ast, context) {
    ast.lhs.visitExpression(this, context);
    ast.rhs.visitExpression(this, context);
    return this.visitExpression(ast, context);
  }
  visitReadPropExpr(ast, context) {
    ast.receiver.visitExpression(this, context);
    return this.visitExpression(ast, context);
  }
  visitReadKeyExpr(ast, context) {
    ast.receiver.visitExpression(this, context);
    ast.index.visitExpression(this, context);
    return this.visitExpression(ast, context);
  }
  visitLiteralArrayExpr(ast, context) {
    this.visitAllExpressions(ast.entries, context);
    return this.visitExpression(ast, context);
  }
  visitLiteralMapExpr(ast, context) {
    ast.entries.forEach(entry => {
      if (entry instanceof LiteralMapSpreadAssignment) {
        entry.expression.visitExpression(this, context);
      } else {
        entry.value.visitExpression(this, context);
      }
    });
    return this.visitExpression(ast, context);
  }
  visitCommaExpr(ast, context) {
    this.visitAllExpressions(ast.parts, context);
    return this.visitExpression(ast, context);
  }
  visitTemplateLiteralExpr(ast, context) {
    this.visitAllExpressions(ast.elements, context);
    this.visitAllExpressions(ast.expressions, context);
    return this.visitExpression(ast, context);
  }
  visitTemplateLiteralElementExpr(ast, context) {
    return this.visitExpression(ast, context);
  }
  visitParenthesizedExpr(ast, context) {
    ast.expr.visitExpression(this, context);
    return this.visitExpression(ast, context);
  }
  visitSpreadElementExpr(ast, context) {
    ast.expression.visitExpression(this, context);
    return this.visitExpression(ast, context);
  }
  visitAllExpressions(exprs, context) {
    exprs.forEach(expr => expr.visitExpression(this, context));
  }
  visitDeclareVarStmt(stmt, context) {
    if (stmt.value) {
      stmt.value.visitExpression(this, context);
    }
    if (stmt.type) {
      stmt.type.visitType(this, context);
    }
    return stmt;
  }
  visitDeclareFunctionStmt(stmt, context) {
    this.visitAllStatements(stmt.statements, context);
    if (stmt.type) {
      stmt.type.visitType(this, context);
    }
    return stmt;
  }
  visitExpressionStmt(stmt, context) {
    stmt.expr.visitExpression(this, context);
    return stmt;
  }
  visitReturnStmt(stmt, context) {
    stmt.value.visitExpression(this, context);
    return stmt;
  }
  visitIfStmt(stmt, context) {
    stmt.condition.visitExpression(this, context);
    this.visitAllStatements(stmt.trueCase, context);
    this.visitAllStatements(stmt.falseCase, context);
    return stmt;
  }
  visitAllStatements(stmts, context) {
    stmts.forEach(stmt => stmt.visitStatement(this, context));
  }
};
function leadingComment(text, multiline = false, trailingNewline = true) {
  return new LeadingComment(text, multiline, trailingNewline);
}
function jsDocComment(tags = []) {
  return new JSDocComment(tags);
}
function variable(name, type, sourceSpan, leadingComments) {
  return new ReadVarExpr(name, type, sourceSpan, leadingComments);
}
function importExpr(id, typeParams = null, sourceSpan) {
  return new ExternalExpr(id, null, typeParams, sourceSpan);
}
function importType(id, typeParams, typeModifiers) {
  return id != null ? expressionType(importExpr(id, typeParams, null), typeModifiers) : null;
}
function expressionType(expr, typeModifiers, typeParams) {
  return new ExpressionType(expr, typeModifiers, typeParams);
}
function transplantedType(type, typeModifiers) {
  return new TransplantedType(type, typeModifiers);
}
function typeofExpr(expr) {
  return new TypeofExpr(expr);
}
function literalArr(values, type, sourceSpan) {
  return new LiteralArrayExpr(values, type, sourceSpan);
}
function literalMap(values, type = null) {
  return new LiteralMapExpr(values.map(e => new LiteralMapPropertyAssignment(e.key, e.value, e.quoted)), type, null);
}
function unary(operator, expr, type, sourceSpan) {
  return new UnaryOperatorExpr(operator, expr, type, sourceSpan);
}
function not(expr, sourceSpan) {
  return new NotExpr(expr, sourceSpan);
}
function fn(params, body, type, sourceSpan, name) {
  return new FunctionExpr(params, body, type, sourceSpan, name);
}
function arrowFn(params, body, type, sourceSpan) {
  return new ArrowFunctionExpr$1(params, body, type, sourceSpan);
}
function ifStmt(condition, thenClause, elseClause, sourceSpan, leadingComments) {
  return new IfStmt(condition, thenClause, elseClause, sourceSpan, leadingComments);
}
function taggedTemplate(tag, template, type, sourceSpan) {
  return new TaggedTemplateLiteralExpr(tag, template, type, sourceSpan);
}
function literal(value, type, sourceSpan) {
  return new LiteralExpr(value, type, sourceSpan);
}
function localizedString(metaBlock, messageParts, placeholderNames, expressions, sourceSpan) {
  return new LocalizedString(metaBlock, messageParts, placeholderNames, expressions, sourceSpan);
}
function isNull(exp) {
  return exp instanceof LiteralExpr && exp.value === null;
}
function tagToString(tag) {
  let out = '';
  if (tag.tagName) {
    out += ` @${tag.tagName}`;
  }
  if (tag.text) {
    if (tag.text.match(/\/\*|\*\//)) {
      throw new Error('JSDoc text cannot contain "/*" and "*/"');
    }
    out += ' ' + tag.text.replace(/@/g, '\\@');
  }
  return out;
}
function serializeTags(tags) {
  if (tags.length === 0) return '';
  if (tags.length === 1 && tags[0].tagName && !tags[0].text) {
    return `*${tagToString(tags[0])} `;
  }
  let out = '*\n';
  for (const tag of tags) {
    out += ' *';
    out += tagToString(tag).replace(/\n/g, '\n * ');
    out += '\n';
  }
  out += ' ';
  return out;
}

var output_ast = /*#__PURE__*/Object.freeze({
    __proto__: null,
    ArrayType: ArrayType,
    ArrowFunctionExpr: ArrowFunctionExpr$1,
    BOOL_TYPE: BOOL_TYPE,
    get BinaryOperator () { return BinaryOperator; },
    BinaryOperatorExpr: BinaryOperatorExpr,
    BuiltinType: BuiltinType,
    get BuiltinTypeName () { return BuiltinTypeName; },
    CommaExpr: CommaExpr,
    ConditionalExpr: ConditionalExpr,
    DYNAMIC_TYPE: DYNAMIC_TYPE,
    DeclareFunctionStmt: DeclareFunctionStmt,
    DeclareVarStmt: DeclareVarStmt,
    DynamicImportExpr: DynamicImportExpr,
    Expression: Expression,
    ExpressionStatement: ExpressionStatement,
    ExpressionType: ExpressionType,
    ExternalExpr: ExternalExpr,
    ExternalReference: ExternalReference,
    FUNCTION_TYPE: FUNCTION_TYPE,
    FnParam: FnParam,
    FunctionExpr: FunctionExpr,
    INFERRED_TYPE: INFERRED_TYPE,
    INT_TYPE: INT_TYPE,
    IfStmt: IfStmt,
    InstantiateExpr: InstantiateExpr,
    InvokeFunctionExpr: InvokeFunctionExpr,
    JSDocComment: JSDocComment,
    LeadingComment: LeadingComment,
    LiteralArrayExpr: LiteralArrayExpr,
    LiteralExpr: LiteralExpr,
    LiteralMapExpr: LiteralMapExpr,
    LiteralMapPropertyAssignment: LiteralMapPropertyAssignment,
    LiteralMapSpreadAssignment: LiteralMapSpreadAssignment,
    LiteralPiece: LiteralPiece,
    LocalizedString: LocalizedString,
    MapType: MapType,
    NONE_TYPE: NONE_TYPE,
    NULL_EXPR: NULL_EXPR,
    NUMBER_TYPE: NUMBER_TYPE,
    NotExpr: NotExpr,
    ParenthesizedExpr: ParenthesizedExpr,
    PlaceholderPiece: PlaceholderPiece,
    ReadKeyExpr: ReadKeyExpr,
    ReadPropExpr: ReadPropExpr,
    ReadVarExpr: ReadVarExpr,
    RecursiveAstVisitor: RecursiveAstVisitor$1,
    RegularExpressionLiteralExpr: RegularExpressionLiteralExpr,
    ReturnStatement: ReturnStatement,
    STRING_TYPE: STRING_TYPE,
    SpreadElementExpr: SpreadElementExpr,
    Statement: Statement,
    get StmtModifier () { return StmtModifier; },
    TYPED_NULL_EXPR: TYPED_NULL_EXPR,
    TaggedTemplateLiteralExpr: TaggedTemplateLiteralExpr,
    TemplateLiteralElementExpr: TemplateLiteralElementExpr,
    TemplateLiteralExpr: TemplateLiteralExpr,
    TransplantedType: TransplantedType,
    Type: Type,
    get TypeModifier () { return TypeModifier; },
    TypeofExpr: TypeofExpr,
    get UnaryOperator () { return UnaryOperator; },
    UnaryOperatorExpr: UnaryOperatorExpr,
    VoidExpr: VoidExpr,
    WrappedNodeExpr: WrappedNodeExpr,
    areAllEquivalent: areAllEquivalent,
    arrowFn: arrowFn,
    expressionType: expressionType,
    fn: fn,
    ifStmt: ifStmt,
    importExpr: importExpr,
    importType: importType,
    isNull: isNull,
    jsDocComment: jsDocComment,
    leadingComment: leadingComment,
    literal: literal,
    literalArr: literalArr,
    literalMap: literalMap,
    localizedString: localizedString,
    not: not,
    nullSafeIsEquivalent: nullSafeIsEquivalent,
    taggedTemplate: taggedTemplate,
    transplantedType: transplantedType,
    typeofExpr: typeofExpr,
    unary: unary,
    variable: variable
});

const CONSTANT_PREFIX = '_c';
const KEY_CONTEXT = {};
const POOL_INCLUSION_LENGTH_THRESHOLD_FOR_STRINGS = 50;
class FixupExpression extends Expression {
  resolved;
  original;
  shared = false;
  constructor(resolved) {
    super(resolved.type);
    this.resolved = resolved;
    this.original = resolved;
  }
  visitExpression(visitor, context) {
    if (context === KEY_CONTEXT) {
      return this.original.visitExpression(visitor, context);
    } else {
      return this.resolved.visitExpression(visitor, context);
    }
  }
  isEquivalent(e) {
    return e instanceof FixupExpression && this.resolved.isEquivalent(e.resolved);
  }
  isConstant() {
    return true;
  }
  clone() {
    throw new Error(`Not supported.`);
  }
  fixup(expression) {
    this.resolved = expression;
    this.shared = true;
  }
}
class ConstantPool {
  isClosureCompilerEnabled;
  statements = [];
  literals = new Map();
  sharedConstants = new Map();
  _claimedNames = new Map();
  constructor(isClosureCompilerEnabled = false) {
    this.isClosureCompilerEnabled = isClosureCompilerEnabled;
  }
  getConstLiteral(literal, forceShared) {
    if (literal instanceof LiteralExpr && !isLongStringLiteral(literal) || literal instanceof FixupExpression) {
      return literal;
    }
    const key = GenericKeyFn.INSTANCE.keyOf(literal);
    let fixup = this.literals.get(key);
    let newValue = false;
    if (!fixup) {
      fixup = new FixupExpression(literal);
      this.literals.set(key, fixup);
      newValue = true;
    }
    if (!newValue && !fixup.shared || newValue && forceShared) {
      const name = this.freshName();
      let value;
      let usage;
      if (this.isClosureCompilerEnabled && isLongStringLiteral(literal)) {
        value = new FunctionExpr([], [new ReturnStatement(literal)]);
        usage = variable(name).callFn([]);
      } else {
        value = literal;
        usage = variable(name);
      }
      this.statements.push(new DeclareVarStmt(name, value, INFERRED_TYPE, StmtModifier.Final));
      fixup.fixup(usage);
    }
    return fixup;
  }
  getSharedConstant(def, expr) {
    const key = def.keyOf(expr);
    if (!this.sharedConstants.has(key)) {
      const id = this.freshName();
      this.sharedConstants.set(key, variable(id));
      this.statements.push(def.toSharedConstantDeclaration(id, expr));
    }
    return this.sharedConstants.get(key);
  }
  getSharedFunctionReference(fn, prefix, useUniqueName = true) {
    const isArrow = fn instanceof ArrowFunctionExpr$1;
    for (const current of this.statements) {
      if (isArrow && current instanceof DeclareVarStmt && current.value?.isEquivalent(fn)) {
        return variable(current.name);
      }
      if (!isArrow && current instanceof DeclareFunctionStmt && fn instanceof FunctionExpr && fn.isEquivalent(current)) {
        return variable(current.name);
      }
    }
    const name = useUniqueName ? this.uniqueName(prefix) : prefix;
    this.statements.push(fn instanceof FunctionExpr ? fn.toDeclStmt(name, StmtModifier.Final) : new DeclareVarStmt(name, fn, INFERRED_TYPE, StmtModifier.Final, fn.sourceSpan));
    return variable(name);
  }
  uniqueName(name, alwaysIncludeSuffix = true) {
    const count = this._claimedNames.get(name) ?? 0;
    const result = count === 0 && !alwaysIncludeSuffix ? `${name}` : `${name}${count}`;
    this._claimedNames.set(name, count + 1);
    return result;
  }
  freshName() {
    return this.uniqueName(CONSTANT_PREFIX);
  }
}
class GenericKeyFn {
  static INSTANCE = new GenericKeyFn();
  keyOf(expr) {
    if (expr instanceof LiteralExpr && typeof expr.value === 'string') {
      return `"${expr.value}"`;
    } else if (expr instanceof LiteralExpr) {
      return String(expr.value);
    } else if (expr instanceof RegularExpressionLiteralExpr) {
      return `/${expr.body}/${expr.flags ?? ''}`;
    } else if (expr instanceof LiteralArrayExpr) {
      const entries = [];
      for (const entry of expr.entries) {
        entries.push(this.keyOf(entry));
      }
      return `[${entries.join(',')}]`;
    } else if (expr instanceof LiteralMapExpr) {
      const entries = [];
      for (const entry of expr.entries) {
        if (entry instanceof LiteralMapSpreadAssignment) {
          entries.push('...' + this.keyOf(entry.expression));
        } else {
          let key = entry.key;
          if (entry.quoted) {
            key = `"${key}"`;
          }
          entries.push(key + ':' + this.keyOf(entry.value));
        }
      }
      return `{${entries.join(',')}}`;
    } else if (expr instanceof ExternalExpr) {
      return `import("${expr.value.moduleName}", ${expr.value.name})`;
    } else if (expr instanceof ReadVarExpr) {
      return `read(${expr.name})`;
    } else if (expr instanceof TypeofExpr) {
      return `typeof(${this.keyOf(expr.expr)})`;
    } else if (expr instanceof SpreadElementExpr) {
      return `...${this.keyOf(expr.expression)}`;
    } else {
      throw new Error(`${this.constructor.name} does not handle expressions of type ${expr.constructor.name}`);
    }
  }
}
function isLongStringLiteral(expr) {
  return expr instanceof LiteralExpr && typeof expr.value === 'string' && expr.value.length >= POOL_INCLUSION_LENGTH_THRESHOLD_FOR_STRINGS;
}

const CORE = '@angular/core';
class Identifiers {
  static core = {
    name: null,
    moduleName: CORE
  };
  static namespaceHTML = {
    name: 'ɵɵnamespaceHTML',
    moduleName: CORE
  };
  static namespaceMathML = {
    name: 'ɵɵnamespaceMathML',
    moduleName: CORE
  };
  static namespaceSVG = {
    name: 'ɵɵnamespaceSVG',
    moduleName: CORE
  };
  static element = {
    name: 'ɵɵelement',
    moduleName: CORE
  };
  static elementStart = {
    name: 'ɵɵelementStart',
    moduleName: CORE
  };
  static elementEnd = {
    name: 'ɵɵelementEnd',
    moduleName: CORE
  };
  static foreignComponent = {
    name: 'ɵɵforeignComponent',
    moduleName: CORE
  };
  static foreignContent = {
    name: 'ɵɵforeignContent',
    moduleName: CORE
  };
  static foreignContentFn = {
    name: 'ɵɵforeignContentFn',
    moduleName: CORE
  };
  static domElement = {
    name: 'ɵɵdomElement',
    moduleName: CORE
  };
  static domElementStart = {
    name: 'ɵɵdomElementStart',
    moduleName: CORE
  };
  static domElementEnd = {
    name: 'ɵɵdomElementEnd',
    moduleName: CORE
  };
  static domElementContainer = {
    name: 'ɵɵdomElementContainer',
    moduleName: CORE
  };
  static domElementContainerStart = {
    name: 'ɵɵdomElementContainerStart',
    moduleName: CORE
  };
  static domElementContainerEnd = {
    name: 'ɵɵdomElementContainerEnd',
    moduleName: CORE
  };
  static domTemplate = {
    name: 'ɵɵdomTemplate',
    moduleName: CORE
  };
  static domListener = {
    name: 'ɵɵdomListener',
    moduleName: CORE
  };
  static advance = {
    name: 'ɵɵadvance',
    moduleName: CORE
  };
  static syntheticHostProperty = {
    name: 'ɵɵsyntheticHostProperty',
    moduleName: CORE
  };
  static syntheticHostListener = {
    name: 'ɵɵsyntheticHostListener',
    moduleName: CORE
  };
  static attribute = {
    name: 'ɵɵattribute',
    moduleName: CORE
  };
  static classProp = {
    name: 'ɵɵclassProp',
    moduleName: CORE
  };
  static elementContainerStart = {
    name: 'ɵɵelementContainerStart',
    moduleName: CORE
  };
  static elementContainerEnd = {
    name: 'ɵɵelementContainerEnd',
    moduleName: CORE
  };
  static elementContainer = {
    name: 'ɵɵelementContainer',
    moduleName: CORE
  };
  static styleMap = {
    name: 'ɵɵstyleMap',
    moduleName: CORE
  };
  static classMap = {
    name: 'ɵɵclassMap',
    moduleName: CORE
  };
  static styleProp = {
    name: 'ɵɵstyleProp',
    moduleName: CORE
  };
  static interpolate = {
    name: 'ɵɵinterpolate',
    moduleName: CORE
  };
  static interpolate1 = {
    name: 'ɵɵinterpolate1',
    moduleName: CORE
  };
  static interpolate2 = {
    name: 'ɵɵinterpolate2',
    moduleName: CORE
  };
  static interpolate3 = {
    name: 'ɵɵinterpolate3',
    moduleName: CORE
  };
  static interpolate4 = {
    name: 'ɵɵinterpolate4',
    moduleName: CORE
  };
  static interpolate5 = {
    name: 'ɵɵinterpolate5',
    moduleName: CORE
  };
  static interpolate6 = {
    name: 'ɵɵinterpolate6',
    moduleName: CORE
  };
  static interpolate7 = {
    name: 'ɵɵinterpolate7',
    moduleName: CORE
  };
  static interpolate8 = {
    name: 'ɵɵinterpolate8',
    moduleName: CORE
  };
  static interpolateV = {
    name: 'ɵɵinterpolateV',
    moduleName: CORE
  };
  static nextContext = {
    name: 'ɵɵnextContext',
    moduleName: CORE
  };
  static resetView = {
    name: 'ɵɵresetView',
    moduleName: CORE
  };
  static templateCreate = {
    name: 'ɵɵtemplate',
    moduleName: CORE
  };
  static defer = {
    name: 'ɵɵdefer',
    moduleName: CORE
  };
  static deferWhen = {
    name: 'ɵɵdeferWhen',
    moduleName: CORE
  };
  static deferOnIdle = {
    name: 'ɵɵdeferOnIdle',
    moduleName: CORE
  };
  static deferOnImmediate = {
    name: 'ɵɵdeferOnImmediate',
    moduleName: CORE
  };
  static deferOnTimer = {
    name: 'ɵɵdeferOnTimer',
    moduleName: CORE
  };
  static deferOnHover = {
    name: 'ɵɵdeferOnHover',
    moduleName: CORE
  };
  static deferOnInteraction = {
    name: 'ɵɵdeferOnInteraction',
    moduleName: CORE
  };
  static deferOnViewport = {
    name: 'ɵɵdeferOnViewport',
    moduleName: CORE
  };
  static deferPrefetchWhen = {
    name: 'ɵɵdeferPrefetchWhen',
    moduleName: CORE
  };
  static deferPrefetchOnIdle = {
    name: 'ɵɵdeferPrefetchOnIdle',
    moduleName: CORE
  };
  static deferPrefetchOnImmediate = {
    name: 'ɵɵdeferPrefetchOnImmediate',
    moduleName: CORE
  };
  static deferPrefetchOnTimer = {
    name: 'ɵɵdeferPrefetchOnTimer',
    moduleName: CORE
  };
  static deferPrefetchOnHover = {
    name: 'ɵɵdeferPrefetchOnHover',
    moduleName: CORE
  };
  static deferPrefetchOnInteraction = {
    name: 'ɵɵdeferPrefetchOnInteraction',
    moduleName: CORE
  };
  static deferPrefetchOnViewport = {
    name: 'ɵɵdeferPrefetchOnViewport',
    moduleName: CORE
  };
  static deferHydrateWhen = {
    name: 'ɵɵdeferHydrateWhen',
    moduleName: CORE
  };
  static deferHydrateNever = {
    name: 'ɵɵdeferHydrateNever',
    moduleName: CORE
  };
  static deferHydrateOnIdle = {
    name: 'ɵɵdeferHydrateOnIdle',
    moduleName: CORE
  };
  static deferHydrateOnImmediate = {
    name: 'ɵɵdeferHydrateOnImmediate',
    moduleName: CORE
  };
  static deferHydrateOnTimer = {
    name: 'ɵɵdeferHydrateOnTimer',
    moduleName: CORE
  };
  static deferHydrateOnHover = {
    name: 'ɵɵdeferHydrateOnHover',
    moduleName: CORE
  };
  static deferHydrateOnInteraction = {
    name: 'ɵɵdeferHydrateOnInteraction',
    moduleName: CORE
  };
  static deferHydrateOnViewport = {
    name: 'ɵɵdeferHydrateOnViewport',
    moduleName: CORE
  };
  static deferEnableTimerScheduling = {
    name: 'ɵɵdeferEnableTimerScheduling',
    moduleName: CORE
  };
  static enableIncrementalHydrationRuntime = {
    name: 'ɵɵenableIncrementalHydrationRuntime',
    moduleName: CORE
  };
  static conditionalCreate = {
    name: 'ɵɵconditionalCreate',
    moduleName: CORE
  };
  static conditionalBranchCreate = {
    name: 'ɵɵconditionalBranchCreate',
    moduleName: CORE
  };
  static conditional = {
    name: 'ɵɵconditional',
    moduleName: CORE
  };
  static repeater = {
    name: 'ɵɵrepeater',
    moduleName: CORE
  };
  static repeaterCreate = {
    name: 'ɵɵrepeaterCreate',
    moduleName: CORE
  };
  static repeaterTrackByIndex = {
    name: 'ɵɵrepeaterTrackByIndex',
    moduleName: CORE
  };
  static repeaterTrackByIdentity = {
    name: 'ɵɵrepeaterTrackByIdentity',
    moduleName: CORE
  };
  static componentInstance = {
    name: 'ɵɵcomponentInstance',
    moduleName: CORE
  };
  static text = {
    name: 'ɵɵtext',
    moduleName: CORE
  };
  static enableBindings = {
    name: 'ɵɵenableBindings',
    moduleName: CORE
  };
  static disableBindings = {
    name: 'ɵɵdisableBindings',
    moduleName: CORE
  };
  static getCurrentView = {
    name: 'ɵɵgetCurrentView',
    moduleName: CORE
  };
  static textInterpolate = {
    name: 'ɵɵtextInterpolate',
    moduleName: CORE
  };
  static textInterpolate1 = {
    name: 'ɵɵtextInterpolate1',
    moduleName: CORE
  };
  static textInterpolate2 = {
    name: 'ɵɵtextInterpolate2',
    moduleName: CORE
  };
  static textInterpolate3 = {
    name: 'ɵɵtextInterpolate3',
    moduleName: CORE
  };
  static textInterpolate4 = {
    name: 'ɵɵtextInterpolate4',
    moduleName: CORE
  };
  static textInterpolate5 = {
    name: 'ɵɵtextInterpolate5',
    moduleName: CORE
  };
  static textInterpolate6 = {
    name: 'ɵɵtextInterpolate6',
    moduleName: CORE
  };
  static textInterpolate7 = {
    name: 'ɵɵtextInterpolate7',
    moduleName: CORE
  };
  static textInterpolate8 = {
    name: 'ɵɵtextInterpolate8',
    moduleName: CORE
  };
  static textInterpolateV = {
    name: 'ɵɵtextInterpolateV',
    moduleName: CORE
  };
  static restoreView = {
    name: 'ɵɵrestoreView',
    moduleName: CORE
  };
  static pureFunction0 = {
    name: 'ɵɵpureFunction0',
    moduleName: CORE
  };
  static pureFunction1 = {
    name: 'ɵɵpureFunction1',
    moduleName: CORE
  };
  static pureFunction2 = {
    name: 'ɵɵpureFunction2',
    moduleName: CORE
  };
  static pureFunction3 = {
    name: 'ɵɵpureFunction3',
    moduleName: CORE
  };
  static pureFunction4 = {
    name: 'ɵɵpureFunction4',
    moduleName: CORE
  };
  static pureFunction5 = {
    name: 'ɵɵpureFunction5',
    moduleName: CORE
  };
  static pureFunction6 = {
    name: 'ɵɵpureFunction6',
    moduleName: CORE
  };
  static pureFunction7 = {
    name: 'ɵɵpureFunction7',
    moduleName: CORE
  };
  static pureFunction8 = {
    name: 'ɵɵpureFunction8',
    moduleName: CORE
  };
  static pureFunctionV = {
    name: 'ɵɵpureFunctionV',
    moduleName: CORE
  };
  static pipeBind1 = {
    name: 'ɵɵpipeBind1',
    moduleName: CORE
  };
  static pipeBind2 = {
    name: 'ɵɵpipeBind2',
    moduleName: CORE
  };
  static pipeBind3 = {
    name: 'ɵɵpipeBind3',
    moduleName: CORE
  };
  static pipeBind4 = {
    name: 'ɵɵpipeBind4',
    moduleName: CORE
  };
  static pipeBindV = {
    name: 'ɵɵpipeBindV',
    moduleName: CORE
  };
  static domProperty = {
    name: 'ɵɵdomProperty',
    moduleName: CORE
  };
  static ariaProperty = {
    name: 'ɵɵariaProperty',
    moduleName: CORE
  };
  static property = {
    name: 'ɵɵproperty',
    moduleName: CORE
  };
  static control = {
    name: 'ɵɵcontrol',
    moduleName: CORE
  };
  static controlCreate = {
    name: 'ɵɵcontrolCreate',
    moduleName: CORE
  };
  static animationEnterListener = {
    name: 'ɵɵanimateEnterListener',
    moduleName: CORE
  };
  static animationLeaveListener = {
    name: 'ɵɵanimateLeaveListener',
    moduleName: CORE
  };
  static animationEnter = {
    name: 'ɵɵanimateEnter',
    moduleName: CORE
  };
  static animationLeave = {
    name: 'ɵɵanimateLeave',
    moduleName: CORE
  };
  static i18n = {
    name: 'ɵɵi18n',
    moduleName: CORE
  };
  static i18nAttributes = {
    name: 'ɵɵi18nAttributes',
    moduleName: CORE
  };
  static i18nExp = {
    name: 'ɵɵi18nExp',
    moduleName: CORE
  };
  static i18nStart = {
    name: 'ɵɵi18nStart',
    moduleName: CORE
  };
  static i18nEnd = {
    name: 'ɵɵi18nEnd',
    moduleName: CORE
  };
  static i18nApply = {
    name: 'ɵɵi18nApply',
    moduleName: CORE
  };
  static i18nPostprocess = {
    name: 'ɵɵi18nPostprocess',
    moduleName: CORE
  };
  static pipe = {
    name: 'ɵɵpipe',
    moduleName: CORE
  };
  static projection = {
    name: 'ɵɵprojection',
    moduleName: CORE
  };
  static projectionDef = {
    name: 'ɵɵprojectionDef',
    moduleName: CORE
  };
  static reference = {
    name: 'ɵɵreference',
    moduleName: CORE
  };
  static inject = {
    name: 'ɵɵinject',
    moduleName: CORE
  };
  static injectAttribute = {
    name: 'ɵɵinjectAttribute',
    moduleName: CORE
  };
  static directiveInject = {
    name: 'ɵɵdirectiveInject',
    moduleName: CORE
  };
  static invalidFactory = {
    name: 'ɵɵinvalidFactory',
    moduleName: CORE
  };
  static invalidFactoryDep = {
    name: 'ɵɵinvalidFactoryDep',
    moduleName: CORE
  };
  static templateRefExtractor = {
    name: 'ɵɵtemplateRefExtractor',
    moduleName: CORE
  };
  static forwardRef = {
    name: 'forwardRef',
    moduleName: CORE
  };
  static resolveForwardRef = {
    name: 'resolveForwardRef',
    moduleName: CORE
  };
  static replaceMetadata = {
    name: 'ɵɵreplaceMetadata',
    moduleName: CORE
  };
  static getReplaceMetadataURL = {
    name: 'ɵɵgetReplaceMetadataURL',
    moduleName: CORE
  };
  static ɵɵdefineInjectable = {
    name: 'ɵɵdefineInjectable',
    moduleName: CORE
  };
  static declareInjectable = {
    name: 'ɵɵngDeclareInjectable',
    moduleName: CORE
  };
  static InjectableDeclaration = {
    name: 'ɵɵInjectableDeclaration',
    moduleName: CORE
  };
  static defineService = {
    name: 'ɵɵdefineService',
    moduleName: CORE
  };
  static declareService = {
    name: 'ɵɵngDeclareService',
    moduleName: CORE
  };
  static resolveWindow = {
    name: 'ɵɵresolveWindow',
    moduleName: CORE
  };
  static resolveDocument = {
    name: 'ɵɵresolveDocument',
    moduleName: CORE
  };
  static resolveBody = {
    name: 'ɵɵresolveBody',
    moduleName: CORE
  };
  static getComponentDepsFactory = {
    name: 'ɵɵgetComponentDepsFactory',
    moduleName: CORE
  };
  static defineComponent = {
    name: 'ɵɵdefineComponent',
    moduleName: CORE
  };
  static declareComponent = {
    name: 'ɵɵngDeclareComponent',
    moduleName: CORE
  };
  static setComponentScope = {
    name: 'ɵɵsetComponentScope',
    moduleName: CORE
  };
  static ChangeDetectionStrategy = {
    name: 'ChangeDetectionStrategy',
    moduleName: CORE
  };
  static ViewEncapsulation = {
    name: 'ViewEncapsulation',
    moduleName: CORE
  };
  static ComponentDeclaration = {
    name: 'ɵɵComponentDeclaration',
    moduleName: CORE
  };
  static FactoryDeclaration = {
    name: 'ɵɵFactoryDeclaration',
    moduleName: CORE
  };
  static declareFactory = {
    name: 'ɵɵngDeclareFactory',
    moduleName: CORE
  };
  static FactoryTarget = {
    name: 'ɵɵFactoryTarget',
    moduleName: CORE
  };
  static defineDirective = {
    name: 'ɵɵdefineDirective',
    moduleName: CORE
  };
  static declareDirective = {
    name: 'ɵɵngDeclareDirective',
    moduleName: CORE
  };
  static DirectiveDeclaration = {
    name: 'ɵɵDirectiveDeclaration',
    moduleName: CORE
  };
  static InjectorDef = {
    name: 'ɵɵInjectorDef',
    moduleName: CORE
  };
  static InjectorDeclaration = {
    name: 'ɵɵInjectorDeclaration',
    moduleName: CORE
  };
  static defineInjector = {
    name: 'ɵɵdefineInjector',
    moduleName: CORE
  };
  static declareInjector = {
    name: 'ɵɵngDeclareInjector',
    moduleName: CORE
  };
  static NgModuleDeclaration = {
    name: 'ɵɵNgModuleDeclaration',
    moduleName: CORE
  };
  static ModuleWithProviders = {
    name: 'ModuleWithProviders',
    moduleName: CORE
  };
  static defineNgModule = {
    name: 'ɵɵdefineNgModule',
    moduleName: CORE
  };
  static declareNgModule = {
    name: 'ɵɵngDeclareNgModule',
    moduleName: CORE
  };
  static setNgModuleScope = {
    name: 'ɵɵsetNgModuleScope',
    moduleName: CORE
  };
  static registerNgModuleType = {
    name: 'ɵɵregisterNgModuleType',
    moduleName: CORE
  };
  static PipeDeclaration = {
    name: 'ɵɵPipeDeclaration',
    moduleName: CORE
  };
  static definePipe = {
    name: 'ɵɵdefinePipe',
    moduleName: CORE
  };
  static declarePipe = {
    name: 'ɵɵngDeclarePipe',
    moduleName: CORE
  };
  static declareClassMetadata = {
    name: 'ɵɵngDeclareClassMetadata',
    moduleName: CORE
  };
  static declareClassMetadataAsync = {
    name: 'ɵɵngDeclareClassMetadataAsync',
    moduleName: CORE
  };
  static setClassMetadata = {
    name: 'ɵsetClassMetadata',
    moduleName: CORE
  };
  static setClassMetadataAsync = {
    name: 'ɵsetClassMetadataAsync',
    moduleName: CORE
  };
  static setClassDebugInfo = {
    name: 'ɵsetClassDebugInfo',
    moduleName: CORE
  };
  static queryRefresh = {
    name: 'ɵɵqueryRefresh',
    moduleName: CORE
  };
  static viewQuery = {
    name: 'ɵɵviewQuery',
    moduleName: CORE
  };
  static loadQuery = {
    name: 'ɵɵloadQuery',
    moduleName: CORE
  };
  static contentQuery = {
    name: 'ɵɵcontentQuery',
    moduleName: CORE
  };
  static viewQuerySignal = {
    name: 'ɵɵviewQuerySignal',
    moduleName: CORE
  };
  static contentQuerySignal = {
    name: 'ɵɵcontentQuerySignal',
    moduleName: CORE
  };
  static queryAdvance = {
    name: 'ɵɵqueryAdvance',
    moduleName: CORE
  };
  static twoWayProperty = {
    name: 'ɵɵtwoWayProperty',
    moduleName: CORE
  };
  static twoWayBindingSet = {
    name: 'ɵɵtwoWayBindingSet',
    moduleName: CORE
  };
  static twoWayListener = {
    name: 'ɵɵtwoWayListener',
    moduleName: CORE
  };
  static declareLet = {
    name: 'ɵɵdeclareLet',
    moduleName: CORE
  };
  static storeLet = {
    name: 'ɵɵstoreLet',
    moduleName: CORE
  };
  static readContextLet = {
    name: 'ɵɵreadContextLet',
    moduleName: CORE
  };
  static arrowFunction = {
    name: 'ɵɵarrowFunction',
    moduleName: CORE
  };
  static attachSourceLocations = {
    name: 'ɵɵattachSourceLocations',
    moduleName: CORE
  };
  static NgOnChangesFeature = {
    name: 'ɵɵNgOnChangesFeature',
    moduleName: CORE
  };
  static ControlFeature = {
    name: 'ɵɵControlFeature',
    moduleName: CORE
  };
  static InheritDefinitionFeature = {
    name: 'ɵɵInheritDefinitionFeature',
    moduleName: CORE
  };
  static ProvidersFeature = {
    name: 'ɵɵProvidersFeature',
    moduleName: CORE
  };
  static HostDirectivesFeature = {
    name: 'ɵɵHostDirectivesFeature',
    moduleName: CORE
  };
  static ExternalStylesFeature = {
    name: 'ɵɵExternalStylesFeature',
    moduleName: CORE
  };
  static listener = {
    name: 'ɵɵlistener',
    moduleName: CORE
  };
  static getInheritedFactory = {
    name: 'ɵɵgetInheritedFactory',
    moduleName: CORE
  };
  static sanitizeHtml = {
    name: 'ɵɵsanitizeHtml',
    moduleName: CORE
  };
  static sanitizeStyle = {
    name: 'ɵɵsanitizeStyle',
    moduleName: CORE
  };
  static validateAttribute = {
    name: 'ɵɵvalidateAttribute',
    moduleName: CORE
  };
  static sanitizeResourceUrl = {
    name: 'ɵɵsanitizeResourceUrl',
    moduleName: CORE
  };
  static sanitizeScript = {
    name: 'ɵɵsanitizeScript',
    moduleName: CORE
  };
  static sanitizeUrl = {
    name: 'ɵɵsanitizeUrl',
    moduleName: CORE
  };
  static sanitizeUrlOrResourceUrl = {
    name: 'ɵɵsanitizeUrlOrResourceUrl',
    moduleName: CORE
  };
  static trustConstantHtml = {
    name: 'ɵɵtrustConstantHtml',
    moduleName: CORE
  };
  static trustConstantResourceUrl = {
    name: 'ɵɵtrustConstantResourceUrl',
    moduleName: CORE
  };
  static inputDecorator = {
    name: 'Input',
    moduleName: CORE
  };
  static outputDecorator = {
    name: 'Output',
    moduleName: CORE
  };
  static viewChildDecorator = {
    name: 'ViewChild',
    moduleName: CORE
  };
  static viewChildrenDecorator = {
    name: 'ViewChildren',
    moduleName: CORE
  };
  static contentChildDecorator = {
    name: 'ContentChild',
    moduleName: CORE
  };
  static contentChildrenDecorator = {
    name: 'ContentChildren',
    moduleName: CORE
  };
  static InputSignalBrandWriteType = {
    name: 'ɵINPUT_SIGNAL_BRAND_WRITE_TYPE',
    moduleName: CORE
  };
  static UnwrapDirectiveSignalInputs = {
    name: 'ɵUnwrapDirectiveSignalInputs',
    moduleName: CORE
  };
  static unwrapWritableSignal = {
    name: 'ɵunwrapWritableSignal',
    moduleName: CORE
  };
  static assertType = {
    name: 'ɵassertType',
    moduleName: CORE
  };
}

const DASH_CASE_REGEXP = /-+([a-z0-9])/g;
function dashCaseToCamelCase(input) {
  return input.replace(DASH_CASE_REGEXP, (...m) => m[1].toUpperCase());
}
function splitAtColon(input, defaultValues) {
  return _splitAt(input, ':', defaultValues);
}
function splitAtPeriod(input, defaultValues) {
  return _splitAt(input, '.', defaultValues);
}
function _splitAt(input, character, defaultValues) {
  const characterIndex = input.indexOf(character);
  if (characterIndex == -1) return defaultValues;
  return [input.slice(0, characterIndex).trim(), input.slice(characterIndex + 1).trim()];
}
function noUndefined(val) {
  return val === undefined ? null : val;
}
function escapeRegExp(s) {
  return s.replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
}
function utf8Encode(str) {
  let encoded = [];
  for (let index = 0; index < str.length; index++) {
    let codePoint = str.charCodeAt(index);
    if (codePoint >= 0xd800 && codePoint <= 0xdbff && str.length > index + 1) {
      const low = str.charCodeAt(index + 1);
      if (low >= 0xdc00 && low <= 0xdfff) {
        index++;
        codePoint = (codePoint - 0xd800 << 10) + low - 0xdc00 + 0x10000;
      }
    }
    if (codePoint <= 0x7f) {
      encoded.push(codePoint);
    } else if (codePoint <= 0x7ff) {
      encoded.push(codePoint >> 6 & 0x1f | 0xc0, codePoint & 0x3f | 0x80);
    } else if (codePoint <= 0xffff) {
      encoded.push(codePoint >> 12 | 0xe0, codePoint >> 6 & 0x3f | 0x80, codePoint & 0x3f | 0x80);
    } else if (codePoint <= 0x1fffff) {
      encoded.push(codePoint >> 18 & 0x07 | 0xf0, codePoint >> 12 & 0x3f | 0x80, codePoint >> 6 & 0x3f | 0x80, codePoint & 0x3f | 0x80);
    }
  }
  return encoded;
}
function stringify(token) {
  if (typeof token === 'string') {
    return token;
  }
  if (Array.isArray(token)) {
    return `[${token.map(stringify).join(', ')}]`;
  }
  if (token == null) {
    return '' + token;
  }
  const name = token.overriddenName || token.name;
  if (name) {
    return `${name}`;
  }
  if (!token.toString) {
    return 'object';
  }
  const result = token.toString();
  if (result == null) {
    return '' + result;
  }
  const newLineIndex = result.indexOf('\n');
  return newLineIndex >= 0 ? result.slice(0, newLineIndex) : result;
}
class Version {
  full;
  major;
  minor;
  patch;
  constructor(full) {
    this.full = full;
    const splits = full.split('.');
    this.major = splits[0];
    this.minor = splits[1];
    this.patch = splits.slice(2).join('.');
  }
}
const _global = globalThis;
const V1_TO_18 = /^([1-9]|1[0-8])\./;
function getJitStandaloneDefaultForVersion(version) {
  if (version.startsWith('0.')) {
    return true;
  }
  if (V1_TO_18.test(version)) {
    return false;
  }
  return true;
}
function namespaceCssVariable(varName) {
  if (varName.startsWith('--global--')) {
    return '--' + varName.substring('--global--'.length);
  } else {
    return '--%NS%' + varName.substring('--'.length);
  }
}

const VERSION$1 = 3;
const JS_B64_PREFIX = '# sourceMappingURL=data:application/json;base64,';
class SourceMapGenerator {
  file;
  sourcesContent = new Map();
  lines = [];
  lastCol0 = 0;
  hasMappings = false;
  constructor(file = null) {
    this.file = file;
  }
  addSource(url, content = null) {
    if (!this.sourcesContent.has(url)) {
      this.sourcesContent.set(url, content);
    }
    return this;
  }
  addLine() {
    this.lines.push([]);
    this.lastCol0 = 0;
    return this;
  }
  addMapping(col0, sourceUrl, sourceLine0, sourceCol0) {
    if (!this.currentLine) {
      throw new Error(`A line must be added before mappings can be added`);
    }
    if (sourceUrl != null && !this.sourcesContent.has(sourceUrl)) {
      throw new Error(`Unknown source file "${sourceUrl}"`);
    }
    if (col0 == null) {
      throw new Error(`The column in the generated code must be provided`);
    }
    if (col0 < this.lastCol0) {
      throw new Error(`Mapping should be added in output order`);
    }
    if (sourceUrl && (sourceLine0 == null || sourceCol0 == null)) {
      throw new Error(`The source location must be provided when a source url is provided`);
    }
    this.hasMappings = true;
    this.lastCol0 = col0;
    this.currentLine.push({
      col0,
      sourceUrl,
      sourceLine0,
      sourceCol0
    });
    return this;
  }
  get currentLine() {
    return this.lines.slice(-1)[0];
  }
  toJSON() {
    if (!this.hasMappings) {
      return null;
    }
    const sourcesIndex = new Map();
    const sources = [];
    const sourcesContent = [];
    Array.from(this.sourcesContent.keys()).forEach((url, i) => {
      sourcesIndex.set(url, i);
      sources.push(url);
      sourcesContent.push(this.sourcesContent.get(url) || null);
    });
    let mappings = '';
    let lastCol0 = 0;
    let lastSourceIndex = 0;
    let lastSourceLine0 = 0;
    let lastSourceCol0 = 0;
    this.lines.forEach(segments => {
      lastCol0 = 0;
      mappings += segments.map(segment => {
        let segAsStr = toBase64VLQ(segment.col0 - lastCol0);
        lastCol0 = segment.col0;
        if (segment.sourceUrl != null) {
          segAsStr += toBase64VLQ(sourcesIndex.get(segment.sourceUrl) - lastSourceIndex);
          lastSourceIndex = sourcesIndex.get(segment.sourceUrl);
          segAsStr += toBase64VLQ(segment.sourceLine0 - lastSourceLine0);
          lastSourceLine0 = segment.sourceLine0;
          segAsStr += toBase64VLQ(segment.sourceCol0 - lastSourceCol0);
          lastSourceCol0 = segment.sourceCol0;
        }
        return segAsStr;
      }).join(',');
      mappings += ';';
    });
    mappings = mappings.slice(0, -1);
    return {
      'file': this.file || '',
      'version': VERSION$1,
      'sourceRoot': '',
      'sources': sources,
      'sourcesContent': sourcesContent,
      'mappings': mappings
    };
  }
  toJsComment() {
    return this.hasMappings ? '//' + JS_B64_PREFIX + toBase64String(JSON.stringify(this, null, 0)) : '';
  }
}
function toBase64String(value) {
  let b64 = '';
  const encoded = utf8Encode(value);
  for (let i = 0; i < encoded.length;) {
    const i1 = encoded[i++];
    const i2 = i < encoded.length ? encoded[i++] : null;
    const i3 = i < encoded.length ? encoded[i++] : null;
    b64 += toBase64Digit(i1 >> 2);
    b64 += toBase64Digit((i1 & 3) << 4 | (i2 === null ? 0 : i2 >> 4));
    b64 += i2 === null ? '=' : toBase64Digit((i2 & 15) << 2 | (i3 === null ? 0 : i3 >> 6));
    b64 += i2 === null || i3 === null ? '=' : toBase64Digit(i3 & 63);
  }
  return b64;
}
function toBase64VLQ(value) {
  value = value < 0 ? (-value << 1) + 1 : value << 1;
  let out = '';
  do {
    let digit = value & 31;
    value = value >> 5;
    if (value > 0) {
      digit = digit | 32;
    }
    out += toBase64Digit(digit);
  } while (value > 0);
  return out;
}
const B64_DIGITS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
function toBase64Digit(value) {
  if (value < 0 || value >= 64) {
    throw new Error(`Can only encode value in the range [0, 63]`);
  }
  return B64_DIGITS[value];
}

const SINGLE_QUOTE_ESCAPE_STRING_RE = /'|\\|\n|\r/g;
const LEGAL_IDENTIFIER_RE = /^[$A-Z_][0-9A-Z_$]*$/i;
const INDENT_WITH = '  ';
class EmittedLine {
  indent;
  partsLength = 0;
  parts = [];
  srcSpans = [];
  constructor(indent) {
    this.indent = indent;
  }
}
const BINARY_OPERATORS$1 = new Map([[BinaryOperator.And, '&&'], [BinaryOperator.Bigger, '>'], [BinaryOperator.BiggerEquals, '>='], [BinaryOperator.BitwiseOr, '|'], [BinaryOperator.BitwiseAnd, '&'], [BinaryOperator.Divide, '/'], [BinaryOperator.Assign, '='], [BinaryOperator.Equals, '=='], [BinaryOperator.Identical, '==='], [BinaryOperator.Lower, '<'], [BinaryOperator.LowerEquals, '<='], [BinaryOperator.Minus, '-'], [BinaryOperator.Modulo, '%'], [BinaryOperator.Exponentiation, '**'], [BinaryOperator.Multiply, '*'], [BinaryOperator.NotEquals, '!='], [BinaryOperator.NotIdentical, '!=='], [BinaryOperator.NullishCoalesce, '??'], [BinaryOperator.Or, '||'], [BinaryOperator.Plus, '+'], [BinaryOperator.In, 'in'], [BinaryOperator.InstanceOf, 'instanceof'], [BinaryOperator.AdditionAssignment, '+='], [BinaryOperator.SubtractionAssignment, '-='], [BinaryOperator.MultiplicationAssignment, '*='], [BinaryOperator.DivisionAssignment, '/='], [BinaryOperator.RemainderAssignment, '%='], [BinaryOperator.ExponentiationAssignment, '**='], [BinaryOperator.AndAssignment, '&&='], [BinaryOperator.OrAssignment, '||='], [BinaryOperator.NullishCoalesceAssignment, '??=']]);
class EmitterVisitorContext {
  _indent;
  static createRoot() {
    return new EmitterVisitorContext(0);
  }
  _lines;
  constructor(_indent) {
    this._indent = _indent;
    this._lines = [new EmittedLine(_indent)];
  }
  get _currentLine() {
    return this._lines[this._lines.length - 1];
  }
  println(from, lastPart = '') {
    this.print(from || null, lastPart, true);
  }
  lineIsEmpty() {
    return this._currentLine.parts.length === 0;
  }
  lineLength() {
    return this._currentLine.indent * INDENT_WITH.length + this._currentLine.partsLength;
  }
  print(from, part, newLine = false) {
    if (part.length > 0) {
      this._currentLine.parts.push(part);
      this._currentLine.partsLength += part.length;
      this._currentLine.srcSpans.push(from && from.sourceSpan || null);
    }
    if (newLine) {
      this._lines.push(new EmittedLine(this._indent));
    }
  }
  removeEmptyLastLine() {
    if (this.lineIsEmpty()) {
      this._lines.pop();
    }
  }
  incIndent() {
    this._indent++;
    if (this.lineIsEmpty()) {
      this._currentLine.indent = this._indent;
    }
  }
  decIndent() {
    this._indent--;
    if (this.lineIsEmpty()) {
      this._currentLine.indent = this._indent;
    }
  }
  toSource() {
    return this.sourceLines.map(l => l.parts.length > 0 ? INDENT_WITH.repeat(l.indent) + l.parts.join('') : '').join('\n');
  }
  toSourceMapGenerator(genFilePath, startsAtLine = 0) {
    const map = new SourceMapGenerator(genFilePath);
    let firstOffsetMapped = false;
    const mapFirstOffsetIfNeeded = () => {
      if (!firstOffsetMapped) {
        map.addSource(genFilePath, ' ').addMapping(0, genFilePath, 0, 0);
        firstOffsetMapped = true;
      }
    };
    for (let i = 0; i < startsAtLine; i++) {
      map.addLine();
      mapFirstOffsetIfNeeded();
    }
    this.sourceLines.forEach((line, lineIdx) => {
      map.addLine();
      const spans = line.srcSpans;
      const parts = line.parts;
      let col0 = line.indent * INDENT_WITH.length;
      let spanIdx = 0;
      while (spanIdx < spans.length && !spans[spanIdx]) {
        col0 += parts[spanIdx].length;
        spanIdx++;
      }
      if (spanIdx < spans.length && lineIdx === 0 && col0 === 0) {
        firstOffsetMapped = true;
      } else {
        mapFirstOffsetIfNeeded();
      }
      while (spanIdx < spans.length) {
        const span = spans[spanIdx];
        const source = span.start.file;
        const sourceLine = span.start.line;
        const sourceCol = span.start.col;
        map.addSource(source.url, source.content).addMapping(col0, source.url, sourceLine, sourceCol);
        col0 += parts[spanIdx].length;
        spanIdx++;
        while (spanIdx < spans.length && (span === spans[spanIdx] || !spans[spanIdx])) {
          col0 += parts[spanIdx].length;
          spanIdx++;
        }
      }
    });
    return map;
  }
  spanOf(line, column) {
    const emittedLine = this._lines[line];
    if (emittedLine) {
      let columnsLeft = column - INDENT_WITH.repeat(emittedLine.indent).length;
      for (let partIndex = 0; partIndex < emittedLine.parts.length; partIndex++) {
        const part = emittedLine.parts[partIndex];
        if (part.length > columnsLeft) {
          return emittedLine.srcSpans[partIndex];
        }
        columnsLeft -= part.length;
      }
    }
    return null;
  }
  get sourceLines() {
    if (this._lines.length && this._lines[this._lines.length - 1].parts.length === 0) {
      return this._lines.slice(0, -1);
    }
    return this._lines;
  }
}
class AbstractEmitterVisitor {
  printComments;
  printTypes;
  lastIfCondition = null;
  constructor(printComments, printTypes) {
    this.printComments = printComments;
    this.printTypes = printTypes;
  }
  visitExpressionStmt(stmt, ctx) {
    this.printLeadingComments(stmt, ctx);
    stmt.expr.visitExpression(this, ctx);
    ctx.println(stmt, ';');
  }
  visitReturnStmt(stmt, ctx) {
    this.printLeadingComments(stmt, ctx);
    ctx.print(stmt, `return `);
    stmt.value.visitExpression(this, ctx);
    ctx.println(stmt, ';');
  }
  visitIfStmt(stmt, ctx) {
    this.printLeadingComments(stmt, ctx);
    ctx.print(stmt, `if (`);
    this.lastIfCondition = stmt.condition;
    stmt.condition.visitExpression(this, ctx);
    this.lastIfCondition = null;
    ctx.print(stmt, `) {`);
    const hasElseCase = stmt.falseCase != null && stmt.falseCase.length > 0;
    if (stmt.trueCase.length <= 1 && !hasElseCase) {
      ctx.print(stmt, ` `);
      this.visitAllStatements(stmt.trueCase, ctx);
      ctx.removeEmptyLastLine();
      ctx.print(stmt, ` `);
    } else {
      ctx.println();
      ctx.incIndent();
      this.visitAllStatements(stmt.trueCase, ctx);
      ctx.decIndent();
      if (hasElseCase) {
        ctx.println(stmt, `} else {`);
        ctx.incIndent();
        this.visitAllStatements(stmt.falseCase, ctx);
        ctx.decIndent();
      }
    }
    ctx.println(stmt, `}`);
  }
  visitDeclareVarStmt(stmt, ctx) {
    const varKind = stmt.hasModifier(StmtModifier.Final) ? 'const' : 'let';
    this.printLeadingComments(stmt, ctx);
    ctx.print(stmt, `${varKind} ${stmt.name}`);
    stmt.type?.visitType(this, ctx);
    if (stmt.value) {
      ctx.print(stmt, ' = ');
      stmt.value.visitExpression(this, ctx);
    }
    ctx.println(stmt, `;`);
  }
  visitInvokeFunctionExpr(expr, ctx) {
    this.printLeadingComments(expr, ctx);
    const shouldParenthesize = this.shouldParenthesize(expr.fn, expr);
    if (shouldParenthesize) {
      ctx.print(expr.fn, '(');
    }
    expr.fn.visitExpression(this, ctx);
    if (shouldParenthesize) {
      ctx.print(expr.fn, ')');
    }
    ctx.print(expr, expr.isOptional ? '?.(' : '(');
    this.visitAllExpressions(expr.args, ctx, ',');
    ctx.print(expr, ')');
  }
  visitTaggedTemplateLiteralExpr(expr, ctx) {
    this.printLeadingComments(expr, ctx);
    expr.tag.visitExpression(this, ctx);
    expr.template.visitExpression(this, ctx);
  }
  visitTemplateLiteralExpr(expr, ctx) {
    this.printLeadingComments(expr, ctx);
    ctx.print(expr, '`');
    for (let i = 0; i < expr.elements.length; i++) {
      expr.elements[i].visitExpression(this, ctx);
      const expression = i < expr.expressions.length ? expr.expressions[i] : null;
      if (expression !== null) {
        ctx.print(expression, '${');
        expression.visitExpression(this, ctx);
        ctx.print(expression, '}');
      }
    }
    ctx.print(expr, '`');
  }
  visitTemplateLiteralElementExpr(expr, ctx) {
    this.printLeadingComments(expr, ctx);
    ctx.print(expr, expr.rawText);
  }
  visitTypeofExpr(expr, ctx) {
    this.printLeadingComments(expr, ctx);
    ctx.print(expr, 'typeof ');
    expr.expr.visitExpression(this, ctx);
  }
  visitVoidExpr(expr, ctx) {
    this.printLeadingComments(expr, ctx);
    ctx.print(expr, 'void ');
    expr.expr.visitExpression(this, ctx);
  }
  visitReadVarExpr(ast, ctx) {
    this.printLeadingComments(ast, ctx);
    ctx.print(ast, ast.name);
  }
  visitInstantiateExpr(ast, ctx) {
    this.printLeadingComments(ast, ctx);
    ctx.print(ast, `new `);
    ast.classExpr.visitExpression(this, ctx);
    ctx.print(ast, `(`);
    this.visitAllExpressions(ast.args, ctx, ',');
    ctx.print(ast, `)`);
  }
  visitLiteralExpr(ast, ctx) {
    this.printLeadingComments(ast, ctx);
    const value = ast.value;
    if (typeof value === 'string') {
      ctx.print(ast, escapeIdentifier(value));
    } else {
      ctx.print(ast, `${value}`);
    }
  }
  visitRegularExpressionLiteral(ast, ctx) {
    this.printLeadingComments(ast, ctx);
    ctx.print(ast, `/${ast.body}/${ast.flags || ''}`);
  }
  visitLocalizedString(ast, ctx) {
    this.printLeadingComments(ast, ctx);
    const head = ast.serializeI18nHead();
    ctx.print(ast, '$localize `' + head.raw);
    for (let i = 1; i < ast.messageParts.length; i++) {
      ctx.print(ast, '${');
      ast.expressions[i - 1].visitExpression(this, ctx);
      ctx.print(ast, `}${ast.serializeI18nTemplatePart(i).raw}`);
    }
    ctx.print(ast, '`');
  }
  visitConditionalExpr(ast, ctx) {
    this.printLeadingComments(ast, ctx);
    ctx.print(ast, `(`);
    ast.condition.visitExpression(this, ctx);
    ctx.print(ast, ' ? ');
    ast.trueCase.visitExpression(this, ctx);
    ctx.print(ast, ' : ');
    ast.falseCase?.visitExpression(this, ctx);
    ctx.print(ast, `)`);
  }
  visitDynamicImportExpr(ast, ctx) {
    this.printLeadingComments(ast, ctx);
    ctx.print(ast, `import(`);
    if (typeof ast.url === 'string') {
      ctx.print(ast, escapeIdentifier(ast.url, true));
    } else {
      ast.url.visitExpression(this, ctx);
    }
    ctx.print(ast, `)`);
  }
  visitNotExpr(ast, ctx) {
    this.printLeadingComments(ast, ctx);
    ctx.print(ast, '!');
    ast.condition.visitExpression(this, ctx);
  }
  visitFunctionExpr(ast, ctx) {
    this.printLeadingComments(ast, ctx);
    ctx.print(ast, `function${ast.name ? ' ' + ast.name : ''}(`);
    this.visitParams(ast.params, ctx);
    ctx.print(ast, `)`);
    ast.type?.visitType(this, ctx);
    ctx.print(ast, ` {`);
    ctx.println(ast);
    ctx.incIndent();
    this.visitAllStatements(ast.statements, ctx);
    ctx.decIndent();
    ctx.println(ast, `}`);
  }
  visitArrowFunctionExpr(ast, ctx) {
    this.printLeadingComments(ast, ctx);
    ctx.print(ast, '(');
    this.visitParams(ast.params, ctx);
    ctx.print(ast, ')');
    ast.type?.visitType(this, ctx);
    ctx.print(ast, ' => ');
    if (Array.isArray(ast.body)) {
      ctx.print(ast, `{`);
      ctx.println(ast);
      ctx.incIndent();
      this.visitAllStatements(ast.body, ctx);
      ctx.decIndent();
      ctx.println(ast, `}`);
    } else {
      const shouldParenthesize = this.shouldParenthesize(ast.body, ast);
      if (shouldParenthesize) {
        ctx.print(ast, '(');
      }
      ast.body.visitExpression(this, ctx);
      if (shouldParenthesize) {
        ctx.print(ast, ')');
      }
    }
  }
  visitDeclareFunctionStmt(stmt, ctx) {
    this.printLeadingComments(stmt, ctx);
    ctx.print(stmt, `function ${stmt.name}(`);
    this.visitParams(stmt.params, ctx);
    ctx.print(stmt, `)`);
    stmt.type?.visitType(this, ctx);
    ctx.print(stmt, ` {`);
    ctx.println(stmt);
    ctx.incIndent();
    this.visitAllStatements(stmt.statements, ctx);
    ctx.decIndent();
    ctx.println(stmt, `}`);
  }
  visitUnaryOperatorExpr(ast, ctx) {
    this.printLeadingComments(ast, ctx);
    let opStr;
    switch (ast.operator) {
      case UnaryOperator.Plus:
        opStr = '+';
        break;
      case UnaryOperator.Minus:
        opStr = '-';
        break;
      default:
        throw new Error(`Unknown operator ${ast.operator}`);
    }
    const parens = ast !== this.lastIfCondition;
    if (parens) ctx.print(ast, `(`);
    ctx.print(ast, opStr);
    ast.expr.visitExpression(this, ctx);
    if (parens) ctx.print(ast, `)`);
  }
  visitBinaryOperatorExpr(ast, ctx) {
    this.printLeadingComments(ast, ctx);
    const operator = BINARY_OPERATORS$1.get(ast.operator);
    if (!operator) {
      throw new Error(`Unknown operator ${ast.operator}`);
    }
    const parens = ast !== this.lastIfCondition;
    if (parens) ctx.print(ast, `(`);
    ast.lhs.visitExpression(this, ctx);
    ctx.print(ast, ` ${operator} `);
    ast.rhs.visitExpression(this, ctx);
    if (parens) ctx.print(ast, `)`);
  }
  visitReadPropExpr(ast, ctx) {
    this.printLeadingComments(ast, ctx);
    ast.receiver.visitExpression(this, ctx);
    ctx.print(ast, ast.isOptional ? `?.` : `.`);
    ctx.print(ast, ast.name);
  }
  visitReadKeyExpr(ast, ctx) {
    this.printLeadingComments(ast, ctx);
    ast.receiver.visitExpression(this, ctx);
    ctx.print(ast, ast.isOptional ? `?.[` : `[`);
    ast.index.visitExpression(this, ctx);
    ctx.print(ast, `]`);
  }
  visitLiteralArrayExpr(ast, ctx) {
    this.printLeadingComments(ast, ctx);
    ctx.print(ast, `[`);
    this.visitAllExpressions(ast.entries, ctx, ', ');
    ctx.print(ast, `]`);
  }
  visitLiteralMapExpr(ast, ctx) {
    this.printLeadingComments(ast, ctx);
    ctx.print(ast, `{`);
    this.visitAllObjects(entry => {
      if (entry instanceof LiteralMapSpreadAssignment) {
        ctx.print(ast, '...');
        entry.expression.visitExpression(this, ctx);
      } else {
        ctx.print(ast, `${escapeIdentifier(entry.key, entry.quoted)}: `);
        entry.value.visitExpression(this, ctx);
      }
    }, ast.entries, ctx, ', ');
    ctx.print(ast, `}`);
  }
  visitCommaExpr(ast, ctx) {
    this.printLeadingComments(ast, ctx);
    ctx.print(ast, '(');
    this.visitAllExpressions(ast.parts, ctx, ', ');
    ctx.print(ast, ')');
  }
  visitParenthesizedExpr(ast, ctx) {
    this.printLeadingComments(ast, ctx);
    ast.expr.visitExpression(this, ctx);
  }
  visitSpreadElementExpr(ast, ctx) {
    this.printLeadingComments(ast, ctx);
    ctx.print(ast, '...');
    ast.expression.visitExpression(this, ctx);
  }
  visitBuiltinType(type, ctx) {
    if (!this.printTypes) {
      return;
    }
    switch (type.name) {
      case BuiltinTypeName.Bool:
        ctx.print(null, ': boolean');
        break;
      case BuiltinTypeName.Dynamic:
        ctx.print(null, ': any');
        break;
      case BuiltinTypeName.Int:
      case BuiltinTypeName.Number:
        ctx.print(null, ': number');
        break;
      case BuiltinTypeName.String:
        ctx.print(null, ': string');
        break;
      case BuiltinTypeName.None:
        ctx.print(null, ': void');
        break;
      case BuiltinTypeName.Inferred:
        break;
      case BuiltinTypeName.Function:
        ctx.print(null, ': Function');
        break;
      default:
        ctx.print(null, ': any');
        break;
    }
  }
  visitExpressionType(type, ctx) {
    if (!this.printTypes) {
      return;
    }
    ctx.print(null, ': ');
    type.value.visitExpression(this, ctx);
    if (type.typeParams && type.typeParams.length > 0) {
      ctx.print(null, '<');
      this.visitAllObjects(param => param.visitType(this, ctx), type.typeParams, ctx, ',');
      ctx.print(null, '>');
    }
  }
  visitArrayType(type, ctx) {
    if (!this.printTypes) {
      return;
    }
    ctx.print(null, ': ');
    type.of.visitType(this, ctx);
    ctx.print(null, '[]');
  }
  visitMapType(type, ctx) {
    if (!this.printTypes) {
      return;
    }
    ctx.print(null, ': { [key: string]: ');
    if (type.valueType) {
      type.valueType.visitType(this, ctx);
    } else {
      ctx.print(null, 'any');
    }
    ctx.print(null, '}');
  }
  visitTransplantedType(type, ctx) {
    throw new Error('TransplantedType nodes are not supported');
  }
  visitAllExpressions(expressions, ctx, separator) {
    this.visitAllObjects(expr => expr.visitExpression(this, ctx), expressions, ctx, separator);
  }
  visitAllObjects(handler, expressions, ctx, separator) {
    for (let i = 0; i < expressions.length; i++) {
      if (i > 0) {
        ctx.print(null, separator, false);
      }
      handler(expressions[i]);
    }
  }
  visitAllStatements(statements, ctx) {
    statements.forEach(stmt => stmt.visitStatement(this, ctx));
  }
  visitParams(params, ctx) {
    this.visitAllObjects(param => {
      ctx.print(null, param.name);
      param.type?.visitType(this, ctx);
    }, params, ctx, ', ');
  }
  shouldParenthesize(expression, containingExpression) {
    return ((expression instanceof ArrowFunctionExpr$1 || expression instanceof FunctionExpr) && containingExpression instanceof InvokeFunctionExpr || expression instanceof LiteralMapExpr && containingExpression instanceof ArrowFunctionExpr$1
    );
  }
  printLeadingComments(node, ctx) {
    if (!this.printComments || node.leadingComments === undefined) {
      return;
    }
    for (const comment of node.leadingComments) {
      if (comment instanceof JSDocComment) {
        ctx.print(node, `/*${comment.toString()}*/`, comment.trailingNewline);
      } else {
        if (comment.multiline) {
          ctx.print(node, `/* ${comment.text} */`, comment.trailingNewline);
        } else {
          comment.text.split('\n').forEach(line => ctx.println(node, `// ${line}`));
        }
      }
    }
  }
}
function escapeIdentifier(input, alwaysQuote = true) {
  if (input == null) {
    return null;
  }
  const body = input.replace(SINGLE_QUOTE_ESCAPE_STRING_RE, (...match) => {
    if (match[0] == '\n') {
      return '\\n';
    } else if (match[0] == '\r') {
      return '\\r';
    } else {
      return `\\${match[0]}`;
    }
  });
  const requiresQuotes = alwaysQuote || !LEGAL_IDENTIFIER_RE.test(body);
  return requiresQuotes ? `'${body}'` : body;
}

const UNSAFE_OBJECT_KEY_NAME_REGEXP = /[-.]/;
const IDENTIFIER_PATTERN = /^[$A-Z_][0-9A-Z_$]*$/i;
const LET_PATTERN = /^let\s+([\S\s]*)/;
function typeWithParameters(type, numParams) {
  if (numParams === 0) {
    return expressionType(type);
  }
  const params = [];
  for (let i = 0; i < numParams; i++) {
    params.push(DYNAMIC_TYPE);
  }
  return expressionType(type, undefined, params);
}
function getSafePropertyAccessString(accessor, name) {
  const escapedName = escapeIdentifier(name, false);
  return escapedName !== name ? `${accessor}[${escapedName}]` : `${accessor}.${name}`;
}
function jitOnlyGuardedExpression(expr) {
  return guardedExpression('ngJitMode', expr);
}
function devOnlyGuardedExpression(expr) {
  return guardedExpression('ngDevMode', expr);
}
function guardedExpression(guard, expr) {
  const guardExpr = new ExternalExpr({
    name: guard,
    moduleName: null
  });
  const guardNotDefined = new BinaryOperatorExpr(BinaryOperator.Identical, new TypeofExpr(guardExpr), literal('undefined'));
  const guardUndefinedOrTrue = new BinaryOperatorExpr(BinaryOperator.Or, guardNotDefined, guardExpr, undefined, undefined);
  return new BinaryOperatorExpr(BinaryOperator.And, guardUndefinedOrTrue, expr);
}
function wrapReference(value) {
  const wrapped = new WrappedNodeExpr(value);
  return {
    value: wrapped,
    type: wrapped
  };
}
function refsToArray(refs, shouldForwardDeclare) {
  const values = literalArr(refs.map(ref => ref.value));
  return shouldForwardDeclare ? arrowFn([], values) : values;
}
function tsIgnoreComment() {
  return leadingComment('@ts-ignore', true, true);
}
function isUnsafeObjectKey(key) {
  return UNSAFE_OBJECT_KEY_NAME_REGEXP.test(key);
}
function createMayBeForwardRefExpression(expression, forwardRef) {
  return {
    expression,
    forwardRef
  };
}
function convertFromMaybeForwardRefExpression({
  expression,
  forwardRef
}) {
  switch (forwardRef) {
    case 0:
    case 1:
      return expression;
    case 2:
      return generateForwardRef(expression);
  }
}
function generateForwardRef(expr) {
  return importExpr(Identifiers.forwardRef).callFn([arrowFn([], expr)]);
}

var R3FactoryDelegateType;
(function (R3FactoryDelegateType) {
  R3FactoryDelegateType[R3FactoryDelegateType["Class"] = 0] = "Class";
  R3FactoryDelegateType[R3FactoryDelegateType["Function"] = 1] = "Function";
})(R3FactoryDelegateType || (R3FactoryDelegateType = {}));
function compileFactoryFunction(meta) {
  const t = variable('__ngFactoryType__');
  let baseFactoryVar = null;
  const typeForCtor = !isDelegatedFactoryMetadata(meta) ? new BinaryOperatorExpr(BinaryOperator.Or, t, meta.type.value) : t;
  let ctorExpr = null;
  const factoryComments = meta.deps !== null && meta.deps !== 'invalid' && meta.deps.length > 0 ? [tsIgnoreComment()] : undefined;
  if (meta.deps !== null) {
    if (meta.deps !== 'invalid') {
      ctorExpr = new InstantiateExpr(typeForCtor, injectDependencies(meta.deps, meta.target));
    }
  } else {
    baseFactoryVar = variable(`ɵ${meta.name}_BaseFactory`);
    ctorExpr = baseFactoryVar.callFn([typeForCtor]);
  }
  const body = [];
  let retExpr = null;
  function makeConditionalFactory(nonCtorExpr) {
    const r = variable('__ngConditionalFactory__');
    body.push(new DeclareVarStmt(r.name, NULL_EXPR, DYNAMIC_TYPE));
    const ctorStmt = ctorExpr !== null ? r.set(ctorExpr).toStmt(factoryComments) : importExpr(Identifiers.invalidFactory).callFn([]).toStmt();
    body.push(ifStmt(t, [ctorStmt], [r.set(nonCtorExpr).toStmt([tsIgnoreComment()])]));
    return r;
  }
  if (isDelegatedFactoryMetadata(meta)) {
    const delegateArgs = injectDependencies(meta.delegateDeps, meta.target);
    const factoryExpr = new (meta.delegateType === R3FactoryDelegateType.Class ? InstantiateExpr : InvokeFunctionExpr)(meta.delegate, delegateArgs);
    retExpr = makeConditionalFactory(factoryExpr);
  } else if (isExpressionFactoryMetadata(meta)) {
    retExpr = makeConditionalFactory(meta.expression);
  } else {
    retExpr = ctorExpr;
  }
  if (retExpr === null) {
    body.push(importExpr(Identifiers.invalidFactory).callFn([]).toStmt());
  } else if (baseFactoryVar !== null) {
    const getInheritedFactoryCall = importExpr(Identifiers.getInheritedFactory).callFn([meta.type.value]);
    const baseFactory = new BinaryOperatorExpr(BinaryOperator.Or, baseFactoryVar, baseFactoryVar.set(getInheritedFactoryCall));
    body.push(new ReturnStatement(baseFactory.callFn([typeForCtor])));
  } else {
    body.push(new ReturnStatement(retExpr, null, factoryComments));
  }
  let factoryFn = fn([new FnParam(t.name, DYNAMIC_TYPE)], body, INFERRED_TYPE, undefined, `${meta.name}_Factory`);
  if (baseFactoryVar !== null) {
    factoryFn = arrowFn([], [new DeclareVarStmt(baseFactoryVar.name, undefined, DYNAMIC_TYPE), new ReturnStatement(factoryFn)]).callFn([], undefined, true);
  }
  return {
    expression: factoryFn,
    statements: [],
    type: createFactoryType(meta)
  };
}
function createFactoryType(meta) {
  const ctorDepsType = meta.deps !== null && meta.deps !== 'invalid' ? createCtorDepsType(meta.deps) : NONE_TYPE;
  return expressionType(importExpr(Identifiers.FactoryDeclaration, [typeWithParameters(meta.type.type, meta.typeArgumentCount), ctorDepsType]));
}
function injectDependencies(deps, target) {
  return deps.map((dep, index) => compileInjectDependency(dep, target, index));
}
function compileInjectDependency(dep, target, index) {
  if (dep.token === null) {
    return importExpr(Identifiers.invalidFactoryDep).callFn([literal(index)]);
  } else if (dep.attributeNameType === null) {
    const flags = 0 | (dep.self ? 2 : 0) | (dep.skipSelf ? 4 : 0) | (dep.host ? 1 : 0) | (dep.optional ? 8 : 0) | (target === FactoryTarget.Pipe ? 16 : 0);
    let flagsParam = flags !== 0 || dep.optional ? literal(flags) : null;
    const injectArgs = [dep.token];
    if (flagsParam) {
      injectArgs.push(flagsParam);
    }
    const injectFn = getInjectFn(target);
    return importExpr(injectFn).callFn(injectArgs);
  } else {
    return importExpr(Identifiers.injectAttribute).callFn([dep.token]);
  }
}
function createCtorDepsType(deps) {
  let hasTypes = false;
  const attributeTypes = deps.map(dep => {
    const type = createCtorDepType(dep);
    if (type !== null) {
      hasTypes = true;
      return type;
    } else {
      return literal(null);
    }
  });
  if (hasTypes) {
    return expressionType(literalArr(attributeTypes));
  } else {
    return NONE_TYPE;
  }
}
function createCtorDepType(dep) {
  const entries = [];
  if (dep.attributeNameType !== null) {
    entries.push({
      key: 'attribute',
      value: dep.attributeNameType,
      quoted: false
    });
  }
  if (dep.optional) {
    entries.push({
      key: 'optional',
      value: literal(true),
      quoted: false
    });
  }
  if (dep.host) {
    entries.push({
      key: 'host',
      value: literal(true),
      quoted: false
    });
  }
  if (dep.self) {
    entries.push({
      key: 'self',
      value: literal(true),
      quoted: false
    });
  }
  if (dep.skipSelf) {
    entries.push({
      key: 'skipSelf',
      value: literal(true),
      quoted: false
    });
  }
  return entries.length > 0 ? literalMap(entries) : null;
}
function isDelegatedFactoryMetadata(meta) {
  return meta.delegateType !== undefined;
}
function isExpressionFactoryMetadata(meta) {
  return meta.expression !== undefined;
}
function getInjectFn(target) {
  switch (target) {
    case FactoryTarget.Component:
    case FactoryTarget.Directive:
    case FactoryTarget.Pipe:
      return Identifiers.directiveInject;
    case FactoryTarget.NgModule:
    case FactoryTarget.Injectable:
    default:
      return Identifiers.inject;
  }
}

class ParseSpan {
  start;
  end;
  constructor(start, end) {
    this.start = start;
    this.end = end;
  }
  toAbsolute(absoluteOffset) {
    return new AbsoluteSourceSpan(absoluteOffset + this.start, absoluteOffset + this.end);
  }
}
class AST {
  span;
  sourceSpan;
  constructor(span, sourceSpan) {
    this.span = span;
    this.sourceSpan = sourceSpan;
  }
  toString() {
    return 'AST';
  }
}
class ASTWithName extends AST {
  nameSpan;
  constructor(span, sourceSpan, nameSpan) {
    super(span, sourceSpan);
    this.nameSpan = nameSpan;
  }
}
let EmptyExpr$1 = class EmptyExpr extends AST {
  visit(visitor, context = null) {
    return visitor.visitEmptyExpr?.(this, context);
  }
};
class ImplicitReceiver extends AST {
  visit(visitor, context = null) {
    return visitor.visitImplicitReceiver(this, context);
  }
}
class ThisReceiver extends AST {
  visit(visitor, context = null) {
    return visitor.visitThisReceiver?.(this, context);
  }
}
class Chain extends AST {
  expressions;
  constructor(span, sourceSpan, expressions) {
    super(span, sourceSpan);
    this.expressions = expressions;
  }
  visit(visitor, context = null) {
    return visitor.visitChain(this, context);
  }
}
class Conditional extends AST {
  condition;
  trueExp;
  falseExp;
  constructor(span, sourceSpan, condition, trueExp, falseExp) {
    super(span, sourceSpan);
    this.condition = condition;
    this.trueExp = trueExp;
    this.falseExp = falseExp;
  }
  visit(visitor, context = null) {
    return visitor.visitConditional(this, context);
  }
}
class PropertyRead extends ASTWithName {
  receiver;
  name;
  constructor(span, sourceSpan, nameSpan, receiver, name) {
    super(span, sourceSpan, nameSpan);
    this.receiver = receiver;
    this.name = name;
  }
  visit(visitor, context = null) {
    return visitor.visitPropertyRead(this, context);
  }
}
class SafePropertyRead extends ASTWithName {
  receiver;
  name;
  constructor(span, sourceSpan, nameSpan, receiver, name) {
    super(span, sourceSpan, nameSpan);
    this.receiver = receiver;
    this.name = name;
  }
  visit(visitor, context = null) {
    return visitor.visitSafePropertyRead(this, context);
  }
}
class KeyedRead extends AST {
  receiver;
  key;
  constructor(span, sourceSpan, receiver, key) {
    super(span, sourceSpan);
    this.receiver = receiver;
    this.key = key;
  }
  visit(visitor, context = null) {
    return visitor.visitKeyedRead(this, context);
  }
}
class SafeKeyedRead extends AST {
  receiver;
  key;
  constructor(span, sourceSpan, receiver, key) {
    super(span, sourceSpan);
    this.receiver = receiver;
    this.key = key;
  }
  visit(visitor, context = null) {
    return visitor.visitSafeKeyedRead(this, context);
  }
}
var BindingPipeType;
(function (BindingPipeType) {
  BindingPipeType[BindingPipeType["ReferencedByName"] = 0] = "ReferencedByName";
  BindingPipeType[BindingPipeType["ReferencedDirectly"] = 1] = "ReferencedDirectly";
})(BindingPipeType || (BindingPipeType = {}));
class BindingPipe extends ASTWithName {
  exp;
  name;
  args;
  type;
  constructor(span, sourceSpan, exp, name, args, type, nameSpan) {
    super(span, sourceSpan, nameSpan);
    this.exp = exp;
    this.name = name;
    this.args = args;
    this.type = type;
  }
  visit(visitor, context = null) {
    return visitor.visitPipe(this, context);
  }
}
class LiteralPrimitive extends AST {
  value;
  constructor(span, sourceSpan, value) {
    super(span, sourceSpan);
    this.value = value;
  }
  visit(visitor, context = null) {
    return visitor.visitLiteralPrimitive(this, context);
  }
}
class LiteralArray extends AST {
  expressions;
  constructor(span, sourceSpan, expressions) {
    super(span, sourceSpan);
    this.expressions = expressions;
  }
  visit(visitor, context = null) {
    return visitor.visitLiteralArray(this, context);
  }
}
class SpreadElement extends AST {
  expression;
  constructor(span, sourceSpan, expression) {
    super(span, sourceSpan);
    this.expression = expression;
  }
  visit(visitor, context = null) {
    return visitor.visitSpreadElement(this, context);
  }
}
class LiteralMap extends AST {
  keys;
  values;
  constructor(span, sourceSpan, keys, values) {
    super(span, sourceSpan);
    this.keys = keys;
    this.values = values;
  }
  visit(visitor, context = null) {
    return visitor.visitLiteralMap(this, context);
  }
}
let Interpolation$1 = class Interpolation extends AST {
  strings;
  expressions;
  constructor(span, sourceSpan, strings, expressions) {
    super(span, sourceSpan);
    this.strings = strings;
    this.expressions = expressions;
  }
  visit(visitor, context = null) {
    return visitor.visitInterpolation(this, context);
  }
};
class Binary extends AST {
  operation;
  left;
  right;
  constructor(span, sourceSpan, operation, left, right) {
    super(span, sourceSpan);
    this.operation = operation;
    this.left = left;
    this.right = right;
  }
  visit(visitor, context = null) {
    return visitor.visitBinary(this, context);
  }
  static isAssignmentOperation(op) {
    return op === '=' || op === '+=' || op === '-=' || op === '*=' || op === '/=' || op === '%=' || op === '**=' || op === '&&=' || op === '||=' || op === '??=';
  }
}
class Unary extends Binary {
  operator;
  expr;
  left = null;
  right = null;
  operation = null;
  static createMinus(span, sourceSpan, expr) {
    return new Unary(span, sourceSpan, '-', expr, '-', new LiteralPrimitive(span, sourceSpan, 0), expr);
  }
  static createPlus(span, sourceSpan, expr) {
    return new Unary(span, sourceSpan, '+', expr, '-', expr, new LiteralPrimitive(span, sourceSpan, 0));
  }
  constructor(span, sourceSpan, operator, expr, binaryOp, binaryLeft, binaryRight) {
    super(span, sourceSpan, binaryOp, binaryLeft, binaryRight);
    this.operator = operator;
    this.expr = expr;
  }
  visit(visitor, context = null) {
    if (visitor.visitUnary !== undefined) {
      return visitor.visitUnary(this, context);
    }
    return visitor.visitBinary(this, context);
  }
}
class PrefixNot extends AST {
  expression;
  constructor(span, sourceSpan, expression) {
    super(span, sourceSpan);
    this.expression = expression;
  }
  visit(visitor, context = null) {
    return visitor.visitPrefixNot(this, context);
  }
}
class TypeofExpression extends AST {
  expression;
  constructor(span, sourceSpan, expression) {
    super(span, sourceSpan);
    this.expression = expression;
  }
  visit(visitor, context = null) {
    return visitor.visitTypeofExpression(this, context);
  }
}
class VoidExpression extends AST {
  expression;
  constructor(span, sourceSpan, expression) {
    super(span, sourceSpan);
    this.expression = expression;
  }
  visit(visitor, context = null) {
    return visitor.visitVoidExpression(this, context);
  }
}
class NonNullAssert extends AST {
  expression;
  constructor(span, sourceSpan, expression) {
    super(span, sourceSpan);
    this.expression = expression;
  }
  visit(visitor, context = null) {
    return visitor.visitNonNullAssert(this, context);
  }
}
class Call extends AST {
  receiver;
  args;
  argumentSpan;
  constructor(span, sourceSpan, receiver, args, argumentSpan) {
    super(span, sourceSpan);
    this.receiver = receiver;
    this.args = args;
    this.argumentSpan = argumentSpan;
  }
  visit(visitor, context = null) {
    return visitor.visitCall(this, context);
  }
}
class SafeCall extends AST {
  receiver;
  args;
  argumentSpan;
  constructor(span, sourceSpan, receiver, args, argumentSpan) {
    super(span, sourceSpan);
    this.receiver = receiver;
    this.args = args;
    this.argumentSpan = argumentSpan;
  }
  visit(visitor, context = null) {
    return visitor.visitSafeCall(this, context);
  }
}
class TaggedTemplateLiteral extends AST {
  tag;
  template;
  constructor(span, sourceSpan, tag, template) {
    super(span, sourceSpan);
    this.tag = tag;
    this.template = template;
  }
  visit(visitor, context) {
    return visitor.visitTaggedTemplateLiteral(this, context);
  }
}
class TemplateLiteral extends AST {
  elements;
  expressions;
  constructor(span, sourceSpan, elements, expressions) {
    super(span, sourceSpan);
    this.elements = elements;
    this.expressions = expressions;
  }
  visit(visitor, context) {
    return visitor.visitTemplateLiteral(this, context);
  }
}
class TemplateLiteralElement extends AST {
  text;
  constructor(span, sourceSpan, text) {
    super(span, sourceSpan);
    this.text = text;
  }
  visit(visitor, context) {
    return visitor.visitTemplateLiteralElement(this, context);
  }
}
class ParenthesizedExpression extends AST {
  expression;
  constructor(span, sourceSpan, expression) {
    super(span, sourceSpan);
    this.expression = expression;
  }
  visit(visitor, context) {
    return visitor.visitParenthesizedExpression(this, context);
  }
}
class ArrowFunctionIdentifierParameter {
  name;
  span;
  sourceSpan;
  constructor(name, span, sourceSpan) {
    this.name = name;
    this.span = span;
    this.sourceSpan = sourceSpan;
  }
}
class ArrowFunction extends AST {
  parameters;
  body;
  constructor(span, sourceSpan, parameters, body) {
    super(span, sourceSpan);
    this.parameters = parameters;
    this.body = body;
  }
  visit(visitor, context) {
    return visitor.visitArrowFunction(this, context);
  }
}
class RegularExpressionLiteral extends AST {
  body;
  flags;
  constructor(span, sourceSpan, body, flags) {
    super(span, sourceSpan);
    this.body = body;
    this.flags = flags;
  }
  visit(visitor, context) {
    return visitor.visitRegularExpressionLiteral(this, context);
  }
}
class AbsoluteSourceSpan {
  start;
  end;
  constructor(start, end) {
    this.start = start;
    this.end = end;
  }
}
class ASTWithSource extends AST {
  ast;
  source;
  location;
  errors;
  constructor(ast, source, location, absoluteOffset, errors) {
    super(new ParseSpan(0, source === null ? 0 : source.length), new AbsoluteSourceSpan(absoluteOffset, source === null ? absoluteOffset : absoluteOffset + source.length));
    this.ast = ast;
    this.source = source;
    this.location = location;
    this.errors = errors;
  }
  visit(visitor, context = null) {
    if (visitor.visitASTWithSource) {
      return visitor.visitASTWithSource(this, context);
    }
    return this.ast.visit(visitor, context);
  }
  toString() {
    return `${this.source} in ${this.location}`;
  }
}
class VariableBinding {
  sourceSpan;
  key;
  value;
  constructor(sourceSpan, key, value) {
    this.sourceSpan = sourceSpan;
    this.key = key;
    this.value = value;
  }
}
class ExpressionBinding {
  sourceSpan;
  key;
  value;
  constructor(sourceSpan, key, value) {
    this.sourceSpan = sourceSpan;
    this.key = key;
    this.value = value;
  }
}
class RecursiveAstVisitor {
  visit(ast, context) {
    ast.visit(this, context);
  }
  visitUnary(ast, context) {
    this.visit(ast.expr, context);
  }
  visitBinary(ast, context) {
    this.visit(ast.left, context);
    this.visit(ast.right, context);
  }
  visitChain(ast, context) {
    this.visitAll(ast.expressions, context);
  }
  visitConditional(ast, context) {
    this.visit(ast.condition, context);
    this.visit(ast.trueExp, context);
    this.visit(ast.falseExp, context);
  }
  visitPipe(ast, context) {
    this.visit(ast.exp, context);
    this.visitAll(ast.args, context);
  }
  visitImplicitReceiver(ast, context) {}
  visitThisReceiver(ast, context) {}
  visitInterpolation(ast, context) {
    this.visitAll(ast.expressions, context);
  }
  visitKeyedRead(ast, context) {
    this.visit(ast.receiver, context);
    this.visit(ast.key, context);
  }
  visitLiteralArray(ast, context) {
    this.visitAll(ast.expressions, context);
  }
  visitLiteralMap(ast, context) {
    this.visitAll(ast.values, context);
  }
  visitLiteralPrimitive(ast, context) {}
  visitPrefixNot(ast, context) {
    this.visit(ast.expression, context);
  }
  visitTypeofExpression(ast, context) {
    this.visit(ast.expression, context);
  }
  visitVoidExpression(ast, context) {
    this.visit(ast.expression, context);
  }
  visitNonNullAssert(ast, context) {
    this.visit(ast.expression, context);
  }
  visitPropertyRead(ast, context) {
    this.visit(ast.receiver, context);
  }
  visitSafePropertyRead(ast, context) {
    this.visit(ast.receiver, context);
  }
  visitSafeKeyedRead(ast, context) {
    this.visit(ast.receiver, context);
    this.visit(ast.key, context);
  }
  visitCall(ast, context) {
    this.visit(ast.receiver, context);
    this.visitAll(ast.args, context);
  }
  visitSafeCall(ast, context) {
    this.visit(ast.receiver, context);
    this.visitAll(ast.args, context);
  }
  visitTemplateLiteral(ast, context) {
    for (let i = 0; i < ast.elements.length; i++) {
      this.visit(ast.elements[i], context);
      const expression = i < ast.expressions.length ? ast.expressions[i] : null;
      if (expression !== null) {
        this.visit(expression, context);
      }
    }
  }
  visitTemplateLiteralElement(ast, context) {}
  visitTaggedTemplateLiteral(ast, context) {
    this.visit(ast.tag, context);
    this.visit(ast.template, context);
  }
  visitParenthesizedExpression(ast, context) {
    this.visit(ast.expression, context);
  }
  visitArrowFunction(ast, context) {
    this.visit(ast.body, context);
  }
  visitRegularExpressionLiteral(ast, context) {}
  visitSpreadElement(ast, context) {
    this.visit(ast.expression, context);
  }
  visitEmptyExpr(ast, context) {}
  visitAll(asts, context) {
    for (const ast of asts) {
      this.visit(ast, context);
    }
  }
}
class ParsedProperty {
  name;
  expression;
  type;
  sourceSpan;
  keySpan;
  valueSpan;
  isLiteral;
  isLegacyAnimation;
  isAnimation;
  constructor(name, expression, type, sourceSpan, keySpan, valueSpan) {
    this.name = name;
    this.expression = expression;
    this.type = type;
    this.sourceSpan = sourceSpan;
    this.keySpan = keySpan;
    this.valueSpan = valueSpan;
    this.isLiteral = this.type === ParsedPropertyType.LITERAL_ATTR;
    this.isLegacyAnimation = this.type === ParsedPropertyType.LEGACY_ANIMATION;
    this.isAnimation = this.type === ParsedPropertyType.ANIMATION;
  }
}
var ParsedPropertyType;
(function (ParsedPropertyType) {
  ParsedPropertyType[ParsedPropertyType["DEFAULT"] = 0] = "DEFAULT";
  ParsedPropertyType[ParsedPropertyType["LITERAL_ATTR"] = 1] = "LITERAL_ATTR";
  ParsedPropertyType[ParsedPropertyType["LEGACY_ANIMATION"] = 2] = "LEGACY_ANIMATION";
  ParsedPropertyType[ParsedPropertyType["TWO_WAY"] = 3] = "TWO_WAY";
  ParsedPropertyType[ParsedPropertyType["ANIMATION"] = 4] = "ANIMATION";
})(ParsedPropertyType || (ParsedPropertyType = {}));
var ParsedEventType;
(function (ParsedEventType) {
  ParsedEventType[ParsedEventType["Regular"] = 0] = "Regular";
  ParsedEventType[ParsedEventType["LegacyAnimation"] = 1] = "LegacyAnimation";
  ParsedEventType[ParsedEventType["TwoWay"] = 2] = "TwoWay";
  ParsedEventType[ParsedEventType["Animation"] = 3] = "Animation";
})(ParsedEventType || (ParsedEventType = {}));
class ParsedEvent {
  name;
  targetOrPhase;
  type;
  handler;
  sourceSpan;
  handlerSpan;
  keySpan;
  constructor(name, targetOrPhase, type, handler, sourceSpan, handlerSpan, keySpan) {
    this.name = name;
    this.targetOrPhase = targetOrPhase;
    this.type = type;
    this.handler = handler;
    this.sourceSpan = sourceSpan;
    this.handlerSpan = handlerSpan;
    this.keySpan = keySpan;
  }
}
class ParsedVariable {
  name;
  value;
  sourceSpan;
  keySpan;
  valueSpan;
  constructor(name, value, sourceSpan, keySpan, valueSpan) {
    this.name = name;
    this.value = value;
    this.sourceSpan = sourceSpan;
    this.keySpan = keySpan;
    this.valueSpan = valueSpan;
  }
}
var BindingType;
(function (BindingType) {
  BindingType[BindingType["Property"] = 0] = "Property";
  BindingType[BindingType["Attribute"] = 1] = "Attribute";
  BindingType[BindingType["Class"] = 2] = "Class";
  BindingType[BindingType["Style"] = 3] = "Style";
  BindingType[BindingType["LegacyAnimation"] = 4] = "LegacyAnimation";
  BindingType[BindingType["TwoWay"] = 5] = "TwoWay";
  BindingType[BindingType["Animation"] = 6] = "Animation";
})(BindingType || (BindingType = {}));
class BoundElementProperty {
  name;
  type;
  securityContext;
  value;
  unit;
  sourceSpan;
  keySpan;
  valueSpan;
  constructor(name, type, securityContext, value, unit, sourceSpan, keySpan, valueSpan) {
    this.name = name;
    this.type = type;
    this.securityContext = securityContext;
    this.value = value;
    this.unit = unit;
    this.sourceSpan = sourceSpan;
    this.keySpan = keySpan;
    this.valueSpan = valueSpan;
  }
}

var TagContentType;
(function (TagContentType) {
  TagContentType[TagContentType["RAW_TEXT"] = 0] = "RAW_TEXT";
  TagContentType[TagContentType["ESCAPABLE_RAW_TEXT"] = 1] = "ESCAPABLE_RAW_TEXT";
  TagContentType[TagContentType["PARSABLE_DATA"] = 2] = "PARSABLE_DATA";
})(TagContentType || (TagContentType = {}));
function splitNsName(elementName, fatal = true) {
  if (elementName[0] != ':') {
    return [null, elementName];
  }
  const colonIndex = elementName.indexOf(':', 1);
  if (colonIndex === -1) {
    if (fatal) {
      throw new Error(`Unsupported format "${elementName}" expecting ":namespace:name"`);
    } else {
      return [null, elementName];
    }
  }
  return [elementName.slice(1, colonIndex), elementName.slice(colonIndex + 1)];
}
function isNgContainer(tagName) {
  return splitNsName(tagName)[1] === 'ng-container';
}
function isNgContent(tagName) {
  return splitNsName(tagName)[1] === 'ng-content';
}
function isNgTemplate(tagName) {
  return splitNsName(tagName)[1] === 'ng-template';
}
function getNsPrefix(fullName) {
  return fullName === null ? null : splitNsName(fullName)[0];
}
function mergeNsAndName(prefix, localName) {
  return prefix ? `:${prefix}:${localName}` : localName;
}

let Comment$1 = class Comment {
  value;
  sourceSpan;
  constructor(value, sourceSpan) {
    this.value = value;
    this.sourceSpan = sourceSpan;
  }
  visit(_visitor) {
    throw new Error('visit() not implemented for Comment');
  }
};
let Text$3 = class Text {
  value;
  sourceSpan;
  constructor(value, sourceSpan) {
    this.value = value;
    this.sourceSpan = sourceSpan;
  }
  visit(visitor) {
    return visitor.visitText(this);
  }
};
class BoundText {
  value;
  sourceSpan;
  i18n;
  constructor(value, sourceSpan, i18n) {
    this.value = value;
    this.sourceSpan = sourceSpan;
    this.i18n = i18n;
  }
  visit(visitor) {
    return visitor.visitBoundText(this);
  }
}
class TextAttribute {
  name;
  value;
  sourceSpan;
  keySpan;
  valueSpan;
  i18n;
  constructor(name, value, sourceSpan, keySpan, valueSpan, i18n) {
    this.name = name;
    this.value = value;
    this.sourceSpan = sourceSpan;
    this.keySpan = keySpan;
    this.valueSpan = valueSpan;
    this.i18n = i18n;
  }
  visit(visitor) {
    return visitor.visitTextAttribute(this);
  }
}
class BoundAttribute {
  name;
  type;
  securityContext;
  value;
  unit;
  sourceSpan;
  keySpan;
  valueSpan;
  i18n;
  constructor(name, type, securityContext, value, unit, sourceSpan, keySpan, valueSpan, i18n) {
    this.name = name;
    this.type = type;
    this.securityContext = securityContext;
    this.value = value;
    this.unit = unit;
    this.sourceSpan = sourceSpan;
    this.keySpan = keySpan;
    this.valueSpan = valueSpan;
    this.i18n = i18n;
  }
  static fromBoundElementProperty(prop, i18n) {
    if (prop.keySpan === undefined) {
      throw new Error(`Unexpected state: keySpan must be defined for bound attributes but was not for ${prop.name}: ${prop.sourceSpan}`);
    }
    return new BoundAttribute(prop.name, prop.type, prop.securityContext, prop.value, prop.unit, prop.sourceSpan, prop.keySpan, prop.valueSpan, i18n);
  }
  visit(visitor) {
    return visitor.visitBoundAttribute(this);
  }
}
class BoundEvent {
  name;
  type;
  handler;
  target;
  phase;
  sourceSpan;
  handlerSpan;
  keySpan;
  constructor(name, type, handler, target, phase, sourceSpan, handlerSpan, keySpan) {
    this.name = name;
    this.type = type;
    this.handler = handler;
    this.target = target;
    this.phase = phase;
    this.sourceSpan = sourceSpan;
    this.handlerSpan = handlerSpan;
    this.keySpan = keySpan;
  }
  static fromParsedEvent(event) {
    const target = event.type === ParsedEventType.Regular ? event.targetOrPhase : null;
    const phase = event.type === ParsedEventType.LegacyAnimation ? event.targetOrPhase : null;
    if (event.keySpan === undefined) {
      throw new Error(`Unexpected state: keySpan must be defined for bound event but was not for ${event.name}: ${event.sourceSpan}`);
    }
    return new BoundEvent(event.name, event.type, event.handler, target, phase, event.sourceSpan, event.handlerSpan, event.keySpan);
  }
  visit(visitor) {
    return visitor.visitBoundEvent(this);
  }
}
let Element$1 = class Element {
  name;
  attributes;
  inputs;
  outputs;
  directives;
  children;
  references;
  isSelfClosing;
  sourceSpan;
  startSourceSpan;
  endSourceSpan;
  isVoid;
  i18n;
  constructor(name, attributes, inputs, outputs, directives, children, references, isSelfClosing, sourceSpan, startSourceSpan, endSourceSpan, isVoid, i18n) {
    this.name = name;
    this.attributes = attributes;
    this.inputs = inputs;
    this.outputs = outputs;
    this.directives = directives;
    this.children = children;
    this.references = references;
    this.isSelfClosing = isSelfClosing;
    this.sourceSpan = sourceSpan;
    this.startSourceSpan = startSourceSpan;
    this.endSourceSpan = endSourceSpan;
    this.isVoid = isVoid;
    this.i18n = i18n;
  }
  visit(visitor) {
    return visitor.visitElement(this);
  }
};
class DeferredTrigger {
  nameSpan;
  sourceSpan;
  prefetchSpan;
  whenOrOnSourceSpan;
  hydrateSpan;
  constructor(nameSpan, sourceSpan, prefetchSpan, whenOrOnSourceSpan, hydrateSpan) {
    this.nameSpan = nameSpan;
    this.sourceSpan = sourceSpan;
    this.prefetchSpan = prefetchSpan;
    this.whenOrOnSourceSpan = whenOrOnSourceSpan;
    this.hydrateSpan = hydrateSpan;
  }
  visit(visitor) {
    return visitor.visitDeferredTrigger(this);
  }
}
class BoundDeferredTrigger extends DeferredTrigger {
  value;
  constructor(value, sourceSpan, prefetchSpan, whenSourceSpan, hydrateSpan) {
    super(null, sourceSpan, prefetchSpan, whenSourceSpan, hydrateSpan);
    this.value = value;
  }
}
class NeverDeferredTrigger extends DeferredTrigger {}
class IdleDeferredTrigger extends DeferredTrigger {
  timeout;
  constructor(nameSpan, sourceSpan, prefetchSpan, onSourceSpan, hydrateSpan, timeout) {
    super(nameSpan, sourceSpan, prefetchSpan, onSourceSpan, hydrateSpan);
    this.timeout = timeout;
  }
}
class ImmediateDeferredTrigger extends DeferredTrigger {}
class HoverDeferredTrigger extends DeferredTrigger {
  reference;
  constructor(reference, nameSpan, sourceSpan, prefetchSpan, onSourceSpan, hydrateSpan) {
    super(nameSpan, sourceSpan, prefetchSpan, onSourceSpan, hydrateSpan);
    this.reference = reference;
  }
}
class TimerDeferredTrigger extends DeferredTrigger {
  delay;
  constructor(delay, nameSpan, sourceSpan, prefetchSpan, onSourceSpan, hydrateSpan) {
    super(nameSpan, sourceSpan, prefetchSpan, onSourceSpan, hydrateSpan);
    this.delay = delay;
  }
}
class InteractionDeferredTrigger extends DeferredTrigger {
  reference;
  constructor(reference, nameSpan, sourceSpan, prefetchSpan, onSourceSpan, hydrateSpan) {
    super(nameSpan, sourceSpan, prefetchSpan, onSourceSpan, hydrateSpan);
    this.reference = reference;
  }
}
class ViewportDeferredTrigger extends DeferredTrigger {
  reference;
  options;
  constructor(reference, options, nameSpan, sourceSpan, prefetchSpan, onSourceSpan, hydrateSpan) {
    super(nameSpan, sourceSpan, prefetchSpan, onSourceSpan, hydrateSpan);
    this.reference = reference;
    this.options = options;
  }
}
class BlockNode {
  nameSpan;
  sourceSpan;
  startSourceSpan;
  endSourceSpan;
  constructor(nameSpan, sourceSpan, startSourceSpan, endSourceSpan) {
    this.nameSpan = nameSpan;
    this.sourceSpan = sourceSpan;
    this.startSourceSpan = startSourceSpan;
    this.endSourceSpan = endSourceSpan;
  }
}
class DeferredBlockPlaceholder extends BlockNode {
  children;
  minimumTime;
  i18n;
  constructor(children, minimumTime, nameSpan, sourceSpan, startSourceSpan, endSourceSpan, i18n) {
    super(nameSpan, sourceSpan, startSourceSpan, endSourceSpan);
    this.children = children;
    this.minimumTime = minimumTime;
    this.i18n = i18n;
  }
  visit(visitor) {
    return visitor.visitDeferredBlockPlaceholder(this);
  }
}
class DeferredBlockLoading extends BlockNode {
  children;
  afterTime;
  minimumTime;
  i18n;
  constructor(children, afterTime, minimumTime, nameSpan, sourceSpan, startSourceSpan, endSourceSpan, i18n) {
    super(nameSpan, sourceSpan, startSourceSpan, endSourceSpan);
    this.children = children;
    this.afterTime = afterTime;
    this.minimumTime = minimumTime;
    this.i18n = i18n;
  }
  visit(visitor) {
    return visitor.visitDeferredBlockLoading(this);
  }
}
class DeferredBlockError extends BlockNode {
  children;
  i18n;
  constructor(children, nameSpan, sourceSpan, startSourceSpan, endSourceSpan, i18n) {
    super(nameSpan, sourceSpan, startSourceSpan, endSourceSpan);
    this.children = children;
    this.i18n = i18n;
  }
  visit(visitor) {
    return visitor.visitDeferredBlockError(this);
  }
}
class ContentBlock extends BlockNode {
  name;
  variables;
  children;
  i18n;
  constructor(name, variables, children, nameSpan, sourceSpan, startSourceSpan, endSourceSpan, i18n) {
    super(nameSpan, sourceSpan, startSourceSpan, endSourceSpan);
    this.name = name;
    this.variables = variables;
    this.children = children;
    this.i18n = i18n;
  }
  visit(visitor) {
    return visitor.visitContentBlock(this);
  }
}
class DeferredBlock extends BlockNode {
  children;
  placeholder;
  loading;
  error;
  mainBlockSpan;
  i18n;
  triggers;
  prefetchTriggers;
  hydrateTriggers;
  definedTriggers;
  definedPrefetchTriggers;
  definedHydrateTriggers;
  constructor(children, triggers, prefetchTriggers, hydrateTriggers, placeholder, loading, error, nameSpan, sourceSpan, mainBlockSpan, startSourceSpan, endSourceSpan, i18n) {
    super(nameSpan, sourceSpan, startSourceSpan, endSourceSpan);
    this.children = children;
    this.placeholder = placeholder;
    this.loading = loading;
    this.error = error;
    this.mainBlockSpan = mainBlockSpan;
    this.i18n = i18n;
    this.triggers = triggers;
    this.prefetchTriggers = prefetchTriggers;
    this.hydrateTriggers = hydrateTriggers;
    this.definedTriggers = Object.keys(triggers);
    this.definedPrefetchTriggers = Object.keys(prefetchTriggers);
    this.definedHydrateTriggers = Object.keys(hydrateTriggers);
  }
  visit(visitor) {
    return visitor.visitDeferredBlock(this);
  }
  visitAll(visitor) {
    this.visitTriggers(this.definedHydrateTriggers, this.hydrateTriggers, visitor);
    this.visitTriggers(this.definedTriggers, this.triggers, visitor);
    this.visitTriggers(this.definedPrefetchTriggers, this.prefetchTriggers, visitor);
    visitAll$1(visitor, this.children);
    const remainingBlocks = [this.placeholder, this.loading, this.error].filter(x => x !== null);
    visitAll$1(visitor, remainingBlocks);
  }
  visitTriggers(keys, triggers, visitor) {
    visitAll$1(visitor, keys.map(k => triggers[k]));
  }
}
class SwitchBlock extends BlockNode {
  expression;
  groups;
  unknownBlocks;
  exhaustiveCheck;
  constructor(expression, groups, unknownBlocks, exhaustiveCheck, sourceSpan, startSourceSpan, endSourceSpan, nameSpan) {
    super(nameSpan, sourceSpan, startSourceSpan, endSourceSpan);
    this.expression = expression;
    this.groups = groups;
    this.unknownBlocks = unknownBlocks;
    this.exhaustiveCheck = exhaustiveCheck;
  }
  visit(visitor) {
    return visitor.visitSwitchBlock(this);
  }
}
class SwitchBlockCase extends BlockNode {
  expression;
  constructor(expression, sourceSpan, startSourceSpan, endSourceSpan, nameSpan) {
    super(nameSpan, sourceSpan, startSourceSpan, endSourceSpan);
    this.expression = expression;
  }
  visit(visitor) {
    return visitor.visitSwitchBlockCase(this);
  }
}
class SwitchBlockCaseGroup extends BlockNode {
  cases;
  children;
  i18n;
  constructor(cases, children, sourceSpan, startSourceSpan, endSourceSpan, nameSpan, i18n) {
    super(nameSpan, sourceSpan, startSourceSpan, endSourceSpan);
    this.cases = cases;
    this.children = children;
    this.i18n = i18n;
  }
  visit(visitor) {
    return visitor.visitSwitchBlockCaseGroup(this);
  }
}
class SwitchExhaustiveCheck extends BlockNode {
  expression;
  constructor(expression, sourceSpan, startSourceSpan, endSourceSpan, nameSpan) {
    super(nameSpan, sourceSpan, startSourceSpan, endSourceSpan);
    this.expression = expression;
  }
  visit(visitor) {
    return visitor.visitSwitchExhaustiveCheck(this);
  }
}
class ForLoopBlock extends BlockNode {
  item;
  expression;
  trackBy;
  trackKeywordSpan;
  contextVariables;
  children;
  empty;
  mainBlockSpan;
  i18n;
  constructor(item, expression, trackBy, trackKeywordSpan, contextVariables, children, empty, sourceSpan, mainBlockSpan, startSourceSpan, endSourceSpan, nameSpan, i18n) {
    super(nameSpan, sourceSpan, startSourceSpan, endSourceSpan);
    this.item = item;
    this.expression = expression;
    this.trackBy = trackBy;
    this.trackKeywordSpan = trackKeywordSpan;
    this.contextVariables = contextVariables;
    this.children = children;
    this.empty = empty;
    this.mainBlockSpan = mainBlockSpan;
    this.i18n = i18n;
  }
  visit(visitor) {
    return visitor.visitForLoopBlock(this);
  }
}
class ForLoopBlockEmpty extends BlockNode {
  children;
  i18n;
  constructor(children, sourceSpan, startSourceSpan, endSourceSpan, nameSpan, i18n) {
    super(nameSpan, sourceSpan, startSourceSpan, endSourceSpan);
    this.children = children;
    this.i18n = i18n;
  }
  visit(visitor) {
    return visitor.visitForLoopBlockEmpty(this);
  }
}
class IfBlock extends BlockNode {
  branches;
  constructor(branches, sourceSpan, startSourceSpan, endSourceSpan, nameSpan) {
    super(nameSpan, sourceSpan, startSourceSpan, endSourceSpan);
    this.branches = branches;
  }
  visit(visitor) {
    return visitor.visitIfBlock(this);
  }
}
class IfBlockBranch extends BlockNode {
  expression;
  children;
  expressionAlias;
  i18n;
  constructor(expression, children, expressionAlias, sourceSpan, startSourceSpan, endSourceSpan, nameSpan, i18n) {
    super(nameSpan, sourceSpan, startSourceSpan, endSourceSpan);
    this.expression = expression;
    this.children = children;
    this.expressionAlias = expressionAlias;
    this.i18n = i18n;
  }
  visit(visitor) {
    return visitor.visitIfBlockBranch(this);
  }
}
class UnknownBlock {
  name;
  sourceSpan;
  nameSpan;
  constructor(name, sourceSpan, nameSpan) {
    this.name = name;
    this.sourceSpan = sourceSpan;
    this.nameSpan = nameSpan;
  }
  visit(visitor) {
    return visitor.visitUnknownBlock(this);
  }
}
let LetDeclaration$1 = class LetDeclaration {
  name;
  value;
  sourceSpan;
  nameSpan;
  valueSpan;
  constructor(name, value, sourceSpan, nameSpan, valueSpan) {
    this.name = name;
    this.value = value;
    this.sourceSpan = sourceSpan;
    this.nameSpan = nameSpan;
    this.valueSpan = valueSpan;
  }
  visit(visitor) {
    return visitor.visitLetDeclaration(this);
  }
};
let Component$1 = class Component {
  componentName;
  tagName;
  fullName;
  attributes;
  inputs;
  outputs;
  directives;
  children;
  references;
  isSelfClosing;
  sourceSpan;
  startSourceSpan;
  endSourceSpan;
  i18n;
  constructor(componentName, tagName, fullName, attributes, inputs, outputs, directives, children, references, isSelfClosing, sourceSpan, startSourceSpan, endSourceSpan, i18n) {
    this.componentName = componentName;
    this.tagName = tagName;
    this.fullName = fullName;
    this.attributes = attributes;
    this.inputs = inputs;
    this.outputs = outputs;
    this.directives = directives;
    this.children = children;
    this.references = references;
    this.isSelfClosing = isSelfClosing;
    this.sourceSpan = sourceSpan;
    this.startSourceSpan = startSourceSpan;
    this.endSourceSpan = endSourceSpan;
    this.i18n = i18n;
  }
  visit(visitor) {
    return visitor.visitComponent(this);
  }
};
let Directive$1 = class Directive {
  name;
  attributes;
  inputs;
  outputs;
  references;
  sourceSpan;
  startSourceSpan;
  endSourceSpan;
  i18n;
  constructor(name, attributes, inputs, outputs, references, sourceSpan, startSourceSpan, endSourceSpan, i18n) {
    this.name = name;
    this.attributes = attributes;
    this.inputs = inputs;
    this.outputs = outputs;
    this.references = references;
    this.sourceSpan = sourceSpan;
    this.startSourceSpan = startSourceSpan;
    this.endSourceSpan = endSourceSpan;
    this.i18n = i18n;
  }
  visit(visitor) {
    return visitor.visitDirective(this);
  }
};
class Template {
  tagName;
  attributes;
  inputs;
  outputs;
  directives;
  templateAttrs;
  children;
  references;
  variables;
  isSelfClosing;
  sourceSpan;
  startSourceSpan;
  endSourceSpan;
  i18n;
  constructor(tagName, attributes, inputs, outputs, directives, templateAttrs, children, references, variables, isSelfClosing, sourceSpan, startSourceSpan, endSourceSpan, i18n) {
    this.tagName = tagName;
    this.attributes = attributes;
    this.inputs = inputs;
    this.outputs = outputs;
    this.directives = directives;
    this.templateAttrs = templateAttrs;
    this.children = children;
    this.references = references;
    this.variables = variables;
    this.isSelfClosing = isSelfClosing;
    this.sourceSpan = sourceSpan;
    this.startSourceSpan = startSourceSpan;
    this.endSourceSpan = endSourceSpan;
    this.i18n = i18n;
  }
  visit(visitor) {
    return visitor.visitTemplate(this);
  }
}
class Content {
  selector;
  attributes;
  children;
  isSelfClosing;
  sourceSpan;
  startSourceSpan;
  endSourceSpan;
  i18n;
  name = 'ng-content';
  constructor(selector, attributes, children, isSelfClosing, sourceSpan, startSourceSpan, endSourceSpan, i18n) {
    this.selector = selector;
    this.attributes = attributes;
    this.children = children;
    this.isSelfClosing = isSelfClosing;
    this.sourceSpan = sourceSpan;
    this.startSourceSpan = startSourceSpan;
    this.endSourceSpan = endSourceSpan;
    this.i18n = i18n;
  }
  visit(visitor) {
    return visitor.visitContent(this);
  }
}
class Variable {
  name;
  value;
  sourceSpan;
  keySpan;
  valueSpan;
  constructor(name, value, sourceSpan, keySpan, valueSpan) {
    this.name = name;
    this.value = value;
    this.sourceSpan = sourceSpan;
    this.keySpan = keySpan;
    this.valueSpan = valueSpan;
  }
  visit(visitor) {
    return visitor.visitVariable(this);
  }
}
class Reference {
  name;
  value;
  sourceSpan;
  keySpan;
  valueSpan;
  constructor(name, value, sourceSpan, keySpan, valueSpan) {
    this.name = name;
    this.value = value;
    this.sourceSpan = sourceSpan;
    this.keySpan = keySpan;
    this.valueSpan = valueSpan;
  }
  visit(visitor) {
    return visitor.visitReference(this);
  }
}
let Icu$1 = class Icu {
  vars;
  placeholders;
  sourceSpan;
  i18n;
  constructor(vars, placeholders, sourceSpan, i18n) {
    this.vars = vars;
    this.placeholders = placeholders;
    this.sourceSpan = sourceSpan;
    this.i18n = i18n;
  }
  visit(visitor) {
    return visitor.visitIcu(this);
  }
};
class HostElement {
  tagNames;
  bindings;
  listeners;
  sourceSpan;
  constructor(tagNames, bindings, listeners, sourceSpan) {
    this.tagNames = tagNames;
    this.bindings = bindings;
    this.listeners = listeners;
    this.sourceSpan = sourceSpan;
    if (tagNames.length === 0) {
      throw new Error('HostElement must have at least one tag name.');
    }
  }
  visit() {
    throw new Error(`HostElement cannot be visited`);
  }
}
let RecursiveVisitor$1 = class RecursiveVisitor {
  visitElement(element) {
    visitAll$1(this, element.attributes);
    visitAll$1(this, element.inputs);
    visitAll$1(this, element.outputs);
    visitAll$1(this, element.directives);
    visitAll$1(this, element.children);
    visitAll$1(this, element.references);
  }
  visitTemplate(template) {
    visitAll$1(this, template.attributes);
    visitAll$1(this, template.inputs);
    visitAll$1(this, template.outputs);
    visitAll$1(this, template.directives);
    visitAll$1(this, template.children);
    visitAll$1(this, template.references);
    visitAll$1(this, template.variables);
  }
  visitDeferredBlock(deferred) {
    deferred.visitAll(this);
  }
  visitDeferredBlockPlaceholder(block) {
    visitAll$1(this, block.children);
  }
  visitDeferredBlockError(block) {
    visitAll$1(this, block.children);
  }
  visitDeferredBlockLoading(block) {
    visitAll$1(this, block.children);
  }
  visitSwitchBlock(block) {
    visitAll$1(this, block.groups);
  }
  visitSwitchBlockCase(block) {}
  visitSwitchBlockCaseGroup(block) {
    visitAll$1(this, block.cases);
    visitAll$1(this, block.children);
  }
  visitSwitchExhaustiveCheck(block) {}
  visitForLoopBlock(block) {
    const blockItems = [block.item, ...block.contextVariables, ...block.children];
    block.empty && blockItems.push(block.empty);
    visitAll$1(this, blockItems);
  }
  visitForLoopBlockEmpty(block) {
    visitAll$1(this, block.children);
  }
  visitIfBlock(block) {
    visitAll$1(this, block.branches);
  }
  visitIfBlockBranch(block) {
    visitAll$1(this, block.children);
    block.expressionAlias?.visit(this);
  }
  visitContent(content) {
    visitAll$1(this, content.children);
  }
  visitComponent(component) {
    visitAll$1(this, component.attributes);
    visitAll$1(this, component.inputs);
    visitAll$1(this, component.outputs);
    visitAll$1(this, component.directives);
    visitAll$1(this, component.children);
    visitAll$1(this, component.references);
  }
  visitDirective(directive) {
    visitAll$1(this, directive.attributes);
    visitAll$1(this, directive.inputs);
    visitAll$1(this, directive.outputs);
    visitAll$1(this, directive.references);
  }
  visitVariable(variable) {}
  visitReference(reference) {}
  visitTextAttribute(attribute) {}
  visitBoundAttribute(attribute) {}
  visitBoundEvent(attribute) {}
  visitText(text) {}
  visitBoundText(text) {}
  visitIcu(icu) {}
  visitDeferredTrigger(trigger) {}
  visitUnknownBlock(block) {}
  visitLetDeclaration(decl) {}
  visitContentBlock(block) {
    visitAll$1(this, block.children);
  }
};
function visitAll$1(visitor, nodes) {
  const result = [];
  if (visitor.visit) {
    for (const node of nodes) {
      visitor.visit(node);
    }
  } else {
    for (const node of nodes) {
      const newNode = node.visit(visitor);
      if (newNode) {
        result.push(newNode);
      }
    }
  }
  return result;
}

class Message {
  nodes;
  placeholders;
  placeholderToMessage;
  meaning;
  description;
  customId;
  sources;
  id;
  legacyIds = [];
  messageString;
  constructor(nodes, placeholders, placeholderToMessage, meaning, description, customId) {
    this.nodes = nodes;
    this.placeholders = placeholders;
    this.placeholderToMessage = placeholderToMessage;
    this.meaning = meaning;
    this.description = description;
    this.customId = customId;
    this.id = this.customId;
    this.messageString = serializeMessage(this.nodes);
    if (nodes.length) {
      this.sources = [{
        filePath: nodes[0].sourceSpan.start.file.url,
        startLine: nodes[0].sourceSpan.start.line + 1,
        startCol: nodes[0].sourceSpan.start.col + 1,
        endLine: nodes[nodes.length - 1].sourceSpan.end.line + 1,
        endCol: nodes[0].sourceSpan.start.col + 1
      }];
    } else {
      this.sources = [];
    }
  }
}
let Text$2 = class Text {
  value;
  sourceSpan;
  constructor(value, sourceSpan) {
    this.value = value;
    this.sourceSpan = sourceSpan;
  }
  visit(visitor, context) {
    return visitor.visitText(this, context);
  }
};
class Container {
  children;
  sourceSpan;
  constructor(children, sourceSpan) {
    this.children = children;
    this.sourceSpan = sourceSpan;
  }
  visit(visitor, context) {
    return visitor.visitContainer(this, context);
  }
}
class Icu {
  expression;
  type;
  cases;
  sourceSpan;
  expressionPlaceholder;
  constructor(expression, type, cases, sourceSpan, expressionPlaceholder) {
    this.expression = expression;
    this.type = type;
    this.cases = cases;
    this.sourceSpan = sourceSpan;
    this.expressionPlaceholder = expressionPlaceholder;
  }
  visit(visitor, context) {
    return visitor.visitIcu(this, context);
  }
}
class TagPlaceholder {
  tag;
  attrs;
  startName;
  closeName;
  children;
  isVoid;
  sourceSpan;
  startSourceSpan;
  endSourceSpan;
  constructor(tag, attrs, startName, closeName, children, isVoid, sourceSpan, startSourceSpan, endSourceSpan) {
    this.tag = tag;
    this.attrs = attrs;
    this.startName = startName;
    this.closeName = closeName;
    this.children = children;
    this.isVoid = isVoid;
    this.sourceSpan = sourceSpan;
    this.startSourceSpan = startSourceSpan;
    this.endSourceSpan = endSourceSpan;
  }
  visit(visitor, context) {
    return visitor.visitTagPlaceholder(this, context);
  }
}
class Placeholder {
  value;
  name;
  sourceSpan;
  constructor(value, name, sourceSpan) {
    this.value = value;
    this.name = name;
    this.sourceSpan = sourceSpan;
  }
  visit(visitor, context) {
    return visitor.visitPlaceholder(this, context);
  }
}
class IcuPlaceholder {
  value;
  name;
  sourceSpan;
  previousMessage;
  constructor(value, name, sourceSpan) {
    this.value = value;
    this.name = name;
    this.sourceSpan = sourceSpan;
  }
  visit(visitor, context) {
    return visitor.visitIcuPlaceholder(this, context);
  }
}
class BlockPlaceholder {
  name;
  parameters;
  startName;
  closeName;
  children;
  sourceSpan;
  startSourceSpan;
  endSourceSpan;
  constructor(name, parameters, startName, closeName, children, sourceSpan, startSourceSpan, endSourceSpan) {
    this.name = name;
    this.parameters = parameters;
    this.startName = startName;
    this.closeName = closeName;
    this.children = children;
    this.sourceSpan = sourceSpan;
    this.startSourceSpan = startSourceSpan;
    this.endSourceSpan = endSourceSpan;
  }
  visit(visitor, context) {
    return visitor.visitBlockPlaceholder(this, context);
  }
}
class CloneVisitor {
  visitText(text, context) {
    return new Text$2(text.value, text.sourceSpan);
  }
  visitContainer(container, context) {
    const children = container.children.map(n => n.visit(this, context));
    return new Container(children, container.sourceSpan);
  }
  visitIcu(icu, context) {
    const cases = {};
    Object.keys(icu.cases).forEach(key => cases[key] = icu.cases[key].visit(this, context));
    const msg = new Icu(icu.expression, icu.type, cases, icu.sourceSpan, icu.expressionPlaceholder);
    return msg;
  }
  visitTagPlaceholder(ph, context) {
    const children = ph.children.map(n => n.visit(this, context));
    return new TagPlaceholder(ph.tag, ph.attrs, ph.startName, ph.closeName, children, ph.isVoid, ph.sourceSpan, ph.startSourceSpan, ph.endSourceSpan);
  }
  visitPlaceholder(ph, context) {
    return new Placeholder(ph.value, ph.name, ph.sourceSpan);
  }
  visitIcuPlaceholder(ph, context) {
    return new IcuPlaceholder(ph.value, ph.name, ph.sourceSpan);
  }
  visitBlockPlaceholder(ph, context) {
    const children = ph.children.map(n => n.visit(this, context));
    return new BlockPlaceholder(ph.name, ph.parameters, ph.startName, ph.closeName, children, ph.sourceSpan, ph.startSourceSpan, ph.endSourceSpan);
  }
}
class RecurseVisitor {
  visitText(text, context) {}
  visitContainer(container, context) {
    container.children.forEach(child => child.visit(this));
  }
  visitIcu(icu, context) {
    Object.keys(icu.cases).forEach(k => {
      icu.cases[k].visit(this);
    });
  }
  visitTagPlaceholder(ph, context) {
    ph.children.forEach(child => child.visit(this));
  }
  visitPlaceholder(ph, context) {}
  visitIcuPlaceholder(ph, context) {}
  visitBlockPlaceholder(ph, context) {
    ph.children.forEach(child => child.visit(this));
  }
}
function serializeMessage(messageNodes) {
  const visitor = new LocalizeMessageStringVisitor();
  const str = messageNodes.map(n => n.visit(visitor)).join('');
  return str;
}
class LocalizeMessageStringVisitor {
  visitText(text) {
    return text.value;
  }
  visitContainer(container) {
    return container.children.map(child => child.visit(this)).join('');
  }
  visitIcu(icu) {
    const strCases = Object.keys(icu.cases).map(k => `${k} {${icu.cases[k].visit(this)}}`);
    return `{${icu.expressionPlaceholder}, ${icu.type}, ${strCases.join(' ')}}`;
  }
  visitTagPlaceholder(ph) {
    const children = ph.children.map(child => child.visit(this)).join('');
    return `{$${ph.startName}}${children}{$${ph.closeName}}`;
  }
  visitPlaceholder(ph) {
    return `{$${ph.name}}`;
  }
  visitIcuPlaceholder(ph) {
    return `{$${ph.name}}`;
  }
  visitBlockPlaceholder(ph) {
    const children = ph.children.map(child => child.visit(this)).join('');
    return `{$${ph.startName}}${children}{$${ph.closeName}}`;
  }
}

class Serializer {
  createNameMapper(message) {
    return null;
  }
}
class SimplePlaceholderMapper extends RecurseVisitor {
  mapName;
  internalToPublic = {};
  publicToNextId = {};
  publicToInternal = {};
  constructor(message, mapName) {
    super();
    this.mapName = mapName;
    message.nodes.forEach(node => node.visit(this));
  }
  toPublicName(internalName) {
    return Object.hasOwn(this.internalToPublic, internalName) ? this.internalToPublic[internalName] : null;
  }
  toInternalName(publicName) {
    return Object.hasOwn(this.publicToInternal, publicName) ? this.publicToInternal[publicName] : null;
  }
  visitText(text, context) {
    return null;
  }
  visitTagPlaceholder(ph, context) {
    this.visitPlaceholderName(ph.startName);
    super.visitTagPlaceholder(ph, context);
    this.visitPlaceholderName(ph.closeName);
  }
  visitPlaceholder(ph, context) {
    this.visitPlaceholderName(ph.name);
  }
  visitBlockPlaceholder(ph, context) {
    this.visitPlaceholderName(ph.startName);
    super.visitBlockPlaceholder(ph, context);
    this.visitPlaceholderName(ph.closeName);
  }
  visitIcuPlaceholder(ph, context) {
    this.visitPlaceholderName(ph.name);
  }
  visitPlaceholderName(internalName) {
    if (!internalName || Object.hasOwn(this.internalToPublic, internalName)) {
      return;
    }
    let publicName = this.mapName(internalName);
    if (Object.hasOwn(this.publicToInternal, publicName)) {
      const nextId = this.publicToNextId[publicName];
      this.publicToNextId[publicName] = nextId + 1;
      publicName = `${publicName}_${nextId}`;
    } else {
      this.publicToNextId[publicName] = 1;
    }
    this.internalToPublic[internalName] = publicName;
    this.publicToInternal[publicName] = internalName;
  }
}

let _Visitor$2 = class _Visitor {
  visitTag(tag) {
    const strAttrs = this._serializeAttributes(tag.attrs);
    if (tag.children.length == 0) {
      return `<${tag.name}${strAttrs}/>`;
    }
    const strChildren = tag.children.map(node => node.visit(this));
    return `<${tag.name}${strAttrs}>${strChildren.join('')}</${tag.name}>`;
  }
  visitText(text) {
    return text.value;
  }
  visitDeclaration(decl) {
    return `<?xml${this._serializeAttributes(decl.attrs)} ?>`;
  }
  _serializeAttributes(attrs) {
    const strAttrs = Object.keys(attrs).map(name => `${name}="${attrs[name]}"`).join(' ');
    return strAttrs.length > 0 ? ' ' + strAttrs : '';
  }
  visitDoctype(doctype) {
    return `<!DOCTYPE ${doctype.rootTag} [\n${doctype.dtd}\n]>`;
  }
};
const _visitor = new _Visitor$2();
function serialize$1(nodes) {
  return nodes.map(node => node.visit(_visitor)).join('');
}
class Declaration {
  attrs = {};
  constructor(unescapedAttrs) {
    Object.keys(unescapedAttrs).forEach(k => {
      this.attrs[k] = escapeXml(unescapedAttrs[k]);
    });
  }
  visit(visitor) {
    return visitor.visitDeclaration(this);
  }
}
class Doctype {
  rootTag;
  dtd;
  constructor(rootTag, dtd) {
    this.rootTag = rootTag;
    this.dtd = dtd;
  }
  visit(visitor) {
    return visitor.visitDoctype(this);
  }
}
class Tag {
  name;
  children;
  attrs = {};
  constructor(name, unescapedAttrs = {}, children = []) {
    this.name = name;
    this.children = children;
    Object.keys(unescapedAttrs).forEach(k => {
      this.attrs[k] = escapeXml(unescapedAttrs[k]);
    });
  }
  visit(visitor) {
    return visitor.visitTag(this);
  }
}
let Text$1 = class Text {
  value;
  constructor(unescapedValue) {
    this.value = escapeXml(unescapedValue);
  }
  visit(visitor) {
    return visitor.visitText(this);
  }
};
class CR extends Text$1 {
  constructor(ws = 0) {
    super(`\n${new Array(ws + 1).join(' ')}`);
  }
}
const _ESCAPED_CHARS = [[/&/g, '&amp;'], [/"/g, '&quot;'], [/'/g, '&apos;'], [/</g, '&lt;'], [/>/g, '&gt;']];
function escapeXml(text) {
  return _ESCAPED_CHARS.reduce((text, entry) => text.replace(entry[0], entry[1]), text);
}

const _XMB_HANDLER = 'angular';
const _MESSAGES_TAG = 'messagebundle';
const _MESSAGE_TAG = 'msg';
const _PLACEHOLDER_TAG$3 = 'ph';
const _EXAMPLE_TAG = 'ex';
const _SOURCE_TAG$2 = 'source';
const _DOCTYPE = `<!ELEMENT messagebundle (msg)*>
<!ATTLIST messagebundle class CDATA #IMPLIED>

<!ELEMENT msg (#PCDATA|ph|source)*>
<!ATTLIST msg id CDATA #IMPLIED>
<!ATTLIST msg seq CDATA #IMPLIED>
<!ATTLIST msg name CDATA #IMPLIED>
<!ATTLIST msg desc CDATA #IMPLIED>
<!ATTLIST msg meaning CDATA #IMPLIED>
<!ATTLIST msg obsolete (obsolete) #IMPLIED>
<!ATTLIST msg xml:space (default|preserve) "default">
<!ATTLIST msg is_hidden CDATA #IMPLIED>

<!ELEMENT source (#PCDATA)>

<!ELEMENT ph (#PCDATA|ex)*>
<!ATTLIST ph name CDATA #REQUIRED>

<!ELEMENT ex (#PCDATA)>`;
class Xmb extends Serializer {
  write(messages, locale) {
    const exampleVisitor = new ExampleVisitor();
    const visitor = new _Visitor$1();
    const rootNode = new Tag(_MESSAGES_TAG);
    rootNode.attrs['handler'] = _XMB_HANDLER;
    messages.forEach(message => {
      const attrs = {
        id: message.id
      };
      if (message.description) {
        attrs['desc'] = message.description;
      }
      if (message.meaning) {
        attrs['meaning'] = message.meaning;
      }
      let sourceTags = [];
      message.sources.forEach(source => {
        sourceTags.push(new Tag(_SOURCE_TAG$2, {}, [new Text$1(`${source.filePath}:${source.startLine}${source.endLine !== source.startLine ? ',' + source.endLine : ''}`)]));
      });
      rootNode.children.push(new CR(2), new Tag(_MESSAGE_TAG, attrs, [...sourceTags, ...visitor.serialize(message.nodes)]));
    });
    rootNode.children.push(new CR());
    return serialize$1([new Declaration({
      version: '1.0',
      encoding: 'UTF-8'
    }), new CR(), new Doctype(_MESSAGES_TAG, _DOCTYPE), new CR(), exampleVisitor.addDefaultExamples(rootNode), new CR()]);
  }
  load(content, url) {
    throw new Error('Unsupported');
  }
  digest(message) {
    return digest(message);
  }
  createNameMapper(message) {
    return new SimplePlaceholderMapper(message, toPublicName);
  }
}
let _Visitor$1 = class _Visitor {
  visitText(text, context) {
    return [new Text$1(text.value)];
  }
  visitContainer(container, context) {
    const nodes = [];
    container.children.forEach(node => nodes.push(...node.visit(this)));
    return nodes;
  }
  visitIcu(icu, context) {
    const nodes = [new Text$1(`{${icu.expressionPlaceholder}, ${icu.type}, `)];
    Object.keys(icu.cases).forEach(c => {
      nodes.push(new Text$1(`${c} {`), ...icu.cases[c].visit(this), new Text$1(`} `));
    });
    nodes.push(new Text$1(`}`));
    return nodes;
  }
  visitTagPlaceholder(ph, context) {
    const startTagAsText = new Text$1(`<${ph.tag}>`);
    const startEx = new Tag(_EXAMPLE_TAG, {}, [startTagAsText]);
    const startTagPh = new Tag(_PLACEHOLDER_TAG$3, {
      name: ph.startName
    }, [startEx, startTagAsText]);
    if (ph.isVoid) {
      return [startTagPh];
    }
    const closeTagAsText = new Text$1(`</${ph.tag}>`);
    const closeEx = new Tag(_EXAMPLE_TAG, {}, [closeTagAsText]);
    const closeTagPh = new Tag(_PLACEHOLDER_TAG$3, {
      name: ph.closeName
    }, [closeEx, closeTagAsText]);
    return [startTagPh, ...this.serialize(ph.children), closeTagPh];
  }
  visitPlaceholder(ph, context) {
    const interpolationAsText = new Text$1(`{{${ph.value}}}`);
    const exTag = new Tag(_EXAMPLE_TAG, {}, [interpolationAsText]);
    return [new Tag(_PLACEHOLDER_TAG$3, {
      name: ph.name
    }, [exTag, interpolationAsText])];
  }
  visitBlockPlaceholder(ph, context) {
    const startAsText = new Text$1(`@${ph.name}`);
    const startEx = new Tag(_EXAMPLE_TAG, {}, [startAsText]);
    const startTagPh = new Tag(_PLACEHOLDER_TAG$3, {
      name: ph.startName
    }, [startEx, startAsText]);
    const closeAsText = new Text$1(`}`);
    const closeEx = new Tag(_EXAMPLE_TAG, {}, [closeAsText]);
    const closeTagPh = new Tag(_PLACEHOLDER_TAG$3, {
      name: ph.closeName
    }, [closeEx, closeAsText]);
    return [startTagPh, ...this.serialize(ph.children), closeTagPh];
  }
  visitIcuPlaceholder(ph, context) {
    const icuExpression = ph.value.expression;
    const icuType = ph.value.type;
    const icuCases = Object.keys(ph.value.cases).map(value => value + ' {...}').join(' ');
    const icuAsText = new Text$1(`{${icuExpression}, ${icuType}, ${icuCases}}`);
    const exTag = new Tag(_EXAMPLE_TAG, {}, [icuAsText]);
    return [new Tag(_PLACEHOLDER_TAG$3, {
      name: ph.name
    }, [exTag, icuAsText])];
  }
  serialize(nodes) {
    return [].concat(...nodes.map(node => node.visit(this)));
  }
};
function digest(message) {
  return decimalDigest(message);
}
class ExampleVisitor {
  addDefaultExamples(node) {
    node.visit(this);
    return node;
  }
  visitTag(tag) {
    if (tag.name === _PLACEHOLDER_TAG$3) {
      if (!tag.children || tag.children.length == 0) {
        const exText = new Text$1(tag.attrs['name'] || '...');
        tag.children = [new Tag(_EXAMPLE_TAG, {}, [exText])];
      }
    } else if (tag.children) {
      tag.children.forEach(node => node.visit(this));
    }
  }
  visitText(text) {}
  visitDeclaration(decl) {}
  visitDoctype(doctype) {}
}
function toPublicName(internalName) {
  return internalName.toUpperCase().replace(/[^A-Z0-9_]/g, '_');
}

const I18N_ATTR = 'i18n';
const I18N_ATTR_PREFIX = 'i18n-';
const I18N_ICU_VAR_PREFIX = 'VAR_';
function isI18nAttribute(name) {
  return name === I18N_ATTR || name.startsWith(I18N_ATTR_PREFIX);
}
function hasI18nAttrs(node) {
  return node.attrs.some(attr => isI18nAttribute(attr.name));
}
function icuFromI18nMessage(message) {
  return message.nodes[0];
}
function formatI18nPlaceholderNamesInMap(params = {}, useCamelCase) {
  const _params = {};
  if (params && Object.keys(params).length) {
    Object.keys(params).forEach(key => _params[formatI18nPlaceholderName(key, useCamelCase)] = params[key]);
  }
  return _params;
}
function formatI18nPlaceholderName(name, useCamelCase = true) {
  const publicName = toPublicName(name);
  if (!useCamelCase) {
    return publicName;
  }
  const chunks = publicName.split('_');
  if (chunks.length === 1) {
    return name.toLowerCase();
  }
  let postfix;
  if (/^\d+$/.test(chunks[chunks.length - 1])) {
    postfix = chunks.pop();
  }
  let raw = chunks.shift().toLowerCase();
  if (chunks.length) {
    raw += chunks.map(c => c.charAt(0).toUpperCase() + c.slice(1).toLowerCase()).join('');
  }
  return postfix ? `${raw}_${postfix}` : raw;
}

const TEMPORARY_NAME = '_t';
const CONTEXT_NAME = 'ctx';
const RENDER_FLAGS = 'rf';
function temporaryAllocator(pushStatement, name) {
  let temp = null;
  return () => {
    if (!temp) {
      pushStatement(new DeclareVarStmt(TEMPORARY_NAME, undefined, DYNAMIC_TYPE));
      temp = variable(name);
    }
    return temp;
  };
}
function asLiteral(value) {
  if (Array.isArray(value)) {
    return literalArr(value.map(asLiteral));
  }
  return literal(value, INFERRED_TYPE);
}
function conditionallyCreateDirectiveBindingLiteral(map, forInputs) {
  const keys = Object.getOwnPropertyNames(map);
  if (keys.length === 0) {
    return null;
  }
  return literalMap(keys.map(key => {
    const value = map[key];
    let declaredName;
    let publicName;
    let minifiedName;
    let expressionValue;
    if (typeof value === 'string') {
      declaredName = key;
      minifiedName = key;
      publicName = value;
      expressionValue = asLiteral(publicName);
    } else {
      minifiedName = key;
      declaredName = value.classPropertyName;
      publicName = value.bindingPropertyName;
      const differentDeclaringName = publicName !== declaredName;
      const hasDecoratorInputTransform = value.transformFunction !== null;
      let flags = InputFlags.None;
      if (value.isSignal) {
        flags |= InputFlags.SignalBased;
      }
      if (hasDecoratorInputTransform) {
        flags |= InputFlags.HasDecoratorInputTransform;
      }
      if (forInputs && (differentDeclaringName || hasDecoratorInputTransform || flags !== InputFlags.None)) {
        const result = [literal(flags), asLiteral(publicName)];
        if (differentDeclaringName || hasDecoratorInputTransform) {
          result.push(asLiteral(declaredName));
          if (hasDecoratorInputTransform) {
            result.push(value.transformFunction);
          }
        }
        expressionValue = literalArr(result);
      } else {
        expressionValue = asLiteral(publicName);
      }
    }
    return {
      key: minifiedName,
      quoted: isUnsafeObjectKey(minifiedName),
      value: expressionValue
    };
  }));
}
class DefinitionMap {
  values = [];
  set(key, value) {
    if (value) {
      const existing = this.values.find(value => value.key === key);
      if (existing) {
        existing.value = value;
      } else {
        this.values.push({
          key: key,
          value,
          quoted: false
        });
      }
    }
  }
  toLiteralMap() {
    return literalMap(this.values);
  }
}
function createCssSelectorFromNode(node) {
  const elementName = node instanceof Element$1 ? node.name : 'ng-template';
  const attributes = getAttrsForDirectiveMatching(node);
  const cssSelector = new CssSelector();
  const elementNameNoNs = splitNsName(elementName)[1];
  cssSelector.setElement(elementNameNoNs);
  Object.getOwnPropertyNames(attributes).forEach(name => {
    const nameNoNs = splitNsName(name)[1];
    const value = attributes[name];
    cssSelector.addAttribute(nameNoNs, value);
    if (name.toLowerCase() === 'class') {
      const classes = value.trim().split(/\s+/);
      classes.forEach(className => cssSelector.addClassName(className));
    }
  });
  return cssSelector;
}
function getAttrsForDirectiveMatching(elOrTpl) {
  const attributesMap = {};
  if (elOrTpl instanceof Template && elOrTpl.tagName !== 'ng-template') {
    elOrTpl.templateAttrs.forEach(a => attributesMap[a.name] = '');
  } else {
    elOrTpl.attributes.forEach(a => {
      if (!isI18nAttribute(a.name)) {
        attributesMap[a.name] = a.value;
      }
    });
    elOrTpl.inputs.forEach(i => {
      if (i.type === BindingType.Property || i.type === BindingType.TwoWay) {
        attributesMap[i.name] = '';
      }
    });
    elOrTpl.outputs.forEach(o => {
      attributesMap[o.name] = '';
    });
  }
  return attributesMap;
}

function compileInjectable(meta, resolveForwardRefs) {
  let result = null;
  const factoryMeta = {
    name: meta.name,
    type: meta.type,
    typeArgumentCount: meta.typeArgumentCount,
    deps: [],
    target: FactoryTarget.Injectable
  };
  if (meta.useClass !== undefined) {
    const useClassOnSelf = meta.useClass.expression.isEquivalent(meta.type.value);
    let deps = undefined;
    if (meta.deps !== undefined) {
      deps = meta.deps;
    }
    if (deps !== undefined) {
      result = compileFactoryFunction({
        ...factoryMeta,
        delegate: meta.useClass.expression,
        delegateDeps: deps,
        delegateType: R3FactoryDelegateType.Class
      });
    } else if (useClassOnSelf) {
      result = compileFactoryFunction(factoryMeta);
    } else {
      result = {
        statements: [],
        expression: delegateToFactory(meta.type.value, meta.useClass.expression, resolveForwardRefs)
      };
    }
  } else if (meta.useFactory !== undefined) {
    if (meta.deps !== undefined) {
      result = compileFactoryFunction({
        ...factoryMeta,
        delegate: meta.useFactory,
        delegateDeps: meta.deps || [],
        delegateType: R3FactoryDelegateType.Function
      });
    } else {
      result = {
        statements: [],
        expression: arrowFn([], meta.useFactory.callFn([]))
      };
    }
  } else if (meta.useValue !== undefined) {
    result = compileFactoryFunction({
      ...factoryMeta,
      expression: meta.useValue.expression
    });
  } else if (meta.useExisting !== undefined) {
    result = compileFactoryFunction({
      ...factoryMeta,
      expression: importExpr(Identifiers.inject).callFn([meta.useExisting.expression])
    });
  } else {
    result = {
      statements: [],
      expression: delegateToFactory(meta.type.value, meta.type.value, resolveForwardRefs)
    };
  }
  const token = meta.type.value;
  const injectableProps = new DefinitionMap();
  injectableProps.set('token', token);
  injectableProps.set('factory', result.expression);
  if (meta.providedIn.expression.value !== null) {
    injectableProps.set('providedIn', convertFromMaybeForwardRefExpression(meta.providedIn));
  }
  const expression = importExpr(Identifiers.ɵɵdefineInjectable).callFn([injectableProps.toLiteralMap()], undefined, true);
  return {
    expression,
    type: createInjectableType(),
    statements: result.statements
  };
}
function createInjectableType(type, typeArgumentCount) {
  return new ExpressionType(importExpr(Identifiers.InjectableDeclaration, [DYNAMIC_TYPE]));
}
function delegateToFactory(type, useType, unwrapForwardRefs) {
  if (type.node === useType.node) {
    return useType.prop('ɵfac');
  }
  if (!unwrapForwardRefs) {
    return createFactoryFunction(useType);
  }
  const unwrappedType = importExpr(Identifiers.resolveForwardRef).callFn([useType]);
  return createFactoryFunction(unwrappedType);
}
function createFactoryFunction(type) {
  const t = new FnParam('__ngFactoryType__', DYNAMIC_TYPE);
  return arrowFn([t], type.prop('ɵfac').callFn([variable(t.name)]));
}

const LEGACY_OPTIONAL_CHAINING_DEFAULT = false;

const $EOF = 0;
const $BSPACE = 8;
const $TAB = 9;
const $LF = 10;
const $VTAB = 11;
const $FF = 12;
const $CR = 13;
const $SPACE = 32;
const $BANG = 33;
const $DQ = 34;
const $HASH = 35;
const $$ = 36;
const $PERCENT = 37;
const $AMPERSAND = 38;
const $SQ = 39;
const $LPAREN = 40;
const $RPAREN = 41;
const $STAR = 42;
const $PLUS = 43;
const $COMMA = 44;
const $MINUS = 45;
const $PERIOD = 46;
const $SLASH = 47;
const $COLON = 58;
const $SEMICOLON = 59;
const $LT = 60;
const $EQ = 61;
const $GT = 62;
const $QUESTION = 63;
const $0 = 48;
const $7 = 55;
const $9 = 57;
const $A = 65;
const $E = 69;
const $F = 70;
const $X = 88;
const $Z = 90;
const $LBRACKET = 91;
const $BACKSLASH = 92;
const $RBRACKET = 93;
const $CARET = 94;
const $_ = 95;
const $a = 97;
const $b = 98;
const $e = 101;
const $f = 102;
const $n = 110;
const $r = 114;
const $t = 116;
const $u = 117;
const $v = 118;
const $x = 120;
const $z = 122;
const $LBRACE = 123;
const $BAR = 124;
const $RBRACE = 125;
const $NBSP = 160;
const $AT = 64;
const $BT = 96;
function isWhitespace(code) {
  return code >= $TAB && code <= $SPACE || code == $NBSP;
}
function isDigit(code) {
  return $0 <= code && code <= $9;
}
function isAsciiLetter(code) {
  return code >= $a && code <= $z || code >= $A && code <= $Z;
}
function isAsciiHexDigit(code) {
  return code >= $a && code <= $f || code >= $A && code <= $F || isDigit(code);
}
function isNewLine(code) {
  return code === $LF || code === $CR;
}
function isOctalDigit(code) {
  return $0 <= code && code <= $7;
}
function isQuote(code) {
  return code === $SQ || code === $DQ || code === $BT;
}

class ParseLocation {
  file;
  offset;
  line;
  col;
  constructor(file, offset, line, col) {
    this.file = file;
    this.offset = offset;
    this.line = line;
    this.col = col;
  }
  toString() {
    return this.offset != null ? `${this.file.url}@${this.line}:${this.col}` : this.file.url;
  }
  moveBy(delta) {
    const source = this.file.content;
    const len = source.length;
    let offset = this.offset;
    let line = this.line;
    let col = this.col;
    while (offset > 0 && delta < 0) {
      offset--;
      delta++;
      const ch = source.charCodeAt(offset);
      if (ch == $LF) {
        line--;
        const priorLine = source.substring(0, offset - 1).lastIndexOf(String.fromCharCode($LF));
        col = priorLine > 0 ? offset - priorLine : offset;
      } else {
        col--;
      }
    }
    while (offset < len && delta > 0) {
      const ch = source.charCodeAt(offset);
      offset++;
      delta--;
      if (ch == $LF) {
        line++;
        col = 0;
      } else {
        col++;
      }
    }
    return new ParseLocation(this.file, offset, line, col);
  }
  getContext(maxChars, maxLines) {
    const content = this.file.content;
    let startOffset = this.offset;
    if (startOffset != null) {
      if (startOffset > content.length - 1) {
        startOffset = content.length - 1;
      }
      let endOffset = startOffset;
      let ctxChars = 0;
      let ctxLines = 0;
      while (ctxChars < maxChars && startOffset > 0) {
        startOffset--;
        ctxChars++;
        if (content[startOffset] == '\n') {
          if (++ctxLines == maxLines) {
            break;
          }
        }
      }
      ctxChars = 0;
      ctxLines = 0;
      while (ctxChars < maxChars && endOffset < content.length - 1) {
        endOffset++;
        ctxChars++;
        if (content[endOffset] == '\n') {
          if (++ctxLines == maxLines) {
            break;
          }
        }
      }
      return {
        before: content.substring(startOffset, this.offset),
        after: content.substring(this.offset, endOffset + 1)
      };
    }
    return null;
  }
}
class ParseSourceFile {
  content;
  url;
  constructor(content, url) {
    this.content = content;
    this.url = url;
  }
}
class ParseSourceSpan {
  start;
  end;
  fullStart;
  details;
  constructor(start, end, fullStart = start, details = null) {
    this.start = start;
    this.end = end;
    this.fullStart = fullStart;
    this.details = details;
  }
  toString() {
    return this.start.file.content.substring(this.start.offset, this.end.offset);
  }
}
var ParseErrorLevel;
(function (ParseErrorLevel) {
  ParseErrorLevel[ParseErrorLevel["WARNING"] = 0] = "WARNING";
  ParseErrorLevel[ParseErrorLevel["ERROR"] = 1] = "ERROR";
})(ParseErrorLevel || (ParseErrorLevel = {}));
class ParseError extends Error {
  span;
  msg;
  level;
  relatedError;
  constructor(span, msg, level = ParseErrorLevel.ERROR, relatedError) {
    super(msg);
    this.span = span;
    this.msg = msg;
    this.level = level;
    this.relatedError = relatedError;
    Object.setPrototypeOf(this, new.target.prototype);
  }
  contextualMessage() {
    const ctx = this.span.start.getContext(100, 3);
    return ctx ? `${this.msg} ("${ctx.before}[${ParseErrorLevel[this.level]} ->]${ctx.after}")` : this.msg;
  }
  toString() {
    const details = this.span.details ? `, ${this.span.details}` : '';
    return `${this.contextualMessage()}: ${this.span.start}${details}`;
  }
}
function r3JitTypeSourceSpan(kind, typeName, sourceUrl) {
  const sourceFileName = `in ${kind} ${typeName} in ${sourceUrl}`;
  const sourceFile = new ParseSourceFile('', sourceFileName);
  return new ParseSourceSpan(new ParseLocation(sourceFile, -1, -1, -1), new ParseLocation(sourceFile, -1, -1, -1));
}
let _anonymousTypeIndex = 0;
function identifierName(compileIdentifier) {
  if (!compileIdentifier || !compileIdentifier.reference) {
    return null;
  }
  const ref = compileIdentifier.reference;
  if (ref['__anonymousType']) {
    return ref['__anonymousType'];
  }
  if (ref['__forward_ref__']) {
    return '__forward_ref__';
  }
  let identifier = stringify(ref);
  if (identifier.indexOf('(') >= 0) {
    identifier = `anonymous_${_anonymousTypeIndex++}`;
    ref['__anonymousType'] = identifier;
  } else {
    identifier = sanitizeIdentifier(identifier);
  }
  return identifier;
}
function sanitizeIdentifier(name) {
  return name.replace(/\W/g, '_');
}

const makeTemplateObjectPolyfill = '(this&&this.__makeTemplateObject||function(e,t){return Object.defineProperty?Object.defineProperty(e,"raw",{value:t}):e.raw=t,e})';
class AbstractJsEmitterVisitor extends AbstractEmitterVisitor {
  constructor() {
    super(false, false);
  }
  visitWrappedNodeExpr(ast, ctx) {
    throw new Error('Cannot emit a WrappedNodeExpr in Javascript.');
  }
  visitDeclareVarStmt(stmt, ctx) {
    ctx.print(stmt, `var ${stmt.name}`);
    if (stmt.value) {
      ctx.print(stmt, ' = ');
      stmt.value.visitExpression(this, ctx);
    }
    ctx.println(stmt, `;`);
  }
  visitTaggedTemplateLiteralExpr(ast, ctx) {
    const elements = ast.template.elements;
    ast.tag.visitExpression(this, ctx);
    ctx.print(ast, `(${makeTemplateObjectPolyfill}(`);
    ctx.print(ast, `[${elements.map(part => escapeIdentifier(part.text)).join(', ')}], `);
    ctx.print(ast, `[${elements.map(part => escapeIdentifier(part.rawText)).join(', ')}])`);
    ast.template.expressions.forEach(expression => {
      ctx.print(ast, ', ');
      expression.visitExpression(this, ctx);
    });
    ctx.print(ast, ')');
  }
  visitTemplateLiteralExpr(expr, ctx) {
    ctx.print(expr, '`');
    for (let i = 0; i < expr.elements.length; i++) {
      expr.elements[i].visitExpression(this, ctx);
      const expression = i < expr.expressions.length ? expr.expressions[i] : null;
      if (expression !== null) {
        ctx.print(expression, '${');
        expression.visitExpression(this, ctx);
        ctx.print(expression, '}');
      }
    }
    ctx.print(expr, '`');
  }
  visitTemplateLiteralElementExpr(expr, ctx) {
    ctx.print(expr, expr.rawText);
  }
  visitLocalizedString(ast, ctx) {
    ctx.print(ast, `$localize(${makeTemplateObjectPolyfill}(`);
    const parts = [ast.serializeI18nHead()];
    for (let i = 1; i < ast.messageParts.length; i++) {
      parts.push(ast.serializeI18nTemplatePart(i));
    }
    ctx.print(ast, `[${parts.map(part => escapeIdentifier(part.cooked)).join(', ')}], `);
    ctx.print(ast, `[${parts.map(part => escapeIdentifier(part.raw)).join(', ')}])`);
    ast.expressions.forEach(expression => {
      ctx.print(ast, ', ');
      expression.visitExpression(this, ctx);
    });
    ctx.print(ast, ')');
  }
}

let policy;
function getPolicy() {
  if (policy === undefined) {
    const trustedTypes = _global['trustedTypes'];
    policy = null;
    if (trustedTypes) {
      try {
        policy = trustedTypes.createPolicy('angular#unsafe-jit', {
          createScript: s => s
        });
      } catch {}
    }
  }
  return policy;
}
function trustedScriptFromString(script) {
  return getPolicy()?.createScript(script) || script;
}
function newTrustedFunctionForJIT(...args) {
  if (!_global['trustedTypes']) {
    return new Function(...args);
  }
  const fnArgs = args.slice(0, -1).join(',');
  const fnBody = args[args.length - 1];
  const body = `(function anonymous(${fnArgs}
) { ${fnBody}
})`;
  const fn = _global['eval'](trustedScriptFromString(body));
  if (fn.bind === undefined) {
    return new Function(...args);
  }
  fn.toString = () => body;
  return fn.bind(_global);
}

class JitEvaluator {
  evaluateStatements(sourceUrl, statements, refResolver, createSourceMaps) {
    const converter = new JitEmitterVisitor(refResolver);
    const ctx = EmitterVisitorContext.createRoot();
    if (statements.length > 0 && !isUseStrictStatement(statements[0])) {
      statements = [literal('use strict').toStmt(), ...statements];
    }
    converter.visitAllStatements(statements, ctx);
    converter.createReturnStmt(ctx);
    return this.evaluateCode(sourceUrl, ctx, converter.getArgs(), createSourceMaps);
  }
  evaluateCode(sourceUrl, ctx, vars, createSourceMap) {
    let fnBody = `"use strict";${ctx.toSource()}\n//# sourceURL=${sourceUrl}`;
    const fnArgNames = [];
    const fnArgValues = [];
    for (const argName in vars) {
      fnArgValues.push(vars[argName]);
      fnArgNames.push(argName);
    }
    if (createSourceMap) {
      const emptyFn = newTrustedFunctionForJIT(...fnArgNames.concat('return null;')).toString();
      const headerLines = emptyFn.slice(0, emptyFn.indexOf('return null;')).split('\n').length - 1;
      fnBody += `\n${ctx.toSourceMapGenerator(sourceUrl, headerLines).toJsComment()}`;
    }
    const fn = newTrustedFunctionForJIT(...fnArgNames.concat(fnBody));
    return this.executeFunction(fn, fnArgValues);
  }
  executeFunction(fn, args) {
    return fn(...args);
  }
}
class JitEmitterVisitor extends AbstractJsEmitterVisitor {
  refResolver;
  _evalArgNames = [];
  _evalArgValues = [];
  _evalExportedVars = [];
  constructor(refResolver) {
    super();
    this.refResolver = refResolver;
  }
  createReturnStmt(ctx) {
    const stmt = new ReturnStatement(new LiteralMapExpr(this._evalExportedVars.map(resultVar => new LiteralMapPropertyAssignment(resultVar, variable(resultVar), false))));
    stmt.visitStatement(this, ctx);
  }
  getArgs() {
    const result = {};
    for (let i = 0; i < this._evalArgNames.length; i++) {
      result[this._evalArgNames[i]] = this._evalArgValues[i];
    }
    return result;
  }
  visitExternalExpr(ast, ctx) {
    this._emitReferenceToExternal(ast, this.refResolver.resolveExternalReference(ast.value), ctx);
    return null;
  }
  visitWrappedNodeExpr(ast, ctx) {
    this._emitReferenceToExternal(ast, ast.node, ctx);
    return null;
  }
  visitDeclareVarStmt(stmt, ctx) {
    if (stmt.hasModifier(StmtModifier.Exported)) {
      this._evalExportedVars.push(stmt.name);
    }
    return super.visitDeclareVarStmt(stmt, ctx);
  }
  visitDeclareFunctionStmt(stmt, ctx) {
    if (stmt.hasModifier(StmtModifier.Exported)) {
      this._evalExportedVars.push(stmt.name);
    }
    return super.visitDeclareFunctionStmt(stmt, ctx);
  }
  _emitReferenceToExternal(ast, value, ctx) {
    let id = this._evalArgValues.indexOf(value);
    if (id === -1) {
      id = this._evalArgValues.length;
      this._evalArgValues.push(value);
      const name = identifierName({
        reference: value
      }) || 'val';
      this._evalArgNames.push(`jit_${name}_${id}`);
    }
    ctx.print(ast, this._evalArgNames[id]);
  }
}
function isUseStrictStatement(statement) {
  return statement.isEquivalent(literal('use strict').toStmt());
}

function compileInjector(meta) {
  const definitionMap = new DefinitionMap();
  if (meta.providers !== null) {
    definitionMap.set('providers', meta.providers);
  }
  if (meta.imports.length > 0) {
    definitionMap.set('imports', literalArr(meta.imports));
  }
  const expression = importExpr(Identifiers.defineInjector).callFn([definitionMap.toLiteralMap()], undefined, true);
  const type = createInjectorType(meta);
  return {
    expression,
    type,
    statements: []
  };
}
function createInjectorType(meta) {
  return new ExpressionType(importExpr(Identifiers.InjectorDeclaration, [new ExpressionType(meta.type.type)]));
}

class R3JitReflector {
  context;
  constructor(context) {
    this.context = context;
  }
  resolveExternalReference(ref) {
    if (ref.moduleName !== '@angular/core') {
      throw new Error(`Cannot resolve external reference to ${ref.moduleName}, only references to @angular/core are supported.`);
    }
    if (!Object.hasOwn(this.context, ref.name)) {
      throw new Error(`No value provided for @angular/core symbol '${ref.name}'.`);
    }
    return this.context[ref.name];
  }
}

var R3SelectorScopeMode;
(function (R3SelectorScopeMode) {
  R3SelectorScopeMode[R3SelectorScopeMode["Inline"] = 0] = "Inline";
  R3SelectorScopeMode[R3SelectorScopeMode["SideEffect"] = 1] = "SideEffect";
  R3SelectorScopeMode[R3SelectorScopeMode["Omit"] = 2] = "Omit";
})(R3SelectorScopeMode || (R3SelectorScopeMode = {}));
var R3NgModuleMetadataKind;
(function (R3NgModuleMetadataKind) {
  R3NgModuleMetadataKind[R3NgModuleMetadataKind["Global"] = 0] = "Global";
  R3NgModuleMetadataKind[R3NgModuleMetadataKind["Local"] = 1] = "Local";
  R3NgModuleMetadataKind[R3NgModuleMetadataKind["Isolated"] = 2] = "Isolated";
})(R3NgModuleMetadataKind || (R3NgModuleMetadataKind = {}));
function compileNgModule(meta) {
  const statements = [];
  const definitionMap = new DefinitionMap();
  definitionMap.set('type', meta.type.value);
  if (meta.kind === R3NgModuleMetadataKind.Global && meta.bootstrap.length > 0) {
    definitionMap.set('bootstrap', refsToArray(meta.bootstrap, meta.containsForwardDecls));
  }
  if (meta.selectorScopeMode === R3SelectorScopeMode.Inline) {
    if (meta.declarations.length > 0) {
      definitionMap.set('declarations', refsToArray(meta.declarations, meta.containsForwardDecls));
    }
    if (meta.imports.length > 0) {
      definitionMap.set('imports', refsToArray(meta.imports, meta.containsForwardDecls));
    }
    if (meta.exports.length > 0) {
      definitionMap.set('exports', refsToArray(meta.exports, meta.containsForwardDecls));
    }
  } else if (meta.selectorScopeMode === R3SelectorScopeMode.SideEffect) {
    const setNgModuleScopeCall = generateSetNgModuleScopeCall(meta);
    if (setNgModuleScopeCall !== null) {
      statements.push(setNgModuleScopeCall);
    }
  } else ;
  if (meta.schemas !== null && meta.schemas.length > 0) {
    definitionMap.set('schemas', literalArr(meta.schemas.map(ref => ref.value)));
  }
  if (meta.id !== null) {
    definitionMap.set('id', meta.id);
    statements.push(importExpr(Identifiers.registerNgModuleType).callFn([meta.type.value, meta.id]).toStmt());
  }
  const expression = importExpr(Identifiers.defineNgModule).callFn([definitionMap.toLiteralMap()], undefined, true);
  const type = createNgModuleType(meta);
  return {
    expression,
    type,
    statements
  };
}
function compileNgModuleDeclarationExpression(meta) {
  const definitionMap = new DefinitionMap();
  definitionMap.set('type', new WrappedNodeExpr(meta.type));
  if (meta.bootstrap !== undefined) {
    definitionMap.set('bootstrap', new WrappedNodeExpr(meta.bootstrap));
  }
  if (meta.declarations !== undefined) {
    definitionMap.set('declarations', new WrappedNodeExpr(meta.declarations));
  }
  if (meta.imports !== undefined) {
    definitionMap.set('imports', new WrappedNodeExpr(meta.imports));
  }
  if (meta.exports !== undefined) {
    definitionMap.set('exports', new WrappedNodeExpr(meta.exports));
  }
  if (meta.schemas !== undefined) {
    definitionMap.set('schemas', new WrappedNodeExpr(meta.schemas));
  }
  if (meta.id !== undefined) {
    definitionMap.set('id', new WrappedNodeExpr(meta.id));
  }
  return importExpr(Identifiers.defineNgModule).callFn([definitionMap.toLiteralMap()]);
}
function createNgModuleType(meta) {
  if (meta.kind === R3NgModuleMetadataKind.Local) {
    return new ExpressionType(meta.type.value);
  }
  if (meta.kind === R3NgModuleMetadataKind.Isolated) {
    return new ExpressionType(importExpr(Identifiers.NgModuleDeclaration, [new ExpressionType(meta.type.type), NONE_TYPE, meta.importsExpression ? expressionType(meta.importsExpression) : NONE_TYPE, meta.exportsExpression ? expressionType(meta.exportsExpression) : NONE_TYPE]));
  }
  const {
    type: moduleType,
    declarations,
    exports,
    imports,
    includeImportTypes,
    publicDeclarationTypes
  } = meta;
  return new ExpressionType(importExpr(Identifiers.NgModuleDeclaration, [new ExpressionType(moduleType.type), publicDeclarationTypes === null ? tupleTypeOf(declarations) : tupleOfTypes(publicDeclarationTypes), includeImportTypes ? tupleTypeOf(imports) : NONE_TYPE, tupleTypeOf(exports)]));
}
function generateSetNgModuleScopeCall(meta) {
  const scopeMap = new DefinitionMap();
  if (meta.kind === R3NgModuleMetadataKind.Global) {
    if (meta.declarations.length > 0) {
      scopeMap.set('declarations', refsToArray(meta.declarations, meta.containsForwardDecls));
    }
  } else if (meta.kind === R3NgModuleMetadataKind.Local) {
    if (meta.declarationsExpression) {
      scopeMap.set('declarations', meta.declarationsExpression);
    }
  }
  if (meta.kind === R3NgModuleMetadataKind.Global) {
    if (meta.imports.length > 0) {
      scopeMap.set('imports', refsToArray(meta.imports, meta.containsForwardDecls));
    }
  } else if (meta.kind === R3NgModuleMetadataKind.Local) {
    if (meta.importsExpression) {
      scopeMap.set('imports', meta.importsExpression);
    }
  }
  if (meta.kind === R3NgModuleMetadataKind.Global) {
    if (meta.exports.length > 0) {
      scopeMap.set('exports', refsToArray(meta.exports, meta.containsForwardDecls));
    }
  } else if (meta.kind === R3NgModuleMetadataKind.Local) {
    if (meta.exportsExpression) {
      scopeMap.set('exports', meta.exportsExpression);
    }
  }
  if (meta.kind === R3NgModuleMetadataKind.Local && meta.bootstrapExpression) {
    scopeMap.set('bootstrap', meta.bootstrapExpression);
  }
  if (Object.keys(scopeMap.values).length === 0) {
    return null;
  }
  const fnCall = new InvokeFunctionExpr(importExpr(Identifiers.setNgModuleScope), [meta.type.value, scopeMap.toLiteralMap()]);
  const guardedCall = jitOnlyGuardedExpression(fnCall);
  const iife = new FunctionExpr([], [guardedCall.toStmt()]);
  const iifeCall = new InvokeFunctionExpr(iife, []);
  return iifeCall.toStmt();
}
function tupleTypeOf(exp) {
  const types = exp.map(ref => typeofExpr(ref.type));
  return exp.length > 0 ? expressionType(literalArr(types)) : NONE_TYPE;
}
function tupleOfTypes(types) {
  const typeofTypes = types.map(type => typeofExpr(type));
  return types.length > 0 ? expressionType(literalArr(typeofTypes)) : NONE_TYPE;
}

function compilePipeFromMetadata(metadata) {
  const definitionMapValues = [];
  definitionMapValues.push({
    key: 'name',
    value: literal(metadata.pipeName ?? metadata.name),
    quoted: false
  });
  definitionMapValues.push({
    key: 'type',
    value: metadata.type.value,
    quoted: false
  });
  definitionMapValues.push({
    key: 'pure',
    value: literal(metadata.pure),
    quoted: false
  });
  if (metadata.isStandalone === false) {
    definitionMapValues.push({
      key: 'standalone',
      value: literal(false),
      quoted: false
    });
  }
  const expression = importExpr(Identifiers.definePipe).callFn([literalMap(definitionMapValues)], undefined, true);
  const type = createPipeType(metadata);
  return {
    expression,
    type,
    statements: []
  };
}
function createPipeType(metadata) {
  return new ExpressionType(importExpr(Identifiers.PipeDeclaration, [typeWithParameters(metadata.type.type, metadata.typeArgumentCount), new ExpressionType(new LiteralExpr(metadata.pipeName)), new ExpressionType(new LiteralExpr(metadata.isStandalone))]));
}

var R3TemplateDependencyKind;
(function (R3TemplateDependencyKind) {
  R3TemplateDependencyKind[R3TemplateDependencyKind["Directive"] = 0] = "Directive";
  R3TemplateDependencyKind[R3TemplateDependencyKind["Pipe"] = 1] = "Pipe";
  R3TemplateDependencyKind[R3TemplateDependencyKind["NgModule"] = 2] = "NgModule";
})(R3TemplateDependencyKind || (R3TemplateDependencyKind = {}));

const animationKeywords = new Set(['inherit', 'initial', 'revert', 'unset', 'alternate', 'alternate-reverse', 'normal', 'reverse', 'backwards', 'both', 'forwards', 'none', 'paused', 'running', 'ease', 'ease-in', 'ease-in-out', 'ease-out', 'linear', 'step-start', 'step-end', 'end', 'jump-both', 'jump-end', 'jump-none', 'jump-start', 'start']);
const scopedAtRuleIdentifiers = ['@media', '@supports', '@document', '@layer', '@container', '@scope', '@starting-style'];
class ShadowCss {
  shimCssText(cssText, selector, hostSelector = '') {
    const comments = [];
    cssText = cssText.replace(_commentRe, m => {
      if (m.match(_commentWithHashRe)) {
        comments.push(m);
      } else {
        const newLinesMatches = m.match(_newLinesRe);
        comments.push(newLinesMatches?.join('') ?? '');
      }
      return COMMENT_PLACEHOLDER;
    });
    const scopedCssText = this._scopeCssText(cssText, selector, hostSelector);
    let commentIdx = 0;
    return scopedCssText.replace(_commentWithHashPlaceHolderRe, () => comments[commentIdx++]);
  }
  _scopeKeyframesRelatedCss(cssText, scopeSelector) {
    const unscopedKeyframesSet = new Set();
    const scopedKeyframesCssText = processRules(cssText, rule => this._scopeLocalKeyframeDeclarations(rule, scopeSelector, unscopedKeyframesSet));
    return processRules(scopedKeyframesCssText, rule => this._scopeAnimationRule(rule, scopeSelector, unscopedKeyframesSet));
  }
  _scopeLocalKeyframeDeclarations(rule, scopeSelector, unscopedKeyframesSet) {
    return {
      ...rule,
      selector: rule.selector.replace(/(^@(?:-webkit-)?keyframes(?:\s+))(['"]?)(.+)\2(\s*)$/, (_, start, quote, keyframeName, endSpaces) => {
        unscopedKeyframesSet.add(unescapeQuotes(keyframeName, quote));
        return `${start}${quote}${scopeSelector}_${keyframeName}${quote}${endSpaces}`;
      })
    };
  }
  _scopeAnimationKeyframe(keyframe, scopeSelector, unscopedKeyframesSet) {
    return keyframe.replace(/^(\s*)(['"]?)(.+?)\2(\s*)$/, (_, spaces1, quote, name, spaces2) => {
      name = `${unscopedKeyframesSet.has(unescapeQuotes(name, quote)) ? scopeSelector + '_' : ''}${name}`;
      return `${spaces1}${quote}${name}${quote}${spaces2}`;
    });
  }
  _animationDeclarationKeyframesRe = /(^|\s+|,)(?:(?:(['"])((?:\\\\|\\\2|(?!\2).)+)\2)|(-?[A-Za-z][\w\-]*))(?=[,\s]|$)/g;
  _scopeAnimationRule(rule, scopeSelector, unscopedKeyframesSet) {
    let content = rule.content.replace(/((?:^|[\s;{])(?:-webkit-)?animation\s*:\s*)([^;}]+)/g, (_, start, animationDeclarations) => start + animationDeclarations.replace(this._animationDeclarationKeyframesRe, (original, leadingSpaces, quote = '', quotedName, nonQuotedName) => {
      if (quotedName) {
        return `${leadingSpaces}${this._scopeAnimationKeyframe(`${quote}${quotedName}${quote}`, scopeSelector, unscopedKeyframesSet)}`;
      } else {
        return animationKeywords.has(nonQuotedName) ? original : `${leadingSpaces}${this._scopeAnimationKeyframe(nonQuotedName, scopeSelector, unscopedKeyframesSet)}`;
      }
    }));
    content = content.replace(/((?:^|[\s;{])(?:-webkit-)?animation-name(?:\s*):(?:\s*))([^;}]+)/g, (_match, start, commaSeparatedKeyframes) => `${start}${commaSeparatedKeyframes.split(',').map(keyframe => this._scopeAnimationKeyframe(keyframe, scopeSelector, unscopedKeyframesSet)).join(',')}`);
    return {
      ...rule,
      content
    };
  }
  _scopeCssText(cssText, scopeSelector, hostSelector) {
    cssText = this._insertPolyfillHostInCssText(cssText);
    cssText = this._convertColonHost(cssText);
    cssText = this._convertColonHostContext(cssText);
    if (scopeSelector) {
      cssText = this._scopeKeyframesRelatedCss(cssText, scopeSelector);
      cssText = this._scopeSelectors(cssText, scopeSelector, hostSelector);
    }
    return cssText.trim();
  }
  _convertColonHost(cssText) {
    return cssText.replace(_cssColonHostRe, (_, hostSelectors, otherSelectors) => {
      if (hostSelectors) {
        const parts = [...this._splitOnTopLevelCommas(hostSelectors, true)];
        if (parts.length > 1) {
          return ':host(' + hostSelectors + ')' + otherSelectors;
        }
        const trimmedHostSelector = parts[0].trim();
        if (trimmedHostSelector) {
          return _polyfillHostNoCombinator + trimmedHostSelector.replace(_polyfillHost, '') + otherSelectors;
        }
      }
      return _polyfillHostNoCombinator + otherSelectors;
    });
  }
  *_splitOnTopLevelCommas(text, returnOnClosingParen) {
    const length = text.length;
    let parens = 0;
    let prev = 0;
    for (let i = 0; i < length; i++) {
      const charCode = text.charCodeAt(i);
      if (charCode === $LPAREN) {
        parens++;
      } else if (charCode === $RPAREN) {
        parens--;
        if (parens < 0 && returnOnClosingParen) {
          yield text.slice(prev, i);
          return;
        }
      } else if (charCode === $COMMA && parens === 0) {
        yield text.slice(prev, i);
        prev = i + 1;
      }
    }
    yield text.slice(prev);
  }
  _convertColonHostContext(cssText) {
    const results = [];
    for (const part of this._splitOnTopLevelCommas(cssText, false)) {
      results.push(this._convertColonHostContextInSelectorPart(part));
    }
    return results.join(',');
  }
  _convertColonHostContextInSelectorPart(cssText) {
    return cssText.replace(_cssColonHostContextReGlobal, (selectorText, pseudoPrefix) => {
      const contextSelectorGroups = [[]];
      let startIndex = selectorText.indexOf(_polyfillHostContext);
      while (startIndex !== -1) {
        const afterPrefix = selectorText.substring(startIndex + _polyfillHostContext.length);
        if (!afterPrefix || afterPrefix[0] !== '(') {
          selectorText = afterPrefix;
          startIndex = selectorText.indexOf(_polyfillHostContext);
          continue;
        }
        const newContextSelectors = [];
        let endIndex = 0;
        for (const selector of this._splitOnTopLevelCommas(afterPrefix.substring(1), true)) {
          endIndex = endIndex + selector.length + 1;
          const trimmed = selector.trim();
          if (trimmed) {
            newContextSelectors.push(trimmed);
          }
        }
        const contextSelectorGroupsLength = contextSelectorGroups.length;
        repeatGroups(contextSelectorGroups, newContextSelectors.length);
        for (let i = 0; i < newContextSelectors.length; i++) {
          for (let j = 0; j < contextSelectorGroupsLength; j++) {
            contextSelectorGroups[j + i * contextSelectorGroupsLength].push(newContextSelectors[i]);
          }
        }
        selectorText = afterPrefix.substring(endIndex + 1);
        startIndex = selectorText.indexOf(_polyfillHostContext);
      }
      return contextSelectorGroups.map(contextSelectors => _combineHostContextSelectors(contextSelectors, selectorText, pseudoPrefix)).join(', ');
    });
  }
  _scopeSelectors(cssText, scopeSelector, hostSelector) {
    return processRules(cssText, rule => {
      let selector = rule.selector;
      let content = rule.content;
      if (rule.selector[0] !== '@') {
        selector = this._scopeSelector({
          selector,
          scopeSelector,
          hostSelector,
          isParentSelector: true
        });
      } else if (scopedAtRuleIdentifiers.some(atRule => rule.selector.startsWith(atRule))) {
        content = this._scopeSelectors(rule.content, scopeSelector, hostSelector);
      } else if (rule.selector.startsWith('@font-face') || rule.selector.startsWith('@page')) {
        content = this._stripScopingSelectors(rule.content);
      }
      return new CssRule(selector, content);
    });
  }
  _stripScopingSelectors(cssText) {
    return processRules(cssText, rule => {
      const selector = rule.selector.replace(_shadowDeepSelectors, ' ').replace(_polyfillHostNoCombinatorRe, ' ');
      return new CssRule(selector, rule.content);
    });
  }
  _safeSelector;
  _shouldScopeIndicator;
  _scopeSelector({
    selector,
    scopeSelector,
    hostSelector,
    isParentSelector = false
  }) {
    const selectorSplitRe = / ?,(?!(?:[^)(]*(?:\([^)(]*(?:\([^)(]*(?:\([^)(]*\)[^)(]*)*\)[^)(]*)*\)[^)(]*)*\))) ?/;
    return selector.split(selectorSplitRe).map(part => part.split(_shadowDeepSelectors)).map(deepParts => {
      const [shallowPart, ...otherParts] = deepParts;
      const applyScope = shallowPart => {
        if (this._selectorNeedsScoping(shallowPart, scopeSelector)) {
          return this._applySelectorScope({
            selector: shallowPart,
            scopeSelector,
            hostSelector,
            isParentSelector
          });
        } else {
          return shallowPart;
        }
      };
      return [applyScope(shallowPart), ...otherParts].join(' ');
    }).join(', ');
  }
  _selectorNeedsScoping(selector, scopeSelector) {
    const re = this._makeScopeMatcher(scopeSelector);
    return !re.test(selector);
  }
  _makeScopeMatcher(scopeSelector) {
    const lre = /\[/g;
    const rre = /\]/g;
    scopeSelector = scopeSelector.replace(lre, '\\[').replace(rre, '\\]');
    return new RegExp('^(' + scopeSelector + ')' + _selectorReSuffix, 'm');
  }
  _applySimpleSelectorScope(selector, scopeSelector, hostSelector) {
    _polyfillHostRe.lastIndex = 0;
    if (_polyfillHostRe.test(selector)) {
      const replaceBy = `[${hostSelector}]`;
      let result = selector;
      while (result.match(_polyfillHostNoCombinatorRe)) {
        result = result.replace(_polyfillHostNoCombinatorRe, (_hnc, selector) => {
          return selector.replace(/([^:\)]*)(:*)(.*)/, (_, before, colon, after) => {
            return before + replaceBy + colon + after;
          });
        });
      }
      return result.replace(_polyfillHostRe, replaceBy);
    }
    return scopeSelector + ' ' + selector;
  }
  _applySelectorScope({
    selector,
    scopeSelector,
    hostSelector,
    isParentSelector
  }) {
    const isRe = /\[is=([^\]]*)\]/g;
    scopeSelector = scopeSelector.replace(isRe, (_, ...parts) => parts[0]);
    const attrName = `[${scopeSelector}]`;
    const _scopeSelectorPart = p => {
      let scopedP = p.trim();
      if (!scopedP) {
        return p;
      }
      if (p.includes(_polyfillHostNoCombinator)) {
        scopedP = this._applySimpleSelectorScope(p, scopeSelector, hostSelector);
        if (!p.match(_polyfillHostNoCombinatorOutsidePseudoFunction)) {
          const [_, before, colon, after] = scopedP.match(/([^:]*)(:*)([\s\S]*)/);
          scopedP = before + attrName + colon + after;
        }
      } else {
        const t = p.replace(_polyfillHostRe, '');
        if (t.length > 0) {
          const matches = t.match(/([^:]*)(:*)([\s\S]*)/);
          if (matches) {
            scopedP = matches[1] + attrName + matches[2] + matches[3];
          }
        }
      }
      return scopedP;
    };
    const _pseudoFunctionAwareScopeSelectorPart = selectorPart => {
      let scopedPart = '';
      const pseudoSelectorParts = [];
      let pseudoSelectorMatch;
      while ((pseudoSelectorMatch = _cssPrefixWithPseudoSelectorFunction.exec(selectorPart)) !== null) {
        let openedBrackets = 1;
        let index = _cssPrefixWithPseudoSelectorFunction.lastIndex;
        while (index < selectorPart.length) {
          const currentSymbol = selectorPart[index];
          index++;
          if (currentSymbol === '(') {
            openedBrackets++;
            continue;
          }
          if (currentSymbol === ')') {
            openedBrackets--;
            if (openedBrackets === 0) {
              break;
            }
            continue;
          }
        }
        pseudoSelectorParts.push(`${pseudoSelectorMatch[0]}${selectorPart.slice(_cssPrefixWithPseudoSelectorFunction.lastIndex, index)}`);
        _cssPrefixWithPseudoSelectorFunction.lastIndex = index;
      }
      if (pseudoSelectorParts.join('') === selectorPart) {
        scopedPart = pseudoSelectorParts.map(selectorPart => {
          const [cssPseudoSelectorFunction] = selectorPart.match(_cssPrefixWithPseudoSelectorFunction) ?? [];
          const selectorToScope = selectorPart.slice(cssPseudoSelectorFunction?.length, -1);
          if (selectorToScope.includes(_polyfillHostNoCombinator)) {
            this._shouldScopeIndicator = true;
          }
          const scopedInnerPart = this._scopeSelector({
            selector: selectorToScope,
            scopeSelector,
            hostSelector
          });
          return `${cssPseudoSelectorFunction}${scopedInnerPart})`;
        }).join('');
      } else {
        this._shouldScopeIndicator = this._shouldScopeIndicator || selectorPart.includes(_polyfillHostNoCombinator);
        scopedPart = this._shouldScopeIndicator ? _scopeSelectorPart(selectorPart) : selectorPart;
      }
      return scopedPart;
    };
    if (isParentSelector) {
      this._safeSelector = new SafeSelector(selector);
      selector = this._safeSelector.content();
    }
    let scopedSelector = '';
    let startIndex = 0;
    let res;
    const sep = /( |>|\+|~(?!=))(?!([^)(]*(?:\([^)(]*(?:\([^)(]*(?:\([^)(]*\)[^)(]*)*\)[^)(]*)*\)[^)(]*)*\)))\s*/g;
    const hasHost = selector.includes(_polyfillHostNoCombinator);
    if (isParentSelector || this._shouldScopeIndicator) {
      this._shouldScopeIndicator = !hasHost;
    }
    while ((res = sep.exec(selector)) !== null) {
      const separator = res[1];
      const part = selector.slice(startIndex, res.index);
      if (part.match(/__esc-ph-(\d+)__/) && selector[res.index + 1]?.match(/[a-fA-F\d]/)) {
        continue;
      }
      const scopedPart = _pseudoFunctionAwareScopeSelectorPart(part);
      scopedSelector += `${scopedPart} ${separator} `;
      startIndex = sep.lastIndex;
    }
    const part = selector.substring(startIndex);
    scopedSelector += _pseudoFunctionAwareScopeSelectorPart(part);
    return this._safeSelector.restore(scopedSelector);
  }
  _insertPolyfillHostInCssText(selector) {
    return selector.replace(_colonHostContextRe, _polyfillHostContext).replace(_colonHostRe, _polyfillHost);
  }
}
class SafeSelector {
  placeholders = [];
  index = 0;
  _content;
  constructor(selector) {
    selector = this._escapeRegexMatches(selector, /(\[[^\]]*\])/g);
    selector = selector.replace(/(\\.)/g, (_, keep) => {
      const replaceBy = `__esc-ph-${this.index}__`;
      this.placeholders.push(keep);
      this.index++;
      return replaceBy;
    });
    this._content = selector.replace(nthRegex, (_, pseudo, exp) => {
      const replaceBy = `__ph-${this.index}__`;
      this.placeholders.push(`(${exp})`);
      this.index++;
      return pseudo + replaceBy;
    });
  }
  restore(content) {
    return content.replace(/__(?:ph|esc-ph)-(\d+)__/g, (_ph, index) => this.placeholders[+index]);
  }
  content() {
    return this._content;
  }
  _escapeRegexMatches(content, pattern) {
    return content.replace(pattern, (_, keep) => {
      const replaceBy = `__ph-${this.index}__`;
      this.placeholders.push(keep);
      this.index++;
      return replaceBy;
    });
  }
}
const _cssScopedPseudoFunctionPrefix = '(:(where|is)\\()?';
const _cssPrefixWithPseudoSelectorFunction = /:(where|is)\(/gi;
const _polyfillHost = '-shadowcsshost';
const _polyfillHostContext = '-shadowcsscontext';
const _noParens = '[^)(]*';
const _level1Parens = String.raw`(?:\(${_noParens}\)|${_noParens})+?`;
const _level2Parens = String.raw`(?:\(${_level1Parens}\)|${_noParens})+?`;
const _parenSuffix = String.raw`(?:\((${_level2Parens})\))`;
const nthRegex = new RegExp(String.raw`(:nth-[-\w]+)` + _parenSuffix, 'g');
const _cssColonHostRe = new RegExp(_polyfillHost + _parenSuffix + '?([^,{]*)', 'gim');
const _hostContextPattern = _polyfillHostContext + _parenSuffix + '([^{]*)';
const _cssColonHostContextReGlobal = new RegExp(`${_cssScopedPseudoFunctionPrefix}(${_hostContextPattern})`, 'gim');
const _polyfillHostNoCombinator = _polyfillHost + '-no-combinator';
const _polyfillHostNoCombinatorOutsidePseudoFunction = new RegExp(`${_polyfillHostNoCombinator}(?![^(]*\\))`, 'g');
const _polyfillHostNoCombinatorRe = /-shadowcsshost-no-combinator([^\s,]*)/;
const _shadowDeepSelectors = /(?:>>>)|(?:\/deep\/)|(?:::ng-deep)/g;
const _selectorReSuffix = '([>\\s~+[.,{:][\\s\\S]*)?$';
const _polyfillHostRe = /-shadowcsshost/gim;
const _colonHostRe = /:host(?!\-context)/gim;
const _colonHostContextRe = /:host-context(?=\(\s*[^)\s])/gim;
const _newLinesRe = /\r?\n/g;
const _commentRe = /\/\*[\s\S]*?\*\//g;
const _commentWithHashRe = /\/\*\s*#\s*source(Mapping)?URL=/g;
const COMMENT_PLACEHOLDER = '%COMMENT%';
const _commentWithHashPlaceHolderRe = new RegExp(COMMENT_PLACEHOLDER, 'g');
const BLOCK_PLACEHOLDER = '%BLOCK%';
const _ruleRe = new RegExp(`(\\s*(?:${COMMENT_PLACEHOLDER}\\s*)*)([^;\\{\\}]+?)(\\s*)((?:{%BLOCK%}?\\s*;?)|(?:\\s*;))`, 'g');
const CONTENT_PAIRS = new Map([['{', '}']]);
const COMMA_IN_PLACEHOLDER = '%COMMA_IN_PLACEHOLDER%';
const SEMI_IN_PLACEHOLDER = '%SEMI_IN_PLACEHOLDER%';
const COLON_IN_PLACEHOLDER = '%COLON_IN_PLACEHOLDER%';
const _cssCommaInPlaceholderReGlobal = new RegExp(COMMA_IN_PLACEHOLDER, 'g');
const _cssSemiInPlaceholderReGlobal = new RegExp(SEMI_IN_PLACEHOLDER, 'g');
const _cssColonInPlaceholderReGlobal = new RegExp(COLON_IN_PLACEHOLDER, 'g');
const _cssVariableRe = /(var\(\s*|@property\s+)?(--(?:[a-zA-Z0-9_-]|[^\x00-\x7F])+)(\s*:)?/g;
function namespaceCssVariables(cssText) {
  return cssText.replace(_cssVariableRe, (match, prefix, varName, trailingColon) => {
    if (!prefix && !trailingColon) {
      return match;
    }
    return (prefix ?? '') + namespaceCssVariable(varName) + (trailingColon ?? '');
  });
}
class CssRule {
  selector;
  content;
  constructor(selector, content) {
    this.selector = selector;
    this.content = content;
  }
}
function processRules(input, ruleCallback) {
  const escaped = escapeInStrings(input);
  const inputWithEscapedBlocks = escapeBlocks(escaped, CONTENT_PAIRS, BLOCK_PLACEHOLDER);
  let nextBlockIndex = 0;
  const escapedResult = inputWithEscapedBlocks.escapedString.replace(_ruleRe, (...m) => {
    const selector = m[2];
    let content = '';
    let suffix = m[4];
    let contentPrefix = '';
    if (suffix && suffix.startsWith('{' + BLOCK_PLACEHOLDER)) {
      content = inputWithEscapedBlocks.blocks[nextBlockIndex++];
      suffix = suffix.substring(BLOCK_PLACEHOLDER.length + 1);
      contentPrefix = '{';
    }
    const rule = ruleCallback(new CssRule(selector, content));
    return `${m[1]}${rule.selector}${m[3]}${contentPrefix}${rule.content}${suffix}`;
  });
  return unescapeInStrings(escapedResult);
}
class StringWithEscapedBlocks {
  escapedString;
  blocks;
  constructor(escapedString, blocks) {
    this.escapedString = escapedString;
    this.blocks = blocks;
  }
}
function escapeBlocks(input, charPairs, placeholder) {
  const resultParts = [];
  const escapedBlocks = [];
  let openCharCount = 0;
  let nonBlockStartIndex = 0;
  let blockStartIndex = -1;
  let openChar;
  let closeChar;
  for (let i = 0; i < input.length; i++) {
    const char = input[i];
    if (char === '\\') {
      i++;
    } else if (char === closeChar) {
      openCharCount--;
      if (openCharCount === 0) {
        escapedBlocks.push(input.substring(blockStartIndex, i));
        resultParts.push(placeholder);
        nonBlockStartIndex = i;
        blockStartIndex = -1;
        openChar = closeChar = undefined;
      }
    } else if (char === openChar) {
      openCharCount++;
    } else if (openCharCount === 0 && charPairs.has(char)) {
      openChar = char;
      closeChar = charPairs.get(char);
      openCharCount = 1;
      blockStartIndex = i + 1;
      resultParts.push(input.substring(nonBlockStartIndex, blockStartIndex));
    }
  }
  if (blockStartIndex !== -1) {
    escapedBlocks.push(input.substring(blockStartIndex));
    resultParts.push(placeholder);
  } else {
    resultParts.push(input.substring(nonBlockStartIndex));
  }
  return new StringWithEscapedBlocks(resultParts.join(''), escapedBlocks);
}
const ESCAPE_IN_STRING_MAP = {
  ';': SEMI_IN_PLACEHOLDER,
  ',': COMMA_IN_PLACEHOLDER,
  ':': COLON_IN_PLACEHOLDER
};
function escapeInStrings(input) {
  let result = input;
  let currentQuoteChar = null;
  for (let i = 0; i < result.length; i++) {
    const char = result[i];
    if (char === '\\') {
      i++;
    } else {
      if (currentQuoteChar !== null) {
        if (char === currentQuoteChar) {
          currentQuoteChar = null;
        } else {
          const placeholder = ESCAPE_IN_STRING_MAP[char];
          if (placeholder) {
            result = `${result.substr(0, i)}${placeholder}${result.substr(i + 1)}`;
            i += placeholder.length - 1;
          }
        }
      } else if (char === "'" || char === '"') {
        currentQuoteChar = char;
      }
    }
  }
  return result;
}
function unescapeInStrings(input) {
  let result = input.replace(_cssCommaInPlaceholderReGlobal, ',');
  result = result.replace(_cssSemiInPlaceholderReGlobal, ';');
  result = result.replace(_cssColonInPlaceholderReGlobal, ':');
  return result;
}
function unescapeQuotes(str, isQuoted) {
  return !isQuoted ? str : str.replace(/((?:^|[^\\])(?:\\\\)*)\\(?=['"])/g, '$1');
}
function _combineHostContextSelectors(contextSelectors, otherSelectors, pseudoPrefix = '') {
  const hostMarker = _polyfillHostNoCombinator;
  _polyfillHostRe.lastIndex = 0;
  const otherSelectorsHasHost = _polyfillHostRe.test(otherSelectors);
  if (contextSelectors.length === 0) {
    return hostMarker + otherSelectors;
  }
  const combined = [contextSelectors.pop() || ''];
  while (contextSelectors.length > 0) {
    const length = combined.length;
    const contextSelector = contextSelectors.pop();
    for (let i = 0; i < length; i++) {
      const previousSelectors = combined[i];
      combined[length * 2 + i] = previousSelectors + ' ' + contextSelector;
      combined[length + i] = contextSelector + ' ' + previousSelectors;
      combined[i] = contextSelector + previousSelectors;
    }
  }
  return combined.map(s => otherSelectorsHasHost ? `${pseudoPrefix}${s}${otherSelectors}` : `${pseudoPrefix}${s}${hostMarker}${otherSelectors}, ${pseudoPrefix}${s} ${hostMarker}${otherSelectors}`).join(',');
}
function repeatGroups(groups, multiples) {
  const length = groups.length;
  for (let i = 1; i < multiples; i++) {
    for (let j = 0; j < length; j++) {
      groups[j + i * length] = groups[j].slice(0);
    }
  }
}

var OpKind;
(function (OpKind) {
  OpKind[OpKind["ListEnd"] = 0] = "ListEnd";
  OpKind[OpKind["Statement"] = 1] = "Statement";
  OpKind[OpKind["Variable"] = 2] = "Variable";
  OpKind[OpKind["ElementStart"] = 3] = "ElementStart";
  OpKind[OpKind["Element"] = 4] = "Element";
  OpKind[OpKind["ForeignComponent"] = 5] = "ForeignComponent";
  OpKind[OpKind["Template"] = 6] = "Template";
  OpKind[OpKind["ElementEnd"] = 7] = "ElementEnd";
  OpKind[OpKind["ContainerStart"] = 8] = "ContainerStart";
  OpKind[OpKind["Container"] = 9] = "Container";
  OpKind[OpKind["ContainerEnd"] = 10] = "ContainerEnd";
  OpKind[OpKind["DisableBindings"] = 11] = "DisableBindings";
  OpKind[OpKind["ConditionalCreate"] = 12] = "ConditionalCreate";
  OpKind[OpKind["ConditionalBranchCreate"] = 13] = "ConditionalBranchCreate";
  OpKind[OpKind["Conditional"] = 14] = "Conditional";
  OpKind[OpKind["EnableBindings"] = 15] = "EnableBindings";
  OpKind[OpKind["Text"] = 16] = "Text";
  OpKind[OpKind["Listener"] = 17] = "Listener";
  OpKind[OpKind["InterpolateText"] = 18] = "InterpolateText";
  OpKind[OpKind["Binding"] = 19] = "Binding";
  OpKind[OpKind["Property"] = 20] = "Property";
  OpKind[OpKind["StyleProp"] = 21] = "StyleProp";
  OpKind[OpKind["ClassProp"] = 22] = "ClassProp";
  OpKind[OpKind["StyleMap"] = 23] = "StyleMap";
  OpKind[OpKind["ClassMap"] = 24] = "ClassMap";
  OpKind[OpKind["Advance"] = 25] = "Advance";
  OpKind[OpKind["Pipe"] = 26] = "Pipe";
  OpKind[OpKind["Attribute"] = 27] = "Attribute";
  OpKind[OpKind["ExtractedAttribute"] = 28] = "ExtractedAttribute";
  OpKind[OpKind["Defer"] = 29] = "Defer";
  OpKind[OpKind["DeferOn"] = 30] = "DeferOn";
  OpKind[OpKind["DeferWhen"] = 31] = "DeferWhen";
  OpKind[OpKind["I18nMessage"] = 32] = "I18nMessage";
  OpKind[OpKind["DomProperty"] = 33] = "DomProperty";
  OpKind[OpKind["Namespace"] = 34] = "Namespace";
  OpKind[OpKind["ProjectionDef"] = 35] = "ProjectionDef";
  OpKind[OpKind["EnableIncrementalHydrationRuntime"] = 36] = "EnableIncrementalHydrationRuntime";
  OpKind[OpKind["Projection"] = 37] = "Projection";
  OpKind[OpKind["Content"] = 38] = "Content";
  OpKind[OpKind["RepeaterCreate"] = 39] = "RepeaterCreate";
  OpKind[OpKind["Repeater"] = 40] = "Repeater";
  OpKind[OpKind["TwoWayProperty"] = 41] = "TwoWayProperty";
  OpKind[OpKind["TwoWayListener"] = 42] = "TwoWayListener";
  OpKind[OpKind["DeclareLet"] = 43] = "DeclareLet";
  OpKind[OpKind["StoreLet"] = 44] = "StoreLet";
  OpKind[OpKind["I18nStart"] = 45] = "I18nStart";
  OpKind[OpKind["I18n"] = 46] = "I18n";
  OpKind[OpKind["I18nEnd"] = 47] = "I18nEnd";
  OpKind[OpKind["I18nExpression"] = 48] = "I18nExpression";
  OpKind[OpKind["I18nApply"] = 49] = "I18nApply";
  OpKind[OpKind["IcuStart"] = 50] = "IcuStart";
  OpKind[OpKind["IcuEnd"] = 51] = "IcuEnd";
  OpKind[OpKind["IcuPlaceholder"] = 52] = "IcuPlaceholder";
  OpKind[OpKind["I18nContext"] = 53] = "I18nContext";
  OpKind[OpKind["I18nAttributes"] = 54] = "I18nAttributes";
  OpKind[OpKind["SourceLocation"] = 55] = "SourceLocation";
  OpKind[OpKind["Animation"] = 56] = "Animation";
  OpKind[OpKind["AnimationString"] = 57] = "AnimationString";
  OpKind[OpKind["AnimationBinding"] = 58] = "AnimationBinding";
  OpKind[OpKind["AnimationListener"] = 59] = "AnimationListener";
  OpKind[OpKind["Control"] = 60] = "Control";
  OpKind[OpKind["ControlCreate"] = 61] = "ControlCreate";
})(OpKind || (OpKind = {}));
var ExpressionKind;
(function (ExpressionKind) {
  ExpressionKind[ExpressionKind["LexicalRead"] = 0] = "LexicalRead";
  ExpressionKind[ExpressionKind["Context"] = 1] = "Context";
  ExpressionKind[ExpressionKind["TrackContext"] = 2] = "TrackContext";
  ExpressionKind[ExpressionKind["ReadVariable"] = 3] = "ReadVariable";
  ExpressionKind[ExpressionKind["NextContext"] = 4] = "NextContext";
  ExpressionKind[ExpressionKind["Reference"] = 5] = "Reference";
  ExpressionKind[ExpressionKind["StoreLet"] = 6] = "StoreLet";
  ExpressionKind[ExpressionKind["ContextLetReference"] = 7] = "ContextLetReference";
  ExpressionKind[ExpressionKind["GetCurrentView"] = 8] = "GetCurrentView";
  ExpressionKind[ExpressionKind["RestoreView"] = 9] = "RestoreView";
  ExpressionKind[ExpressionKind["ResetView"] = 10] = "ResetView";
  ExpressionKind[ExpressionKind["PureFunctionExpr"] = 11] = "PureFunctionExpr";
  ExpressionKind[ExpressionKind["PureFunctionParameterExpr"] = 12] = "PureFunctionParameterExpr";
  ExpressionKind[ExpressionKind["PipeBinding"] = 13] = "PipeBinding";
  ExpressionKind[ExpressionKind["PipeBindingVariadic"] = 14] = "PipeBindingVariadic";
  ExpressionKind[ExpressionKind["SafePropertyRead"] = 15] = "SafePropertyRead";
  ExpressionKind[ExpressionKind["SafeKeyedRead"] = 16] = "SafeKeyedRead";
  ExpressionKind[ExpressionKind["SafeNavigationMigration"] = 17] = "SafeNavigationMigration";
  ExpressionKind[ExpressionKind["SafeTernaryExpr"] = 18] = "SafeTernaryExpr";
  ExpressionKind[ExpressionKind["EmptyExpr"] = 19] = "EmptyExpr";
  ExpressionKind[ExpressionKind["AssignTemporaryExpr"] = 20] = "AssignTemporaryExpr";
  ExpressionKind[ExpressionKind["ReadTemporaryExpr"] = 21] = "ReadTemporaryExpr";
  ExpressionKind[ExpressionKind["SlotLiteralExpr"] = 22] = "SlotLiteralExpr";
  ExpressionKind[ExpressionKind["ConditionalCase"] = 23] = "ConditionalCase";
  ExpressionKind[ExpressionKind["ConstCollected"] = 24] = "ConstCollected";
  ExpressionKind[ExpressionKind["TwoWayBindingSet"] = 25] = "TwoWayBindingSet";
  ExpressionKind[ExpressionKind["ForeignContent"] = 26] = "ForeignContent";
  ExpressionKind[ExpressionKind["ArrowFunction"] = 27] = "ArrowFunction";
})(ExpressionKind || (ExpressionKind = {}));
var VariableFlags;
(function (VariableFlags) {
  VariableFlags[VariableFlags["None"] = 0] = "None";
  VariableFlags[VariableFlags["AlwaysInline"] = 1] = "AlwaysInline";
})(VariableFlags || (VariableFlags = {}));
var SemanticVariableKind;
(function (SemanticVariableKind) {
  SemanticVariableKind[SemanticVariableKind["Context"] = 0] = "Context";
  SemanticVariableKind[SemanticVariableKind["Identifier"] = 1] = "Identifier";
  SemanticVariableKind[SemanticVariableKind["SavedView"] = 2] = "SavedView";
  SemanticVariableKind[SemanticVariableKind["Alias"] = 3] = "Alias";
})(SemanticVariableKind || (SemanticVariableKind = {}));
var BindingKind;
(function (BindingKind) {
  BindingKind[BindingKind["Attribute"] = 0] = "Attribute";
  BindingKind[BindingKind["ClassName"] = 1] = "ClassName";
  BindingKind[BindingKind["StyleProperty"] = 2] = "StyleProperty";
  BindingKind[BindingKind["Property"] = 3] = "Property";
  BindingKind[BindingKind["Template"] = 4] = "Template";
  BindingKind[BindingKind["I18n"] = 5] = "I18n";
  BindingKind[BindingKind["LegacyAnimation"] = 6] = "LegacyAnimation";
  BindingKind[BindingKind["TwoWayProperty"] = 7] = "TwoWayProperty";
  BindingKind[BindingKind["Animation"] = 8] = "Animation";
})(BindingKind || (BindingKind = {}));
var I18nParamResolutionTime;
(function (I18nParamResolutionTime) {
  I18nParamResolutionTime[I18nParamResolutionTime["Creation"] = 0] = "Creation";
  I18nParamResolutionTime[I18nParamResolutionTime["Postproccessing"] = 1] = "Postproccessing";
})(I18nParamResolutionTime || (I18nParamResolutionTime = {}));
var I18nExpressionFor;
(function (I18nExpressionFor) {
  I18nExpressionFor[I18nExpressionFor["I18nText"] = 0] = "I18nText";
  I18nExpressionFor[I18nExpressionFor["I18nAttribute"] = 1] = "I18nAttribute";
})(I18nExpressionFor || (I18nExpressionFor = {}));
var I18nParamValueFlags;
(function (I18nParamValueFlags) {
  I18nParamValueFlags[I18nParamValueFlags["None"] = 0] = "None";
  I18nParamValueFlags[I18nParamValueFlags["ElementTag"] = 1] = "ElementTag";
  I18nParamValueFlags[I18nParamValueFlags["TemplateTag"] = 2] = "TemplateTag";
  I18nParamValueFlags[I18nParamValueFlags["OpenTag"] = 4] = "OpenTag";
  I18nParamValueFlags[I18nParamValueFlags["CloseTag"] = 8] = "CloseTag";
  I18nParamValueFlags[I18nParamValueFlags["ExpressionIndex"] = 16] = "ExpressionIndex";
})(I18nParamValueFlags || (I18nParamValueFlags = {}));
var Namespace;
(function (Namespace) {
  Namespace[Namespace["HTML"] = 0] = "HTML";
  Namespace[Namespace["SVG"] = 1] = "SVG";
  Namespace[Namespace["Math"] = 2] = "Math";
})(Namespace || (Namespace = {}));
var DeferTriggerKind;
(function (DeferTriggerKind) {
  DeferTriggerKind[DeferTriggerKind["Idle"] = 0] = "Idle";
  DeferTriggerKind[DeferTriggerKind["Immediate"] = 1] = "Immediate";
  DeferTriggerKind[DeferTriggerKind["Timer"] = 2] = "Timer";
  DeferTriggerKind[DeferTriggerKind["Hover"] = 3] = "Hover";
  DeferTriggerKind[DeferTriggerKind["Interaction"] = 4] = "Interaction";
  DeferTriggerKind[DeferTriggerKind["Viewport"] = 5] = "Viewport";
  DeferTriggerKind[DeferTriggerKind["Never"] = 6] = "Never";
})(DeferTriggerKind || (DeferTriggerKind = {}));
var I18nContextKind;
(function (I18nContextKind) {
  I18nContextKind[I18nContextKind["RootI18n"] = 0] = "RootI18n";
  I18nContextKind[I18nContextKind["Icu"] = 1] = "Icu";
  I18nContextKind[I18nContextKind["Attr"] = 2] = "Attr";
})(I18nContextKind || (I18nContextKind = {}));
var TemplateKind;
(function (TemplateKind) {
  TemplateKind[TemplateKind["NgTemplate"] = 0] = "NgTemplate";
  TemplateKind[TemplateKind["Structural"] = 1] = "Structural";
  TemplateKind[TemplateKind["Block"] = 2] = "Block";
})(TemplateKind || (TemplateKind = {}));

class OpList {
  static nextListId = 0;
  debugListId = OpList.nextListId++;
  head = {
    kind: OpKind.ListEnd,
    next: null,
    prev: null,
    debugListId: this.debugListId
  };
  tail = {
    kind: OpKind.ListEnd,
    next: null,
    prev: null,
    debugListId: this.debugListId
  };
  constructor() {
    this.head.next = this.tail;
    this.tail.prev = this.head;
  }
  push(op) {
    if (Array.isArray(op)) {
      for (const o of op) {
        this.push(o);
      }
      return;
    }
    OpList.assertIsNotEnd(op);
    OpList.assertIsUnowned(op);
    op.debugListId = this.debugListId;
    const oldLast = this.tail.prev;
    op.prev = oldLast;
    oldLast.next = op;
    op.next = this.tail;
    this.tail.prev = op;
  }
  prepend(ops) {
    if (ops.length === 0) {
      return;
    }
    for (const op of ops) {
      OpList.assertIsNotEnd(op);
      OpList.assertIsUnowned(op);
      op.debugListId = this.debugListId;
    }
    const first = this.head.next;
    let prev = this.head;
    for (const op of ops) {
      prev.next = op;
      op.prev = prev;
      prev = op;
    }
    prev.next = first;
    first.prev = prev;
  }
  *[Symbol.iterator]() {
    let current = this.head.next;
    while (current !== this.tail) {
      OpList.assertIsOwned(current, this.debugListId);
      const next = current.next;
      yield current;
      current = next;
    }
  }
  *reversed() {
    let current = this.tail.prev;
    while (current !== this.head) {
      OpList.assertIsOwned(current, this.debugListId);
      const prev = current.prev;
      yield current;
      current = prev;
    }
  }
  static replace(oldOp, newOp) {
    OpList.assertIsNotEnd(oldOp);
    OpList.assertIsNotEnd(newOp);
    OpList.assertIsOwned(oldOp);
    OpList.assertIsUnowned(newOp);
    newOp.debugListId = oldOp.debugListId;
    if (oldOp.prev !== null) {
      oldOp.prev.next = newOp;
      newOp.prev = oldOp.prev;
    }
    if (oldOp.next !== null) {
      oldOp.next.prev = newOp;
      newOp.next = oldOp.next;
    }
    oldOp.debugListId = null;
    oldOp.prev = null;
    oldOp.next = null;
  }
  static replaceWithMany(oldOp, newOps) {
    if (newOps.length === 0) {
      OpList.remove(oldOp);
      return;
    }
    OpList.assertIsNotEnd(oldOp);
    OpList.assertIsOwned(oldOp);
    const listId = oldOp.debugListId;
    oldOp.debugListId = null;
    for (const newOp of newOps) {
      OpList.assertIsNotEnd(newOp);
      OpList.assertIsUnowned(newOp);
    }
    const {
      prev: oldPrev,
      next: oldNext
    } = oldOp;
    oldOp.prev = null;
    oldOp.next = null;
    let prev = oldPrev;
    for (const newOp of newOps) {
      OpList.assertIsUnowned(newOp);
      newOp.debugListId = listId;
      prev.next = newOp;
      newOp.prev = prev;
      newOp.next = null;
      prev = newOp;
    }
    const first = newOps[0];
    const last = prev;
    if (oldPrev !== null) {
      oldPrev.next = first;
      first.prev = oldPrev;
    }
    if (oldNext !== null) {
      oldNext.prev = last;
      last.next = oldNext;
    }
  }
  static remove(op) {
    OpList.assertIsNotEnd(op);
    OpList.assertIsOwned(op);
    op.prev.next = op.next;
    op.next.prev = op.prev;
    op.debugListId = null;
    op.prev = null;
    op.next = null;
  }
  static insertBefore(op, target) {
    if (Array.isArray(op)) {
      for (const o of op) {
        OpList.insertBefore(o, target);
      }
      return;
    }
    OpList.assertIsOwned(target);
    if (target.prev === null) {
      throw new Error(`AssertionError: illegal operation on list start`);
    }
    OpList.assertIsNotEnd(op);
    OpList.assertIsUnowned(op);
    op.debugListId = target.debugListId;
    op.prev = null;
    target.prev.next = op;
    op.prev = target.prev;
    op.next = target;
    target.prev = op;
  }
  static insertAfter(op, target) {
    OpList.assertIsOwned(target);
    if (target.next === null) {
      throw new Error(`AssertionError: illegal operation on list end`);
    }
    OpList.assertIsNotEnd(op);
    OpList.assertIsUnowned(op);
    op.debugListId = target.debugListId;
    target.next.prev = op;
    op.next = target.next;
    op.prev = target;
    target.next = op;
  }
  static assertIsUnowned(op) {
    if (op.debugListId !== null) {
      throw new Error(`AssertionError: illegal operation on owned node: ${OpKind[op.kind]}`);
    }
  }
  static assertIsOwned(op, byList) {
    if (op.debugListId === null) {
      throw new Error(`AssertionError: illegal operation on unowned node: ${OpKind[op.kind]}`);
    } else if (byList !== undefined && op.debugListId !== byList) {
      throw new Error(`AssertionError: node belongs to the wrong list (expected ${byList}, actual ${op.debugListId})`);
    }
  }
  static assertIsNotEnd(op) {
    if (op.kind === OpKind.ListEnd) {
      throw new Error(`AssertionError: illegal operation on list head or tail`);
    }
  }
}

function createStatementOp(statement) {
  return {
    kind: OpKind.Statement,
    statement,
    ...NEW_OP
  };
}
function createVariableOp(xref, variable, initializer, flags) {
  return {
    kind: OpKind.Variable,
    xref,
    variable,
    initializer,
    flags,
    ...NEW_OP
  };
}
const NEW_OP = {
  debugListId: null,
  prev: null,
  next: null
};

const ConsumesSlot = Symbol('ConsumesSlot');
const DependsOnSlotContext = Symbol('DependsOnSlotContext');
const ConsumesVarsTrait = Symbol('ConsumesVars');
const UsesVarOffset = Symbol('UsesVarOffset');
const TRAIT_CONSUMES_SLOT = {
  [ConsumesSlot]: true,
  numSlotsUsed: 1
};
const TRAIT_DEPENDS_ON_SLOT_CONTEXT = {
  [DependsOnSlotContext]: true
};
const TRAIT_CONSUMES_VARS = {
  [ConsumesVarsTrait]: true
};
function hasConsumesSlotTrait(op) {
  return op[ConsumesSlot] === true;
}
function hasDependsOnSlotContextTrait(value) {
  return value[DependsOnSlotContext] === true;
}
function hasConsumesVarsTrait(value) {
  return value[ConsumesVarsTrait] === true;
}
function hasUsesVarOffsetTrait(expr) {
  return expr[UsesVarOffset] === true;
}

function createInterpolateTextOp(xref, interpolation, sourceSpan) {
  return {
    kind: OpKind.InterpolateText,
    target: xref,
    interpolation,
    sourceSpan,
    ...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
    ...TRAIT_CONSUMES_VARS,
    ...NEW_OP
  };
}
class Interpolation {
  strings;
  expressions;
  i18nPlaceholders;
  constructor(strings, expressions, i18nPlaceholders) {
    this.strings = strings;
    this.expressions = expressions;
    this.i18nPlaceholders = i18nPlaceholders;
    if (i18nPlaceholders.length !== 0 && i18nPlaceholders.length !== expressions.length) {
      throw new Error(`Expected ${expressions.length} placeholders to match interpolation expression count, but got ${i18nPlaceholders.length}`);
    }
  }
}
function createBindingOp(target, kind, name, expression, unit, securityContext, isTextAttribute, isStructuralTemplateAttribute, templateKind, i18nMessage, sourceSpan) {
  return {
    kind: OpKind.Binding,
    bindingKind: kind,
    target,
    name,
    expression,
    unit,
    securityContext,
    isTextAttribute,
    isStructuralTemplateAttribute,
    templateKind,
    i18nContext: null,
    i18nMessage,
    sourceSpan,
    ...NEW_OP
  };
}
function createPropertyOp(target, name, expression, bindingKind, securityContext, isStructuralTemplateAttribute, templateKind, i18nContext, i18nMessage, sourceSpan) {
  return {
    kind: OpKind.Property,
    target,
    name,
    expression,
    bindingKind,
    securityContext,
    sanitizer: null,
    isStructuralTemplateAttribute,
    templateKind,
    i18nContext,
    i18nMessage,
    sourceSpan,
    ...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
    ...TRAIT_CONSUMES_VARS,
    ...NEW_OP
  };
}
function createTwoWayPropertyOp(target, name, expression, securityContext, isStructuralTemplateAttribute, templateKind, i18nContext, i18nMessage, sourceSpan) {
  return {
    kind: OpKind.TwoWayProperty,
    target,
    name,
    expression,
    securityContext,
    sanitizer: null,
    isStructuralTemplateAttribute,
    templateKind,
    i18nContext,
    i18nMessage,
    sourceSpan,
    ...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
    ...TRAIT_CONSUMES_VARS,
    ...NEW_OP
  };
}
function createStylePropOp(xref, name, expression, unit, sourceSpan) {
  return {
    kind: OpKind.StyleProp,
    target: xref,
    name,
    expression,
    unit,
    sourceSpan,
    ...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
    ...TRAIT_CONSUMES_VARS,
    ...NEW_OP
  };
}
function createClassPropOp(xref, name, expression, sourceSpan) {
  return {
    kind: OpKind.ClassProp,
    target: xref,
    name,
    expression,
    sourceSpan,
    ...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
    ...TRAIT_CONSUMES_VARS,
    ...NEW_OP
  };
}
function createStyleMapOp(xref, expression, sourceSpan) {
  return {
    kind: OpKind.StyleMap,
    target: xref,
    expression,
    sourceSpan,
    ...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
    ...TRAIT_CONSUMES_VARS,
    ...NEW_OP
  };
}
function createClassMapOp(xref, expression, sourceSpan) {
  return {
    kind: OpKind.ClassMap,
    target: xref,
    expression,
    sourceSpan,
    ...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
    ...TRAIT_CONSUMES_VARS,
    ...NEW_OP
  };
}
function createAttributeOp(target, namespace, name, expression, securityContext, isTextAttribute, isStructuralTemplateAttribute, templateKind, i18nMessage, sourceSpan) {
  return {
    kind: OpKind.Attribute,
    target,
    namespace,
    name,
    expression,
    securityContext,
    sanitizer: null,
    isTextAttribute,
    isStructuralTemplateAttribute,
    templateKind,
    i18nContext: null,
    i18nMessage,
    sourceSpan,
    ...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
    ...TRAIT_CONSUMES_VARS,
    ...NEW_OP
  };
}
function createAdvanceOp(delta, sourceSpan) {
  return {
    kind: OpKind.Advance,
    delta,
    sourceSpan,
    ...NEW_OP
  };
}
function createConditionalOp(target, test, conditions, sourceSpan) {
  return {
    kind: OpKind.Conditional,
    target,
    test,
    conditions,
    processed: null,
    sourceSpan,
    contextValue: null,
    ...NEW_OP,
    ...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
    ...TRAIT_CONSUMES_VARS
  };
}
function createRepeaterOp(repeaterCreate, targetSlot, collection, sourceSpan) {
  return {
    kind: OpKind.Repeater,
    target: repeaterCreate,
    targetSlot,
    collection,
    sourceSpan,
    ...NEW_OP,
    ...TRAIT_DEPENDS_ON_SLOT_CONTEXT
  };
}
function createAnimationBindingOp(name, target, animationKind, expression, securityContext, sourceSpan, animationBindingKind) {
  return {
    kind: OpKind.AnimationBinding,
    name,
    target,
    animationKind,
    expression,
    i18nMessage: null,
    securityContext,
    sanitizer: null,
    sourceSpan,
    animationBindingKind,
    ...NEW_OP
  };
}
function createDeferWhenOp(target, expr, modifier, sourceSpan) {
  return {
    kind: OpKind.DeferWhen,
    target,
    expr,
    modifier,
    sourceSpan,
    ...NEW_OP,
    ...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
    ...TRAIT_CONSUMES_VARS
  };
}
function createI18nExpressionOp(context, target, i18nOwner, handle, expression, icuPlaceholder, i18nPlaceholder, resolutionTime, usage, name, sourceSpan) {
  return {
    kind: OpKind.I18nExpression,
    context,
    target,
    i18nOwner,
    handle,
    expression,
    icuPlaceholder,
    i18nPlaceholder,
    resolutionTime,
    usage,
    name,
    sourceSpan,
    ...NEW_OP,
    ...TRAIT_CONSUMES_VARS,
    ...TRAIT_DEPENDS_ON_SLOT_CONTEXT
  };
}
function createI18nApplyOp(owner, handle, sourceSpan) {
  return {
    kind: OpKind.I18nApply,
    owner,
    handle,
    sourceSpan,
    ...NEW_OP
  };
}
function createStoreLetOp(target, declaredName, value, sourceSpan) {
  return {
    kind: OpKind.StoreLet,
    target,
    declaredName,
    value,
    sourceSpan,
    ...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
    ...TRAIT_CONSUMES_VARS,
    ...NEW_OP
  };
}
function createControlOp(target, sourceSpan) {
  return {
    kind: OpKind.Control,
    sourceSpan,
    target,
    ...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
    ...NEW_OP
  };
}

function isIrExpression(expr) {
  return expr instanceof ExpressionBase;
}
class ExpressionBase extends Expression {
  constructor(sourceSpan = null) {
    super(null, sourceSpan);
  }
}
class LexicalReadExpr extends ExpressionBase {
  name;
  kind = ExpressionKind.LexicalRead;
  constructor(name) {
    super();
    this.name = name;
  }
  visitExpression(visitor, context) {}
  isEquivalent(other) {
    return this.name === other.name;
  }
  isConstant() {
    return false;
  }
  transformInternalExpressions() {}
  clone() {
    return new LexicalReadExpr(this.name);
  }
}
class ReferenceExpr extends ExpressionBase {
  target;
  targetSlot;
  offset;
  kind = ExpressionKind.Reference;
  constructor(target, targetSlot, offset) {
    super();
    this.target = target;
    this.targetSlot = targetSlot;
    this.offset = offset;
  }
  visitExpression() {}
  isEquivalent(e) {
    return e instanceof ReferenceExpr && e.target === this.target;
  }
  isConstant() {
    return false;
  }
  transformInternalExpressions() {}
  clone() {
    return new ReferenceExpr(this.target, this.targetSlot, this.offset);
  }
}
class ForeignContentExpr extends ExpressionBase {
  childrenViewXref;
  childrenViewHandle;
  foreignComponentConstIndex;
  kind = ExpressionKind.ForeignContent;
  constructor(childrenViewXref, childrenViewHandle, foreignComponentConstIndex) {
    super();
    this.childrenViewXref = childrenViewXref;
    this.childrenViewHandle = childrenViewHandle;
    this.foreignComponentConstIndex = foreignComponentConstIndex;
  }
  visitExpression() {}
  isEquivalent(e) {
    return e instanceof ForeignContentExpr && e.childrenViewXref === this.childrenViewXref && e.foreignComponentConstIndex === this.foreignComponentConstIndex;
  }
  isConstant() {
    return false;
  }
  transformInternalExpressions() {}
  clone() {
    return new ForeignContentExpr(this.childrenViewXref, this.childrenViewHandle, this.foreignComponentConstIndex);
  }
}
class StoreLetExpr extends ExpressionBase {
  target;
  value;
  sourceSpan;
  kind = ExpressionKind.StoreLet;
  [ConsumesVarsTrait] = true;
  [DependsOnSlotContext] = true;
  constructor(target, value, sourceSpan) {
    super();
    this.target = target;
    this.value = value;
    this.sourceSpan = sourceSpan;
  }
  visitExpression() {}
  isEquivalent(e) {
    return e instanceof StoreLetExpr && e.target === this.target && e.value.isEquivalent(this.value);
  }
  isConstant() {
    return false;
  }
  transformInternalExpressions(transform, flags) {
    this.value = transformExpressionsInExpression(this.value, transform, flags);
  }
  clone() {
    return new StoreLetExpr(this.target, this.value, this.sourceSpan);
  }
}
class ContextLetReferenceExpr extends ExpressionBase {
  target;
  targetSlot;
  kind = ExpressionKind.ContextLetReference;
  constructor(target, targetSlot) {
    super();
    this.target = target;
    this.targetSlot = targetSlot;
  }
  visitExpression() {}
  isEquivalent(e) {
    return e instanceof ContextLetReferenceExpr && e.target === this.target;
  }
  isConstant() {
    return false;
  }
  transformInternalExpressions() {}
  clone() {
    return new ContextLetReferenceExpr(this.target, this.targetSlot);
  }
}
class ContextExpr extends ExpressionBase {
  view;
  kind = ExpressionKind.Context;
  constructor(view) {
    super();
    this.view = view;
  }
  visitExpression() {}
  isEquivalent(e) {
    return e instanceof ContextExpr && e.view === this.view;
  }
  isConstant() {
    return false;
  }
  transformInternalExpressions() {}
  clone() {
    return new ContextExpr(this.view);
  }
}
class TrackContextExpr extends ExpressionBase {
  view;
  kind = ExpressionKind.TrackContext;
  constructor(view) {
    super();
    this.view = view;
  }
  visitExpression() {}
  isEquivalent(e) {
    return e instanceof TrackContextExpr && e.view === this.view;
  }
  isConstant() {
    return false;
  }
  transformInternalExpressions() {}
  clone() {
    return new TrackContextExpr(this.view);
  }
}
class NextContextExpr extends ExpressionBase {
  kind = ExpressionKind.NextContext;
  steps = 1;
  visitExpression() {}
  isEquivalent(e) {
    return e instanceof NextContextExpr && e.steps === this.steps;
  }
  isConstant() {
    return false;
  }
  transformInternalExpressions() {}
  clone() {
    const expr = new NextContextExpr();
    expr.steps = this.steps;
    return expr;
  }
}
class GetCurrentViewExpr extends ExpressionBase {
  kind = ExpressionKind.GetCurrentView;
  constructor() {
    super();
  }
  visitExpression() {}
  isEquivalent(e) {
    return e instanceof GetCurrentViewExpr;
  }
  isConstant() {
    return false;
  }
  transformInternalExpressions() {}
  clone() {
    return new GetCurrentViewExpr();
  }
}
class RestoreViewExpr extends ExpressionBase {
  view;
  kind = ExpressionKind.RestoreView;
  constructor(view) {
    super();
    this.view = view;
  }
  visitExpression(visitor, context) {
    if (typeof this.view !== 'number') {
      this.view.visitExpression(visitor, context);
    }
  }
  isEquivalent(e) {
    if (!(e instanceof RestoreViewExpr) || typeof e.view !== typeof this.view) {
      return false;
    }
    if (typeof this.view === 'number') {
      return this.view === e.view;
    } else {
      return this.view.isEquivalent(e.view);
    }
  }
  isConstant() {
    return false;
  }
  transformInternalExpressions(transform, flags) {
    if (typeof this.view !== 'number') {
      this.view = transformExpressionsInExpression(this.view, transform, flags);
    }
  }
  clone() {
    return new RestoreViewExpr(this.view instanceof Expression ? this.view.clone() : this.view);
  }
}
class ResetViewExpr extends ExpressionBase {
  expr;
  kind = ExpressionKind.ResetView;
  constructor(expr) {
    super();
    this.expr = expr;
  }
  visitExpression(visitor, context) {
    this.expr.visitExpression(visitor, context);
  }
  isEquivalent(e) {
    return e instanceof ResetViewExpr && this.expr.isEquivalent(e.expr);
  }
  isConstant() {
    return false;
  }
  transformInternalExpressions(transform, flags) {
    this.expr = transformExpressionsInExpression(this.expr, transform, flags);
  }
  clone() {
    return new ResetViewExpr(this.expr.clone());
  }
}
class TwoWayBindingSetExpr extends ExpressionBase {
  target;
  value;
  kind = ExpressionKind.TwoWayBindingSet;
  constructor(target, value) {
    super();
    this.target = target;
    this.value = value;
  }
  visitExpression(visitor, context) {
    this.target.visitExpression(visitor, context);
    this.value.visitExpression(visitor, context);
  }
  isEquivalent(other) {
    return this.target.isEquivalent(other.target) && this.value.isEquivalent(other.value);
  }
  isConstant() {
    return false;
  }
  transformInternalExpressions(transform, flags) {
    this.target = transformExpressionsInExpression(this.target, transform, flags);
    this.value = transformExpressionsInExpression(this.value, transform, flags);
  }
  clone() {
    return new TwoWayBindingSetExpr(this.target, this.value);
  }
}
class ReadVariableExpr extends ExpressionBase {
  xref;
  kind = ExpressionKind.ReadVariable;
  name = null;
  constructor(xref) {
    super();
    this.xref = xref;
  }
  visitExpression() {}
  isEquivalent(other) {
    return other instanceof ReadVariableExpr && other.xref === this.xref;
  }
  isConstant() {
    return false;
  }
  transformInternalExpressions() {}
  clone() {
    const expr = new ReadVariableExpr(this.xref);
    expr.name = this.name;
    return expr;
  }
}
class PureFunctionExpr extends ExpressionBase {
  kind = ExpressionKind.PureFunctionExpr;
  [ConsumesVarsTrait] = true;
  [UsesVarOffset] = true;
  varOffset = null;
  body;
  args;
  fn = null;
  constructor(expression, args) {
    super();
    this.body = expression;
    this.args = args;
  }
  visitExpression(visitor, context) {
    this.body?.visitExpression(visitor, context);
    for (const arg of this.args) {
      arg.visitExpression(visitor, context);
    }
  }
  isEquivalent(other) {
    if (!(other instanceof PureFunctionExpr) || other.args.length !== this.args.length) {
      return false;
    }
    return other.body !== null && this.body !== null && other.body.isEquivalent(this.body) && other.args.every((arg, idx) => arg.isEquivalent(this.args[idx]));
  }
  isConstant() {
    return false;
  }
  transformInternalExpressions(transform, flags) {
    if (this.body !== null) {
      this.body = transformExpressionsInExpression(this.body, transform, flags | VisitorContextFlag.InChildOperation);
    } else if (this.fn !== null) {
      this.fn = transformExpressionsInExpression(this.fn, transform, flags);
    }
    for (let i = 0; i < this.args.length; i++) {
      this.args[i] = transformExpressionsInExpression(this.args[i], transform, flags);
    }
  }
  clone() {
    const expr = new PureFunctionExpr(this.body?.clone() ?? null, this.args.map(arg => arg.clone()));
    expr.fn = this.fn?.clone() ?? null;
    expr.varOffset = this.varOffset;
    return expr;
  }
}
class PureFunctionParameterExpr extends ExpressionBase {
  index;
  kind = ExpressionKind.PureFunctionParameterExpr;
  constructor(index) {
    super();
    this.index = index;
  }
  visitExpression() {}
  isEquivalent(other) {
    return other instanceof PureFunctionParameterExpr && other.index === this.index;
  }
  isConstant() {
    return true;
  }
  transformInternalExpressions() {}
  clone() {
    return new PureFunctionParameterExpr(this.index);
  }
}
class PipeBindingExpr extends ExpressionBase {
  target;
  targetSlot;
  name;
  args;
  kind = ExpressionKind.PipeBinding;
  [ConsumesVarsTrait] = true;
  [UsesVarOffset] = true;
  varOffset = null;
  constructor(target, targetSlot, name, args) {
    super();
    this.target = target;
    this.targetSlot = targetSlot;
    this.name = name;
    this.args = args;
  }
  visitExpression(visitor, context) {
    for (const arg of this.args) {
      arg.visitExpression(visitor, context);
    }
  }
  isEquivalent() {
    return false;
  }
  isConstant() {
    return false;
  }
  transformInternalExpressions(transform, flags) {
    for (let idx = 0; idx < this.args.length; idx++) {
      this.args[idx] = transformExpressionsInExpression(this.args[idx], transform, flags);
    }
  }
  clone() {
    const r = new PipeBindingExpr(this.target, this.targetSlot, this.name, this.args.map(a => a.clone()));
    r.varOffset = this.varOffset;
    return r;
  }
}
class PipeBindingVariadicExpr extends ExpressionBase {
  target;
  targetSlot;
  name;
  args;
  numArgs;
  kind = ExpressionKind.PipeBindingVariadic;
  [ConsumesVarsTrait] = true;
  [UsesVarOffset] = true;
  varOffset = null;
  constructor(target, targetSlot, name, args, numArgs) {
    super();
    this.target = target;
    this.targetSlot = targetSlot;
    this.name = name;
    this.args = args;
    this.numArgs = numArgs;
  }
  visitExpression(visitor, context) {
    this.args.visitExpression(visitor, context);
  }
  isEquivalent() {
    return false;
  }
  isConstant() {
    return false;
  }
  transformInternalExpressions(transform, flags) {
    this.args = transformExpressionsInExpression(this.args, transform, flags);
  }
  clone() {
    const r = new PipeBindingVariadicExpr(this.target, this.targetSlot, this.name, this.args.clone(), this.numArgs);
    r.varOffset = this.varOffset;
    return r;
  }
}
class SafePropertyReadExpr extends ExpressionBase {
  receiver;
  name;
  kind = ExpressionKind.SafePropertyRead;
  constructor(receiver, name) {
    super();
    this.receiver = receiver;
    this.name = name;
  }
  get index() {
    return this.name;
  }
  visitExpression(visitor, context) {
    this.receiver.visitExpression(visitor, context);
  }
  isEquivalent() {
    return false;
  }
  isConstant() {
    return false;
  }
  transformInternalExpressions(transform, flags) {
    this.receiver = transformExpressionsInExpression(this.receiver, transform, flags);
  }
  clone() {
    return new SafePropertyReadExpr(this.receiver.clone(), this.name);
  }
}
class SafeKeyedReadExpr extends ExpressionBase {
  receiver;
  index;
  kind = ExpressionKind.SafeKeyedRead;
  constructor(receiver, index, sourceSpan) {
    super(sourceSpan);
    this.receiver = receiver;
    this.index = index;
  }
  visitExpression(visitor, context) {
    this.receiver.visitExpression(visitor, context);
    this.index.visitExpression(visitor, context);
  }
  isEquivalent() {
    return false;
  }
  isConstant() {
    return false;
  }
  transformInternalExpressions(transform, flags) {
    this.receiver = transformExpressionsInExpression(this.receiver, transform, flags);
    this.index = transformExpressionsInExpression(this.index, transform, flags);
  }
  clone() {
    return new SafeKeyedReadExpr(this.receiver.clone(), this.index.clone(), this.sourceSpan);
  }
}
class SafeNavigationMigrationExpr extends ExpressionBase {
  expr;
  kind = ExpressionKind.SafeNavigationMigration;
  constructor(expr) {
    super();
    this.expr = expr;
  }
  visitExpression(visitor, context) {
    this.expr.visitExpression(visitor, context);
  }
  isEquivalent(e) {
    return e instanceof SafeNavigationMigrationExpr && this.expr.isEquivalent(e.expr);
  }
  isConstant() {
    return this.expr.isConstant();
  }
  transformInternalExpressions(transform, flags) {
    this.expr = transformExpressionsInExpression(this.expr, transform, flags | VisitorContextFlag.InSafeNavigationMigration);
  }
  clone() {
    return new SafeNavigationMigrationExpr(this.expr.clone());
  }
}
class SafeTernaryExpr extends ExpressionBase {
  guard;
  expr;
  kind = ExpressionKind.SafeTernaryExpr;
  constructor(guard, expr) {
    super();
    this.guard = guard;
    this.expr = expr;
  }
  visitExpression(visitor, context) {
    this.guard.visitExpression(visitor, context);
    this.expr.visitExpression(visitor, context);
  }
  isEquivalent() {
    return false;
  }
  isConstant() {
    return false;
  }
  transformInternalExpressions(transform, flags) {
    this.guard = transformExpressionsInExpression(this.guard, transform, flags);
    this.expr = transformExpressionsInExpression(this.expr, transform, flags);
  }
  clone() {
    return new SafeTernaryExpr(this.guard.clone(), this.expr.clone());
  }
}
class EmptyExpr extends ExpressionBase {
  kind = ExpressionKind.EmptyExpr;
  visitExpression(visitor, context) {}
  isEquivalent(e) {
    return e instanceof EmptyExpr;
  }
  isConstant() {
    return true;
  }
  clone() {
    return new EmptyExpr();
  }
  transformInternalExpressions() {}
}
class AssignTemporaryExpr extends ExpressionBase {
  expr;
  xref;
  kind = ExpressionKind.AssignTemporaryExpr;
  name = null;
  constructor(expr, xref) {
    super();
    this.expr = expr;
    this.xref = xref;
  }
  visitExpression(visitor, context) {
    this.expr.visitExpression(visitor, context);
  }
  isEquivalent() {
    return false;
  }
  isConstant() {
    return false;
  }
  transformInternalExpressions(transform, flags) {
    this.expr = transformExpressionsInExpression(this.expr, transform, flags);
  }
  clone() {
    const a = new AssignTemporaryExpr(this.expr.clone(), this.xref);
    a.name = this.name;
    return a;
  }
}
class ReadTemporaryExpr extends ExpressionBase {
  xref;
  kind = ExpressionKind.ReadTemporaryExpr;
  name = null;
  constructor(xref) {
    super();
    this.xref = xref;
  }
  visitExpression(visitor, context) {}
  isEquivalent() {
    return this.xref === this.xref;
  }
  isConstant() {
    return false;
  }
  transformInternalExpressions(transform, flags) {}
  clone() {
    const r = new ReadTemporaryExpr(this.xref);
    r.name = this.name;
    return r;
  }
}
class SlotLiteralExpr extends ExpressionBase {
  slot;
  kind = ExpressionKind.SlotLiteralExpr;
  constructor(slot) {
    super();
    this.slot = slot;
  }
  visitExpression(visitor, context) {}
  isEquivalent(e) {
    return e instanceof SlotLiteralExpr && e.slot === this.slot;
  }
  isConstant() {
    return true;
  }
  clone() {
    return new SlotLiteralExpr(this.slot);
  }
  transformInternalExpressions() {}
}
class ConditionalCaseExpr extends ExpressionBase {
  expr;
  target;
  targetSlot;
  alias;
  kind = ExpressionKind.ConditionalCase;
  constructor(expr, target, targetSlot, alias = null) {
    super();
    this.expr = expr;
    this.target = target;
    this.targetSlot = targetSlot;
    this.alias = alias;
  }
  visitExpression(visitor, context) {
    if (this.expr !== null) {
      this.expr.visitExpression(visitor, context);
    }
  }
  isEquivalent(e) {
    return e instanceof ConditionalCaseExpr && e.expr === this.expr;
  }
  isConstant() {
    return true;
  }
  clone() {
    return new ConditionalCaseExpr(this.expr, this.target, this.targetSlot);
  }
  transformInternalExpressions(transform, flags) {
    if (this.expr !== null) {
      this.expr = transformExpressionsInExpression(this.expr, transform, flags);
    }
  }
}
class ConstCollectedExpr extends ExpressionBase {
  expr;
  kind = ExpressionKind.ConstCollected;
  constructor(expr) {
    super();
    this.expr = expr;
  }
  transformInternalExpressions(transform, flags) {
    this.expr = transform(this.expr, flags);
  }
  visitExpression(visitor, context) {
    this.expr.visitExpression(visitor, context);
  }
  isEquivalent(e) {
    if (!(e instanceof ConstCollectedExpr)) {
      return false;
    }
    return this.expr.isEquivalent(e.expr);
  }
  isConstant() {
    return this.expr.isConstant();
  }
  clone() {
    return new ConstCollectedExpr(this.expr);
  }
}
class ArrowFunctionExpr extends ExpressionBase {
  parameters;
  body;
  kind = ExpressionKind.ArrowFunction;
  [ConsumesVarsTrait] = true;
  [UsesVarOffset] = true;
  contextName = CONTEXT_NAME;
  currentViewName = 'view';
  varOffset = null;
  ops;
  constructor(parameters, body) {
    super();
    this.parameters = parameters;
    this.body = body;
    this.ops = new OpList();
    this.ops.push([createStatementOp(new ReturnStatement(body, body.sourceSpan))]);
  }
  visitExpression(visitor, context) {
    for (const op of this.ops) {
      visitExpressionsInOp(op, expr => {
        expr.visitExpression(visitor, context);
      });
    }
  }
  isEquivalent(e) {
    return e instanceof ArrowFunctionExpr && e.parameters.length === this.parameters.length && e.parameters.every((param, index) => param.isEquivalent(this.parameters[index])) && e.body.isEquivalent(this.body);
  }
  isConstant() {
    return false;
  }
  transformInternalExpressions(transform, flags) {
    for (const op of this.ops) {
      transformExpressionsInOp(op, transform, flags | (VisitorContextFlag.InChildOperation | VisitorContextFlag.InArrowFunctionOperation));
    }
  }
  clone() {
    const expr = new ArrowFunctionExpr(this.parameters, this.body);
    expr.varOffset = this.varOffset;
    expr.ops = this.ops;
    return expr;
  }
}
function visitExpressionsInOp(op, visitor) {
  transformExpressionsInOp(op, (expr, flags) => {
    visitor(expr, flags);
    return expr;
  }, VisitorContextFlag.None);
}
var VisitorContextFlag;
(function (VisitorContextFlag) {
  VisitorContextFlag[VisitorContextFlag["None"] = 0] = "None";
  VisitorContextFlag[VisitorContextFlag["InChildOperation"] = 1] = "InChildOperation";
  VisitorContextFlag[VisitorContextFlag["InArrowFunctionOperation"] = 2] = "InArrowFunctionOperation";
  VisitorContextFlag[VisitorContextFlag["InSafeNavigationMigration"] = 4] = "InSafeNavigationMigration";
})(VisitorContextFlag || (VisitorContextFlag = {}));
function transformExpressionsInInterpolation(interpolation, transform, flags) {
  for (let i = 0; i < interpolation.expressions.length; i++) {
    interpolation.expressions[i] = transformExpressionsInExpression(interpolation.expressions[i], transform, flags);
  }
}
function transformExpressionsInOp(op, transform, flags) {
  switch (op.kind) {
    case OpKind.StyleProp:
    case OpKind.StyleMap:
    case OpKind.ClassProp:
    case OpKind.ClassMap:
    case OpKind.AnimationString:
    case OpKind.AnimationBinding:
    case OpKind.Binding:
      if (op.expression instanceof Interpolation) {
        transformExpressionsInInterpolation(op.expression, transform, flags);
      } else {
        op.expression = transformExpressionsInExpression(op.expression, transform, flags);
      }
      break;
    case OpKind.Property:
    case OpKind.DomProperty:
    case OpKind.Attribute:
      if (op.expression instanceof Interpolation) {
        transformExpressionsInInterpolation(op.expression, transform, flags);
      } else {
        op.expression = transformExpressionsInExpression(op.expression, transform, flags);
      }
      op.sanitizer = op.sanitizer && transformExpressionsInExpression(op.sanitizer, transform, flags);
      break;
    case OpKind.TwoWayProperty:
      op.expression = transformExpressionsInExpression(op.expression, transform, flags);
      op.sanitizer = op.sanitizer && transformExpressionsInExpression(op.sanitizer, transform, flags);
      break;
    case OpKind.I18nExpression:
      op.expression = transformExpressionsInExpression(op.expression, transform, flags);
      break;
    case OpKind.InterpolateText:
      transformExpressionsInInterpolation(op.interpolation, transform, flags);
      break;
    case OpKind.Statement:
      transformExpressionsInStatement(op.statement, transform, flags);
      break;
    case OpKind.Variable:
      op.initializer = transformExpressionsInExpression(op.initializer, transform, flags);
      break;
    case OpKind.Conditional:
      for (const condition of op.conditions) {
        if (condition.expr === null) {
          continue;
        }
        condition.expr = transformExpressionsInExpression(condition.expr, transform, flags);
      }
      if (op.processed !== null) {
        op.processed = transformExpressionsInExpression(op.processed, transform, flags);
      }
      if (op.contextValue !== null) {
        op.contextValue = transformExpressionsInExpression(op.contextValue, transform, flags);
      }
      break;
    case OpKind.Animation:
    case OpKind.AnimationListener:
    case OpKind.Listener:
    case OpKind.TwoWayListener:
      for (const innerOp of op.handlerOps) {
        transformExpressionsInOp(innerOp, transform, flags | VisitorContextFlag.InChildOperation);
      }
      break;
    case OpKind.ExtractedAttribute:
      op.expression = op.expression && transformExpressionsInExpression(op.expression, transform, flags);
      op.trustedValueFn = op.trustedValueFn && transformExpressionsInExpression(op.trustedValueFn, transform, flags);
      break;
    case OpKind.RepeaterCreate:
      if (op.trackByOps === null) {
        op.track = transformExpressionsInExpression(op.track, transform, flags);
      } else {
        for (const innerOp of op.trackByOps) {
          transformExpressionsInOp(innerOp, transform, flags | VisitorContextFlag.InChildOperation);
        }
      }
      if (op.trackByFn !== null) {
        op.trackByFn = transformExpressionsInExpression(op.trackByFn, transform, flags);
      }
      break;
    case OpKind.Repeater:
      op.collection = transformExpressionsInExpression(op.collection, transform, flags);
      break;
    case OpKind.Defer:
      if (op.loadingConfig !== null) {
        op.loadingConfig = transformExpressionsInExpression(op.loadingConfig, transform, flags);
      }
      if (op.placeholderConfig !== null) {
        op.placeholderConfig = transformExpressionsInExpression(op.placeholderConfig, transform, flags);
      }
      if (op.resolverFn !== null) {
        op.resolverFn = transformExpressionsInExpression(op.resolverFn, transform, flags);
      }
      break;
    case OpKind.I18nMessage:
      for (const [placeholder, expr] of op.params) {
        op.params.set(placeholder, transformExpressionsInExpression(expr, transform, flags));
      }
      for (const [placeholder, expr] of op.postprocessingParams) {
        op.postprocessingParams.set(placeholder, transformExpressionsInExpression(expr, transform, flags));
      }
      break;
    case OpKind.DeferWhen:
      op.expr = transformExpressionsInExpression(op.expr, transform, flags);
      break;
    case OpKind.StoreLet:
      op.value = transformExpressionsInExpression(op.value, transform, flags);
      break;
    case OpKind.ForeignComponent:
      for (const [key, expr] of op.props) {
        op.props.set(key, transformExpressionsInExpression(expr, transform, flags));
      }
      break;
    case OpKind.Advance:
    case OpKind.Container:
    case OpKind.ContainerEnd:
    case OpKind.ContainerStart:
    case OpKind.DeferOn:
    case OpKind.DisableBindings:
    case OpKind.Element:
    case OpKind.ElementEnd:
    case OpKind.ElementStart:
    case OpKind.EnableBindings:
    case OpKind.I18n:
    case OpKind.I18nApply:
    case OpKind.I18nContext:
    case OpKind.I18nEnd:
    case OpKind.I18nStart:
    case OpKind.IcuEnd:
    case OpKind.IcuStart:
    case OpKind.Namespace:
    case OpKind.Pipe:
    case OpKind.Projection:
    case OpKind.ProjectionDef:
    case OpKind.EnableIncrementalHydrationRuntime:
    case OpKind.Template:
    case OpKind.Content:
    case OpKind.Text:
    case OpKind.I18nAttributes:
    case OpKind.IcuPlaceholder:
    case OpKind.DeclareLet:
    case OpKind.SourceLocation:
    case OpKind.ConditionalCreate:
    case OpKind.ConditionalBranchCreate:
    case OpKind.Control:
    case OpKind.ControlCreate:
      break;
    default:
      throw new Error(`AssertionError: transformExpressionsInOp doesn't handle ${OpKind[op.kind]}`);
  }
}
function transformExpressionsInExpression(expr, transform, flags) {
  if (expr instanceof ExpressionBase) {
    expr.transformInternalExpressions(transform, flags);
  } else if (expr instanceof BinaryOperatorExpr) {
    expr.lhs = transformExpressionsInExpression(expr.lhs, transform, flags);
    expr.rhs = transformExpressionsInExpression(expr.rhs, transform, flags);
  } else if (expr instanceof UnaryOperatorExpr) {
    expr.expr = transformExpressionsInExpression(expr.expr, transform, flags);
  } else if (expr instanceof ReadPropExpr) {
    expr.receiver = transformExpressionsInExpression(expr.receiver, transform, flags);
  } else if (expr instanceof ReadKeyExpr) {
    expr.receiver = transformExpressionsInExpression(expr.receiver, transform, flags);
    expr.index = transformExpressionsInExpression(expr.index, transform, flags);
  } else if (expr instanceof InvokeFunctionExpr) {
    expr.fn = transformExpressionsInExpression(expr.fn, transform, flags);
    for (let i = 0; i < expr.args.length; i++) {
      expr.args[i] = transformExpressionsInExpression(expr.args[i], transform, flags);
    }
  } else if (expr instanceof LiteralArrayExpr) {
    for (let i = 0; i < expr.entries.length; i++) {
      expr.entries[i] = transformExpressionsInExpression(expr.entries[i], transform, flags);
    }
  } else if (expr instanceof LiteralMapExpr) {
    for (const entry of expr.entries) {
      if (entry instanceof LiteralMapSpreadAssignment) {
        entry.expression = transformExpressionsInExpression(entry.expression, transform, flags);
      } else {
        entry.value = transformExpressionsInExpression(entry.value, transform, flags);
      }
    }
  } else if (expr instanceof ConditionalExpr) {
    expr.condition = transformExpressionsInExpression(expr.condition, transform, flags);
    expr.trueCase = transformExpressionsInExpression(expr.trueCase, transform, flags);
    if (expr.falseCase !== null) {
      expr.falseCase = transformExpressionsInExpression(expr.falseCase, transform, flags);
    }
  } else if (expr instanceof TypeofExpr) {
    expr.expr = transformExpressionsInExpression(expr.expr, transform, flags);
  } else if (expr instanceof VoidExpr) {
    expr.expr = transformExpressionsInExpression(expr.expr, transform, flags);
  } else if (expr instanceof LocalizedString) {
    for (let i = 0; i < expr.expressions.length; i++) {
      expr.expressions[i] = transformExpressionsInExpression(expr.expressions[i], transform, flags);
    }
  } else if (expr instanceof NotExpr) {
    expr.condition = transformExpressionsInExpression(expr.condition, transform, flags);
  } else if (expr instanceof TaggedTemplateLiteralExpr) {
    expr.tag = transformExpressionsInExpression(expr.tag, transform, flags);
    expr.template.expressions = expr.template.expressions.map(e => transformExpressionsInExpression(e, transform, flags));
  } else if (expr instanceof ArrowFunctionExpr$1) {
    if (Array.isArray(expr.body)) {
      for (let i = 0; i < expr.body.length; i++) {
        transformExpressionsInStatement(expr.body[i], transform, flags | VisitorContextFlag.InChildOperation);
      }
    } else {
      expr.body = transformExpressionsInExpression(expr.body, transform, flags | VisitorContextFlag.InChildOperation);
    }
  } else if (expr instanceof WrappedNodeExpr) ; else if (expr instanceof TemplateLiteralExpr) {
    for (let i = 0; i < expr.expressions.length; i++) {
      expr.expressions[i] = transformExpressionsInExpression(expr.expressions[i], transform, flags);
    }
  } else if (expr instanceof ParenthesizedExpr) {
    expr.expr = transformExpressionsInExpression(expr.expr, transform, flags);
  } else if (expr instanceof SpreadElementExpr) {
    expr.expression = transformExpressionsInExpression(expr.expression, transform, flags);
  } else if (expr instanceof ReadVarExpr || expr instanceof ExternalExpr || expr instanceof LiteralExpr || expr instanceof RegularExpressionLiteralExpr) ; else {
    throw new Error(`Unhandled expression kind: ${expr.constructor.name}`);
  }
  return transform(expr, flags);
}
function transformExpressionsInStatement(stmt, transform, flags) {
  if (stmt instanceof ExpressionStatement) {
    stmt.expr = transformExpressionsInExpression(stmt.expr, transform, flags);
  } else if (stmt instanceof ReturnStatement) {
    stmt.value = transformExpressionsInExpression(stmt.value, transform, flags);
  } else if (stmt instanceof DeclareVarStmt) {
    if (stmt.value !== undefined) {
      stmt.value = transformExpressionsInExpression(stmt.value, transform, flags);
    }
  } else if (stmt instanceof IfStmt) {
    stmt.condition = transformExpressionsInExpression(stmt.condition, transform, flags);
    for (const caseStatement of stmt.trueCase) {
      transformExpressionsInStatement(caseStatement, transform, flags);
    }
    for (const caseStatement of stmt.falseCase) {
      transformExpressionsInStatement(caseStatement, transform, flags);
    }
  } else {
    throw new Error(`Unhandled statement kind: ${stmt.constructor.name}`);
  }
}
function isStringLiteral(expr) {
  return expr instanceof LiteralExpr && typeof expr.value === 'string';
}

class SlotHandle {
  slot = null;
}

const elementContainerOpKinds = new Set([OpKind.Element, OpKind.ElementStart, OpKind.Container, OpKind.ContainerStart, OpKind.Template, OpKind.RepeaterCreate, OpKind.ConditionalCreate, OpKind.ConditionalBranchCreate]);
function isElementOrContainerOp(op) {
  return elementContainerOpKinds.has(op.kind);
}
function createElementStartOp(tag, xref, namespace, i18nPlaceholder, startSourceSpan, wholeSourceSpan) {
  return {
    kind: OpKind.ElementStart,
    xref,
    tag,
    handle: new SlotHandle(),
    attributes: null,
    localRefs: [],
    nonBindable: false,
    namespace,
    i18nPlaceholder,
    startSourceSpan,
    wholeSourceSpan,
    ...TRAIT_CONSUMES_SLOT,
    ...NEW_OP
  };
}
function createForeignComponentOp(xref, constIndex, props, sourceSpan) {
  return {
    kind: OpKind.ForeignComponent,
    xref,
    handle: new SlotHandle(),
    constIndex,
    props,
    sourceSpan,
    ...TRAIT_CONSUMES_SLOT,
    ...NEW_OP
  };
}
function createContentOp(target, view, propertyName, startSourceSpan, sourceSpan) {
  return {
    kind: OpKind.Content,
    target,
    propertyName,
    view,
    startSourceSpan,
    sourceSpan,
    ...NEW_OP
  };
}
function createTemplateOp(xref, templateKind, tag, functionNameSuffix, namespace, i18nPlaceholder, startSourceSpan, wholeSourceSpan) {
  return {
    kind: OpKind.Template,
    xref,
    templateKind,
    attributes: null,
    tag,
    handle: new SlotHandle(),
    functionNameSuffix,
    decls: null,
    vars: null,
    localRefs: [],
    nonBindable: false,
    namespace,
    i18nPlaceholder,
    startSourceSpan,
    wholeSourceSpan,
    ...TRAIT_CONSUMES_SLOT,
    ...NEW_OP
  };
}
function createConditionalCreateOp(xref, templateKind, tag, functionNameSuffix, namespace, i18nPlaceholder, startSourceSpan, wholeSourceSpan) {
  return {
    kind: OpKind.ConditionalCreate,
    xref,
    templateKind,
    attributes: null,
    tag,
    handle: new SlotHandle(),
    functionNameSuffix,
    decls: null,
    vars: null,
    localRefs: [],
    nonBindable: false,
    namespace,
    i18nPlaceholder,
    startSourceSpan,
    wholeSourceSpan,
    ...TRAIT_CONSUMES_SLOT,
    ...NEW_OP
  };
}
function createConditionalBranchCreateOp(xref, templateKind, tag, functionNameSuffix, namespace, i18nPlaceholder, startSourceSpan, wholeSourceSpan) {
  return {
    kind: OpKind.ConditionalBranchCreate,
    xref,
    templateKind,
    attributes: null,
    tag,
    handle: new SlotHandle(),
    functionNameSuffix,
    decls: null,
    vars: null,
    localRefs: [],
    nonBindable: false,
    namespace,
    i18nPlaceholder,
    startSourceSpan,
    wholeSourceSpan,
    ...TRAIT_CONSUMES_SLOT,
    ...NEW_OP
  };
}
function createRepeaterCreateOp(primaryView, emptyView, tag, track, varNames, emptyTag, i18nPlaceholder, emptyI18nPlaceholder, startSourceSpan, wholeSourceSpan) {
  return {
    kind: OpKind.RepeaterCreate,
    attributes: null,
    xref: primaryView,
    handle: new SlotHandle(),
    emptyView,
    track,
    trackByFn: null,
    trackByOps: null,
    tag,
    emptyTag,
    emptyAttributes: null,
    functionNameSuffix: 'For',
    namespace: Namespace.HTML,
    nonBindable: false,
    localRefs: [],
    decls: null,
    vars: null,
    varNames,
    usesComponentInstance: false,
    i18nPlaceholder,
    emptyI18nPlaceholder,
    startSourceSpan,
    wholeSourceSpan,
    ...TRAIT_CONSUMES_SLOT,
    ...NEW_OP,
    ...TRAIT_CONSUMES_VARS,
    numSlotsUsed: emptyView === null ? 2 : 3
  };
}
function createElementEndOp(xref, sourceSpan) {
  return {
    kind: OpKind.ElementEnd,
    xref,
    sourceSpan,
    ...NEW_OP
  };
}
function createDisableBindingsOp(xref) {
  return {
    kind: OpKind.DisableBindings,
    xref,
    ...NEW_OP
  };
}
function createEnableBindingsOp(xref) {
  return {
    kind: OpKind.EnableBindings,
    xref,
    ...NEW_OP
  };
}
function createTextOp(xref, initialValue, icuPlaceholder, sourceSpan) {
  return {
    kind: OpKind.Text,
    xref,
    handle: new SlotHandle(),
    initialValue,
    icuPlaceholder,
    sourceSpan,
    ...TRAIT_CONSUMES_SLOT,
    ...NEW_OP
  };
}
function createAnimationStringOp(name, target, animationKind, expression, securityContext, sourceSpan) {
  return {
    kind: OpKind.AnimationString,
    name,
    target,
    animationKind,
    expression,
    i18nMessage: null,
    securityContext,
    sanitizer: null,
    sourceSpan,
    ...NEW_OP
  };
}
function createAnimationOp(name, target, animationKind, callbackOps, securityContext, sourceSpan) {
  const handlerOps = new OpList();
  handlerOps.push(callbackOps);
  return {
    kind: OpKind.Animation,
    name,
    target,
    animationKind,
    handlerOps,
    handlerFnName: null,
    i18nMessage: null,
    securityContext,
    sanitizer: null,
    sourceSpan,
    ...NEW_OP
  };
}
function createListenerOp(target, targetSlot, name, tag, handlerOps, legacyAnimationPhase, eventTarget, hostListener, sourceSpan) {
  const handlerList = new OpList();
  handlerList.push(handlerOps);
  return {
    kind: OpKind.Listener,
    target,
    targetSlot,
    tag,
    hostListener,
    name,
    handlerOps: handlerList,
    handlerFnName: null,
    consumesDollarEvent: false,
    isLegacyAnimationListener: legacyAnimationPhase !== null,
    legacyAnimationPhase: legacyAnimationPhase,
    eventTarget,
    sourceSpan,
    ...NEW_OP
  };
}
function createAnimationListenerOp(target, targetSlot, name, tag, handlerOps, animationKind, eventTarget, hostListener, sourceSpan) {
  const handlerList = new OpList();
  handlerList.push(handlerOps);
  return {
    kind: OpKind.AnimationListener,
    target,
    targetSlot,
    tag,
    hostListener,
    name,
    animationKind,
    handlerOps: handlerList,
    handlerFnName: null,
    consumesDollarEvent: false,
    eventTarget,
    sourceSpan,
    ...NEW_OP
  };
}
function createTwoWayListenerOp(target, targetSlot, name, tag, handlerOps, sourceSpan) {
  const handlerList = new OpList();
  handlerList.push(handlerOps);
  return {
    kind: OpKind.TwoWayListener,
    target,
    targetSlot,
    tag,
    name,
    handlerOps: handlerList,
    handlerFnName: null,
    sourceSpan,
    ...NEW_OP
  };
}
function createPipeOp(xref, slot, name) {
  return {
    kind: OpKind.Pipe,
    xref,
    handle: slot,
    name,
    ...NEW_OP,
    ...TRAIT_CONSUMES_SLOT
  };
}
function createNamespaceOp(namespace) {
  return {
    kind: OpKind.Namespace,
    active: namespace,
    ...NEW_OP
  };
}
function createProjectionDefOp(def) {
  return {
    kind: OpKind.ProjectionDef,
    def,
    ...NEW_OP
  };
}
function createEnableIncrementalHydrationRuntimeOp(sourceSpan) {
  return {
    kind: OpKind.EnableIncrementalHydrationRuntime,
    sourceSpan,
    ...NEW_OP
  };
}
function createProjectionOp(xref, selector, i18nPlaceholder, fallbackView, sourceSpan) {
  return {
    kind: OpKind.Projection,
    xref,
    handle: new SlotHandle(),
    selector,
    i18nPlaceholder,
    fallbackView,
    projectionSlotIndex: 0,
    attributes: null,
    localRefs: [],
    sourceSpan,
    ...NEW_OP,
    ...TRAIT_CONSUMES_SLOT,
    numSlotsUsed: fallbackView === null ? 1 : 2
  };
}
function createExtractedAttributeOp(target, bindingKind, namespace, name, expression, i18nContext, i18nMessage, securityContext) {
  return {
    kind: OpKind.ExtractedAttribute,
    target,
    bindingKind,
    namespace,
    name,
    expression,
    i18nContext,
    i18nMessage,
    securityContext,
    trustedValueFn: null,
    ...NEW_OP
  };
}
function createDeferOp(xref, main, mainSlot, ownResolverFn, resolverFn, sourceSpan) {
  return {
    kind: OpKind.Defer,
    xref,
    handle: new SlotHandle(),
    mainView: main,
    mainSlot,
    loadingView: null,
    loadingSlot: null,
    loadingConfig: null,
    loadingMinimumTime: null,
    loadingAfterTime: null,
    placeholderView: null,
    placeholderSlot: null,
    placeholderConfig: null,
    placeholderMinimumTime: null,
    errorView: null,
    errorSlot: null,
    ownResolverFn,
    resolverFn,
    flags: null,
    sourceSpan,
    ...NEW_OP,
    ...TRAIT_CONSUMES_SLOT,
    numSlotsUsed: 2
  };
}
function createDeferOnOp(defer, trigger, modifier, sourceSpan) {
  return {
    kind: OpKind.DeferOn,
    defer,
    trigger,
    modifier,
    sourceSpan,
    ...NEW_OP
  };
}
function createDeclareLetOp(xref, declaredName, sourceSpan) {
  return {
    kind: OpKind.DeclareLet,
    xref,
    declaredName,
    sourceSpan,
    handle: new SlotHandle(),
    ...TRAIT_CONSUMES_SLOT,
    ...NEW_OP
  };
}
function createI18nMessageOp(xref, i18nContext, i18nBlock, message, messagePlaceholder, params, postprocessingParams, needsPostprocessing) {
  return {
    kind: OpKind.I18nMessage,
    xref,
    i18nContext,
    i18nBlock,
    message,
    messagePlaceholder,
    params,
    postprocessingParams,
    needsPostprocessing,
    subMessages: [],
    ...NEW_OP
  };
}
function createI18nStartOp(xref, message, root, sourceSpan) {
  return {
    kind: OpKind.I18nStart,
    xref,
    handle: new SlotHandle(),
    root: root ?? xref,
    message,
    messageIndex: null,
    subTemplateIndex: null,
    context: null,
    sourceSpan,
    ...NEW_OP,
    ...TRAIT_CONSUMES_SLOT
  };
}
function createI18nEndOp(xref, sourceSpan) {
  return {
    kind: OpKind.I18nEnd,
    xref,
    sourceSpan,
    ...NEW_OP
  };
}
function createIcuStartOp(xref, message, messagePlaceholder, sourceSpan) {
  return {
    kind: OpKind.IcuStart,
    xref,
    message,
    messagePlaceholder,
    context: null,
    sourceSpan,
    ...NEW_OP
  };
}
function createIcuEndOp(xref) {
  return {
    kind: OpKind.IcuEnd,
    xref,
    ...NEW_OP
  };
}
function createIcuPlaceholderOp(xref, name, strings) {
  return {
    kind: OpKind.IcuPlaceholder,
    xref,
    name,
    strings,
    expressionPlaceholders: [],
    ...NEW_OP
  };
}
function createI18nContextOp(contextKind, xref, i18nBlock, message, sourceSpan) {
  if (i18nBlock === null && contextKind !== I18nContextKind.Attr) {
    throw new Error('AssertionError: i18nBlock must be provided for non-attribute contexts.');
  }
  return {
    kind: OpKind.I18nContext,
    contextKind,
    xref,
    i18nBlock,
    message,
    sourceSpan,
    params: new Map(),
    postprocessingParams: new Map(),
    ...NEW_OP
  };
}
function createI18nAttributesOp(xref, handle, target) {
  return {
    kind: OpKind.I18nAttributes,
    xref,
    handle,
    target,
    i18nAttributesConfig: null,
    ...NEW_OP,
    ...TRAIT_CONSUMES_SLOT
  };
}
function createSourceLocationOp(templatePath, locations) {
  return {
    kind: OpKind.SourceLocation,
    templatePath,
    locations,
    ...NEW_OP
  };
}
function createControlCreateOp(sourceSpan) {
  return {
    kind: OpKind.ControlCreate,
    sourceSpan,
    ...NEW_OP
  };
}

function createDomPropertyOp(name, expression, bindingKind, i18nContext, securityContext, sourceSpan) {
  return {
    kind: OpKind.DomProperty,
    name,
    expression,
    bindingKind,
    i18nContext,
    securityContext,
    sanitizer: null,
    sourceSpan,
    ...TRAIT_CONSUMES_VARS,
    ...NEW_OP
  };
}

const CTX_REF = 'CTX_REF_MARKER';

var CompilationJobKind;
(function (CompilationJobKind) {
  CompilationJobKind[CompilationJobKind["Tmpl"] = 0] = "Tmpl";
  CompilationJobKind[CompilationJobKind["Host"] = 1] = "Host";
  CompilationJobKind[CompilationJobKind["Both"] = 2] = "Both";
})(CompilationJobKind || (CompilationJobKind = {}));
var TemplateCompilationMode;
(function (TemplateCompilationMode) {
  TemplateCompilationMode[TemplateCompilationMode["Full"] = 0] = "Full";
  TemplateCompilationMode[TemplateCompilationMode["DomOnly"] = 1] = "DomOnly";
})(TemplateCompilationMode || (TemplateCompilationMode = {}));
class CompilationJob {
  componentName;
  pool;
  mode;
  legacyOptionalChaining;
  constructor(componentName, pool, mode, legacyOptionalChaining) {
    this.componentName = componentName;
    this.pool = pool;
    this.mode = mode;
    this.legacyOptionalChaining = legacyOptionalChaining;
  }
  kind = CompilationJobKind.Both;
  allocateXrefId() {
    return this.nextXrefId++;
  }
  nextXrefId = 0;
}
class ComponentCompilationJob extends CompilationJob {
  relativeContextFilePath;
  i18nUseExternalIds;
  deferMeta;
  allDeferrableDepsFn;
  relativeTemplatePath;
  enableDebugLocations;
  foreignImports;
  foreignMatcher;
  constructor(componentName, pool, mode, relativeContextFilePath, i18nUseExternalIds, deferMeta, allDeferrableDepsFn, relativeTemplatePath, enableDebugLocations, legacyOptionalChaining, foreignImports) {
    super(componentName, pool, mode, legacyOptionalChaining);
    this.relativeContextFilePath = relativeContextFilePath;
    this.i18nUseExternalIds = i18nUseExternalIds;
    this.deferMeta = deferMeta;
    this.allDeferrableDepsFn = allDeferrableDepsFn;
    this.relativeTemplatePath = relativeTemplatePath;
    this.enableDebugLocations = enableDebugLocations;
    this.foreignImports = foreignImports;
    this.root = new ViewCompilationUnit(this, this.allocateXrefId(), null);
    this.views.set(this.root.xref, this.root);
    if (foreignImports && foreignImports.length > 0) {
      const registry = new Map();
      for (const meta of foreignImports) {
        registry.set(meta.name, [meta]);
      }
      this.foreignMatcher = new SelectorlessMatcher(registry);
    } else {
      this.foreignMatcher = null;
    }
  }
  getForeignComponent(element) {
    if (this.foreignMatcher === null) {
      return null;
    }
    const matches = this.foreignMatcher.match(element.name);
    return matches.length > 0 ? matches[0] : null;
  }
  kind = CompilationJobKind.Tmpl;
  fnSuffix = 'Template';
  root;
  views = new Map();
  contentSelectors = null;
  allocateView(parent) {
    const view = new ViewCompilationUnit(this, this.allocateXrefId(), parent);
    this.views.set(view.xref, view);
    return view;
  }
  get units() {
    return this.views.values();
  }
  addConst(newConst, initializers) {
    for (let idx = 0; idx < this.consts.length; idx++) {
      if (this.consts[idx].isEquivalent(newConst)) {
        return idx;
      }
    }
    const idx = this.consts.length;
    this.consts.push(newConst);
    if (initializers) {
      this.constsInitializers.push(...initializers);
    }
    return idx;
  }
  consts = [];
  constsInitializers = [];
}
class CompilationUnit {
  xref;
  constructor(xref) {
    this.xref = xref;
  }
  create = new OpList();
  update = new OpList();
  functions = new Set();
  fnName = null;
  vars = null;
  *ops() {
    for (const expr of this.functions) {
      for (const op of expr.ops) {
        yield op;
      }
    }
    for (const op of this.create) {
      yield op;
      if (op.kind === OpKind.Listener || op.kind === OpKind.Animation || op.kind === OpKind.AnimationListener || op.kind === OpKind.TwoWayListener) {
        for (const listenerOp of op.handlerOps) {
          yield listenerOp;
        }
      } else if (op.kind === OpKind.RepeaterCreate && op.trackByOps !== null) {
        for (const trackOp of op.trackByOps) {
          yield trackOp;
        }
      }
    }
    for (const op of this.update) {
      yield op;
    }
  }
}
class ViewCompilationUnit extends CompilationUnit {
  job;
  parent;
  constructor(job, xref, parent) {
    super(xref);
    this.job = job;
    this.parent = parent;
  }
  contextVariables = new Map();
  aliases = new Set();
  decls = null;
}
class HostBindingCompilationJob extends CompilationJob {
  constructor(componentName, pool, mode, legacyOptionalChaining) {
    super(componentName, pool, mode, legacyOptionalChaining);
    this.root = new HostBindingCompilationUnit(this);
  }
  kind = CompilationJobKind.Host;
  fnSuffix = 'HostBindings';
  root;
  get units() {
    return [this.root];
  }
}
class HostBindingCompilationUnit extends CompilationUnit {
  job;
  constructor(job) {
    super(0);
    this.job = job;
  }
  attributes = null;
}

function deleteAnyCasts(job) {
  for (const unit of job.units) {
    for (const op of unit.ops()) {
      transformExpressionsInOp(op, removeAnys, VisitorContextFlag.None);
    }
  }
}
function removeAnys(e) {
  if (e instanceof InvokeFunctionExpr && e.fn instanceof LexicalReadExpr && e.fn.name === '$any') {
    if (e.args.length !== 1) {
      throw new Error('The $any builtin function expects exactly one argument.');
    }
    return e.args[0];
  }
  return e;
}

function applyI18nExpressions(job) {
  const i18nContexts = new Map();
  for (const unit of job.units) {
    for (const op of unit.create) {
      if (op.kind === OpKind.I18nContext) {
        i18nContexts.set(op.xref, op);
      }
    }
  }
  for (const unit of job.units) {
    for (const op of unit.update) {
      if (op.kind === OpKind.I18nExpression && needsApplication(i18nContexts, op)) {
        OpList.insertAfter(createI18nApplyOp(op.i18nOwner, op.handle, null), op);
      }
    }
  }
}
function needsApplication(i18nContexts, op) {
  if (op.next?.kind !== OpKind.I18nExpression) {
    return true;
  }
  const context = i18nContexts.get(op.context);
  const nextContext = i18nContexts.get(op.next.context);
  if (context === undefined) {
    throw new Error("AssertionError: expected an I18nContextOp to exist for the I18nExpressionOp's context");
  }
  if (nextContext === undefined) {
    throw new Error("AssertionError: expected an I18nContextOp to exist for the next I18nExpressionOp's context");
  }
  if (context.i18nBlock !== null) {
    if (context.i18nBlock !== nextContext.i18nBlock) {
      return true;
    }
    return false;
  }
  if (op.i18nOwner !== op.next.i18nOwner) {
    return true;
  }
  return false;
}

function assignI18nSlotDependencies(job) {
  for (const unit of job.units) {
    let updateOp = unit.update.head;
    let i18nExpressionsInProgress = [];
    let state = null;
    for (const createOp of unit.create) {
      if (createOp.kind === OpKind.I18nStart) {
        state = {
          blockXref: createOp.xref,
          lastSlotConsumer: createOp.xref
        };
      } else if (createOp.kind === OpKind.I18nEnd) {
        for (const op of i18nExpressionsInProgress) {
          op.target = state.lastSlotConsumer;
          OpList.insertBefore(op, updateOp);
        }
        i18nExpressionsInProgress.length = 0;
        state = null;
      }
      if (hasConsumesSlotTrait(createOp)) {
        if (state !== null) {
          state.lastSlotConsumer = createOp.xref;
        }
        while (true) {
          if (updateOp.next === null) {
            break;
          }
          if (state !== null && updateOp.kind === OpKind.I18nExpression && updateOp.usage === I18nExpressionFor.I18nText && updateOp.i18nOwner === state.blockXref) {
            const opToRemove = updateOp;
            updateOp = updateOp.next;
            OpList.remove(opToRemove);
            i18nExpressionsInProgress.push(opToRemove);
            continue;
          }
          let hasDifferentTarget = false;
          if (hasDependsOnSlotContextTrait(updateOp) && updateOp.target !== createOp.xref) {
            hasDifferentTarget = true;
          } else if (updateOp.kind === OpKind.Statement || updateOp.kind === OpKind.Variable) {
            visitExpressionsInOp(updateOp, expr => {
              if (!hasDifferentTarget && hasDependsOnSlotContextTrait(expr) && expr.target !== createOp.xref) {
                hasDifferentTarget = true;
              }
            });
          }
          if (hasDifferentTarget) {
            break;
          }
          updateOp = updateOp.next;
        }
      }
    }
  }
}

function attachSourceLocations(job) {
  if (!job.enableDebugLocations || job.relativeTemplatePath === null) {
    return;
  }
  for (const unit of job.units) {
    const locations = [];
    for (const op of unit.create) {
      if (op.kind === OpKind.ElementStart || op.kind === OpKind.Element) {
        const start = op.startSourceSpan.start;
        locations.push({
          targetSlot: op.handle,
          offset: start.offset,
          line: start.line,
          column: start.col
        });
      }
    }
    if (locations.length > 0) {
      unit.create.push(createSourceLocationOp(job.relativeTemplatePath, locations));
    }
  }
}

function createOpXrefMap(unit) {
  const map = new Map();
  for (const op of unit.create) {
    if (!hasConsumesSlotTrait(op)) {
      continue;
    }
    map.set(op.xref, op);
    if (op.kind === OpKind.RepeaterCreate && op.emptyView !== null) {
      map.set(op.emptyView, op);
    }
  }
  return map;
}

function extractAttributes(job) {
  for (const unit of job.units) {
    const elements = createOpXrefMap(unit);
    for (const op of unit.ops()) {
      switch (op.kind) {
        case OpKind.Attribute:
          extractAttributeOp(unit, op, elements);
          break;
        case OpKind.Property:
          if (op.bindingKind !== BindingKind.LegacyAnimation && op.bindingKind !== BindingKind.Animation) {
            let bindingKind;
            if (op.i18nMessage !== null && op.templateKind === null) {
              bindingKind = BindingKind.I18n;
            } else if (op.isStructuralTemplateAttribute) {
              bindingKind = BindingKind.Template;
            } else {
              bindingKind = BindingKind.Property;
            }
            OpList.insertBefore(createExtractedAttributeOp(op.target, bindingKind, null, op.name, null, null, null, op.securityContext), lookupElement$3(elements, op.target));
          }
          break;
        case OpKind.TwoWayProperty:
          OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.TwoWayProperty, null, op.name, null, null, null, op.securityContext), lookupElement$3(elements, op.target));
          break;
        case OpKind.StyleProp:
        case OpKind.ClassProp:
          if (op.expression instanceof EmptyExpr) {
            OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.Property, null, op.name, null, null, null, SecurityContext.STYLE), lookupElement$3(elements, op.target));
          }
          break;
        case OpKind.Listener:
          if (!op.isLegacyAnimationListener) {
            const extractedAttributeOp = createExtractedAttributeOp(op.target, BindingKind.Property, null, op.name, null, null, null, SecurityContext.NONE);
            if (job.kind === CompilationJobKind.Host) {
              break;
            } else {
              OpList.insertBefore(extractedAttributeOp, lookupElement$3(elements, op.target));
            }
          }
          break;
        case OpKind.TwoWayListener:
          if (job.kind !== CompilationJobKind.Host) {
            const extractedAttributeOp = createExtractedAttributeOp(op.target, BindingKind.Property, null, op.name, null, null, null, SecurityContext.NONE);
            OpList.insertBefore(extractedAttributeOp, lookupElement$3(elements, op.target));
          }
          break;
      }
    }
  }
}
function lookupElement$3(elements, xref) {
  const el = elements.get(xref);
  if (el === undefined) {
    throw new Error('All attributes should have an element-like target.');
  }
  return el;
}
function extractAttributeOp(unit, op, elements) {
  if (op.expression instanceof Interpolation) {
    return;
  }
  if (op.isTextAttribute) {
    const extractedAttributeOp = createExtractedAttributeOp(op.target, op.isStructuralTemplateAttribute ? BindingKind.Template : BindingKind.Attribute, op.namespace, op.name, op.expression, op.i18nContext, op.i18nMessage, op.securityContext);
    if (unit.job.kind === CompilationJobKind.Host) {
      unit.create.push(extractedAttributeOp);
    } else {
      const ownerOp = lookupElement$3(elements, op.target);
      OpList.insertBefore(extractedAttributeOp, ownerOp);
    }
    OpList.remove(op);
  }
}

const ARIA_PREFIX = 'aria-';
function isAriaAttribute(name) {
  return name.startsWith(ARIA_PREFIX) && name.length > ARIA_PREFIX.length;
}

function lookupElement$2(elements, xref) {
  const el = elements.get(xref);
  if (el === undefined) {
    throw new Error('All attributes should have an element-like target.');
  }
  return el;
}
function specializeBindings(job) {
  const elements = new Map();
  for (const unit of job.units) {
    for (const op of unit.create) {
      if (!isElementOrContainerOp(op)) {
        continue;
      }
      elements.set(op.xref, op);
    }
  }
  for (const unit of job.units) {
    for (const op of unit.ops()) {
      if (op.kind !== OpKind.Binding) {
        continue;
      }
      switch (op.bindingKind) {
        case BindingKind.Attribute:
          if (op.name === 'ngNonBindable') {
            OpList.remove(op);
            const target = lookupElement$2(elements, op.target);
            target.nonBindable = true;
          } else if (op.name.startsWith('animate.')) {
            OpList.replace(op, createAnimationBindingOp(op.name, op.target, op.name === 'animate.enter' ? "enter" : "leave", op.expression, op.securityContext, op.sourceSpan, 0));
          } else {
            const [namespace, name] = splitNsName(op.name);
            OpList.replace(op, createAttributeOp(op.target, namespace, name, op.expression, op.securityContext, op.isTextAttribute, op.isStructuralTemplateAttribute, op.templateKind, op.i18nMessage, op.sourceSpan));
          }
          break;
        case BindingKind.Animation:
          OpList.replace(op, createAnimationBindingOp(op.name, op.target, op.name === 'animate.enter' ? "enter" : "leave", op.expression, op.securityContext, op.sourceSpan, 1));
          break;
        case BindingKind.Property:
        case BindingKind.LegacyAnimation:
          if (job.mode === TemplateCompilationMode.DomOnly && isAriaAttribute(op.name)) {
            OpList.replace(op, createAttributeOp(op.target, null, op.name, op.expression, op.securityContext, false, op.isStructuralTemplateAttribute, op.templateKind, op.i18nMessage, op.sourceSpan));
          } else if (job.kind === CompilationJobKind.Host) {
            OpList.replace(op, createDomPropertyOp(op.name, op.expression, op.bindingKind, op.i18nContext, op.securityContext, op.sourceSpan));
          } else {
            OpList.replace(op, createPropertyOp(op.target, op.name, op.expression, op.bindingKind, op.securityContext, op.isStructuralTemplateAttribute, op.templateKind, op.i18nContext, op.i18nMessage, op.sourceSpan));
          }
          break;
        case BindingKind.TwoWayProperty:
          if (!(op.expression instanceof Expression)) {
            throw new Error(`Expected value of two-way property binding "${op.name}" to be an expression`);
          }
          OpList.replace(op, createTwoWayPropertyOp(op.target, op.name, op.expression, op.securityContext, op.isStructuralTemplateAttribute, op.templateKind, op.i18nContext, op.i18nMessage, op.sourceSpan));
          break;
        case BindingKind.I18n:
        case BindingKind.ClassName:
        case BindingKind.StyleProperty:
          throw new Error(`Unhandled binding of kind ${BindingKind[op.bindingKind]}`);
      }
    }
  }
}

const CHAIN_COMPATIBILITY = new Map([[Identifiers.ariaProperty, Identifiers.ariaProperty], [Identifiers.attribute, Identifiers.attribute], [Identifiers.classProp, Identifiers.classProp], [Identifiers.element, Identifiers.element], [Identifiers.elementContainer, Identifiers.elementContainer], [Identifiers.elementContainerEnd, Identifiers.elementContainerEnd], [Identifiers.elementContainerStart, Identifiers.elementContainerStart], [Identifiers.elementEnd, Identifiers.elementEnd], [Identifiers.elementStart, Identifiers.elementStart], [Identifiers.domProperty, Identifiers.domProperty], [Identifiers.i18nExp, Identifiers.i18nExp], [Identifiers.listener, Identifiers.listener], [Identifiers.listener, Identifiers.listener], [Identifiers.property, Identifiers.property], [Identifiers.styleProp, Identifiers.styleProp], [Identifiers.syntheticHostListener, Identifiers.syntheticHostListener], [Identifiers.syntheticHostProperty, Identifiers.syntheticHostProperty], [Identifiers.templateCreate, Identifiers.templateCreate], [Identifiers.twoWayProperty, Identifiers.twoWayProperty], [Identifiers.twoWayListener, Identifiers.twoWayListener], [Identifiers.declareLet, Identifiers.declareLet], [Identifiers.conditionalCreate, Identifiers.conditionalBranchCreate], [Identifiers.conditionalBranchCreate, Identifiers.conditionalBranchCreate], [Identifiers.domElement, Identifiers.domElement], [Identifiers.domElementStart, Identifiers.domElementStart], [Identifiers.domElementEnd, Identifiers.domElementEnd], [Identifiers.domElementContainer, Identifiers.domElementContainer], [Identifiers.domElementContainerStart, Identifiers.domElementContainerStart], [Identifiers.domElementContainerEnd, Identifiers.domElementContainerEnd], [Identifiers.domListener, Identifiers.domListener], [Identifiers.domTemplate, Identifiers.domTemplate], [Identifiers.animationEnter, Identifiers.animationEnter], [Identifiers.animationLeave, Identifiers.animationLeave], [Identifiers.animationEnterListener, Identifiers.animationEnterListener], [Identifiers.animationLeaveListener, Identifiers.animationLeaveListener]]);
const MAX_CHAIN_LENGTH = 256;
function chain(job) {
  for (const unit of job.units) {
    chainOperationsInList(unit.create);
    chainOperationsInList(unit.update);
  }
}
function chainOperationsInList(opList) {
  let chain = null;
  for (const op of opList) {
    if (op.kind !== OpKind.Statement || !(op.statement instanceof ExpressionStatement)) {
      chain = null;
      continue;
    }
    if (!(op.statement.expr instanceof InvokeFunctionExpr) || !(op.statement.expr.fn instanceof ExternalExpr)) {
      chain = null;
      continue;
    }
    const instruction = op.statement.expr.fn.value;
    if (!CHAIN_COMPATIBILITY.has(instruction)) {
      chain = null;
      continue;
    }
    if (chain !== null && CHAIN_COMPATIBILITY.get(chain.instruction) === instruction && chain.length < MAX_CHAIN_LENGTH) {
      const expression = chain.expression.callFn(op.statement.expr.args, op.statement.expr.sourceSpan, op.statement.expr.pure);
      chain.expression = expression;
      chain.op.statement = expression.toStmt();
      chain.length++;
      OpList.remove(op);
    } else {
      chain = {
        op,
        instruction,
        expression: op.statement.expr,
        length: 1
      };
    }
  }
}

function collapseSingletonInterpolations(job) {
  for (const unit of job.units) {
    for (const op of unit.update) {
      const eligibleOpKind = op.kind === OpKind.Attribute || op.kind === OpKind.StyleProp || op.kind == OpKind.StyleMap || op.kind === OpKind.ClassMap;
      if (eligibleOpKind && op.expression instanceof Interpolation && op.expression.strings.length === 2 && op.expression.strings.every(s => s === '')) {
        op.expression = op.expression.expressions[0];
      }
    }
  }
}

function generateConditionalExpressions(job) {
  for (const unit of job.units) {
    for (const op of unit.ops()) {
      if (op.kind !== OpKind.Conditional) {
        continue;
      }
      let test;
      const defaultCase = op.conditions.findIndex(cond => cond.expr === null);
      if (defaultCase >= 0) {
        const slot = op.conditions.splice(defaultCase, 1)[0].targetSlot;
        test = new SlotLiteralExpr(slot);
      } else {
        test = literal(-1);
      }
      let tmp = op.test == null ? null : new AssignTemporaryExpr(op.test, job.allocateXrefId());
      let caseExpressionTemporaryXref = null;
      for (let i = op.conditions.length - 1; i >= 0; i--) {
        let conditionalCase = op.conditions[i];
        if (conditionalCase.expr === null) {
          continue;
        }
        if (tmp !== null) {
          const useTmp = i === 0 ? tmp : new ReadTemporaryExpr(tmp.xref);
          conditionalCase.expr = new BinaryOperatorExpr(BinaryOperator.Identical, useTmp, conditionalCase.expr);
        } else if (conditionalCase.alias !== null) {
          caseExpressionTemporaryXref ??= job.allocateXrefId();
          conditionalCase.expr = new AssignTemporaryExpr(conditionalCase.expr, caseExpressionTemporaryXref);
          op.contextValue = new ReadTemporaryExpr(caseExpressionTemporaryXref);
        }
        test = new ConditionalExpr(conditionalCase.expr, new SlotLiteralExpr(conditionalCase.targetSlot), test);
      }
      op.processed = test;
      op.conditions = [];
    }
  }
}

const BINARY_OPERATORS = new Map([['&&', BinaryOperator.And], ['>', BinaryOperator.Bigger], ['>=', BinaryOperator.BiggerEquals], ['|', BinaryOperator.BitwiseOr], ['&', BinaryOperator.BitwiseAnd], ['/', BinaryOperator.Divide], ['=', BinaryOperator.Assign], ['==', BinaryOperator.Equals], ['===', BinaryOperator.Identical], ['<', BinaryOperator.Lower], ['<=', BinaryOperator.LowerEquals], ['-', BinaryOperator.Minus], ['%', BinaryOperator.Modulo], ['**', BinaryOperator.Exponentiation], ['*', BinaryOperator.Multiply], ['!=', BinaryOperator.NotEquals], ['!==', BinaryOperator.NotIdentical], ['??', BinaryOperator.NullishCoalesce], ['||', BinaryOperator.Or], ['+', BinaryOperator.Plus], ['in', BinaryOperator.In], ['instanceof', BinaryOperator.InstanceOf], ['+=', BinaryOperator.AdditionAssignment], ['-=', BinaryOperator.SubtractionAssignment], ['*=', BinaryOperator.MultiplicationAssignment], ['/=', BinaryOperator.DivisionAssignment], ['%=', BinaryOperator.RemainderAssignment], ['**=', BinaryOperator.ExponentiationAssignment], ['&&=', BinaryOperator.AndAssignment], ['||=', BinaryOperator.OrAssignment], ['??=', BinaryOperator.NullishCoalesceAssignment]]);
function namespaceForKey(namespacePrefixKey) {
  const NAMESPACES = new Map([['svg', Namespace.SVG], ['math', Namespace.Math]]);
  if (namespacePrefixKey === null) {
    return Namespace.HTML;
  }
  return NAMESPACES.get(namespacePrefixKey) ?? Namespace.HTML;
}
function keyForNamespace(namespace) {
  const NAMESPACES = new Map([['svg', Namespace.SVG], ['math', Namespace.Math]]);
  for (const [k, n] of NAMESPACES.entries()) {
    if (n === namespace) {
      return k;
    }
  }
  return null;
}
function prefixWithNamespace(strippedTag, namespace) {
  if (namespace === Namespace.HTML) {
    return strippedTag;
  }
  return `:${keyForNamespace(namespace)}:${strippedTag}`;
}
function literalOrArrayLiteral(value) {
  if (Array.isArray(value)) {
    return literalArr(value.map(literalOrArrayLiteral));
  }
  return literal(value);
}

function collectElementConsts(job) {
  const allElementAttributes = new Map();
  for (const unit of job.units) {
    for (const op of unit.create) {
      if (op.kind === OpKind.ExtractedAttribute) {
        const attributes = allElementAttributes.get(op.target) || new ElementAttributes();
        allElementAttributes.set(op.target, attributes);
        attributes.add(op.bindingKind, op.name, op.expression, op.namespace, op.trustedValueFn);
        OpList.remove(op);
      }
    }
  }
  if (job instanceof ComponentCompilationJob) {
    for (const unit of job.units) {
      for (const op of unit.create) {
        if (op.kind == OpKind.Projection) {
          const attributes = allElementAttributes.get(op.xref);
          if (attributes !== undefined) {
            const attrArray = serializeAttributes(attributes);
            if (attrArray.entries.length > 0) {
              op.attributes = job.pool.getConstLiteral(attrArray, true);
            }
          }
        } else if (isElementOrContainerOp(op)) {
          op.attributes = getConstIndex(job, allElementAttributes, op.xref);
          if (op.kind === OpKind.RepeaterCreate && op.emptyView !== null) {
            op.emptyAttributes = getConstIndex(job, allElementAttributes, op.emptyView);
          }
        }
      }
    }
  } else if (job instanceof HostBindingCompilationJob) {
    for (const [xref, attributes] of allElementAttributes.entries()) {
      if (xref !== job.root.xref) {
        throw new Error(`An attribute would be const collected into the host binding's template function, but is not associated with the root xref.`);
      }
      const attrArray = serializeAttributes(attributes);
      if (attrArray.entries.length > 0) {
        job.root.attributes = attrArray;
      }
    }
  }
}
function getConstIndex(job, allElementAttributes, xref) {
  const attributes = allElementAttributes.get(xref);
  if (attributes !== undefined) {
    const attrArray = serializeAttributes(attributes);
    if (attrArray.entries.length > 0) {
      return job.addConst(attrArray);
    }
  }
  return null;
}
const FLYWEIGHT_ARRAY = Object.freeze([]);
class ElementAttributes {
  known = new Map();
  byKind = new Map();
  propertyBindings = null;
  projectAs = null;
  get attributes() {
    return this.byKind.get(BindingKind.Attribute) ?? FLYWEIGHT_ARRAY;
  }
  get classes() {
    return this.byKind.get(BindingKind.ClassName) ?? FLYWEIGHT_ARRAY;
  }
  get styles() {
    return this.byKind.get(BindingKind.StyleProperty) ?? FLYWEIGHT_ARRAY;
  }
  get bindings() {
    return this.propertyBindings ?? FLYWEIGHT_ARRAY;
  }
  get template() {
    return this.byKind.get(BindingKind.Template) ?? FLYWEIGHT_ARRAY;
  }
  get i18n() {
    return this.byKind.get(BindingKind.I18n) ?? FLYWEIGHT_ARRAY;
  }
  isKnown(kind, name) {
    const nameToValue = this.known.get(kind) ?? new Set();
    this.known.set(kind, nameToValue);
    if (nameToValue.has(name)) {
      return true;
    }
    nameToValue.add(name);
    return false;
  }
  add(kind, name, value, namespace, trustedValueFn) {
    const allowDuplicates = kind === BindingKind.Attribute || kind === BindingKind.ClassName || kind === BindingKind.StyleProperty;
    if (!allowDuplicates && this.isKnown(kind, name)) {
      return;
    }
    if (name === 'ngProjectAs') {
      if (value === null || !(value instanceof LiteralExpr) || value.value == null || typeof value.value?.toString() !== 'string') {
        throw Error('ngProjectAs must have a string literal value');
      }
      this.projectAs = value.value.toString();
    }
    const array = this.arrayFor(kind);
    array.push(...getAttributeNameLiterals(namespace, name));
    if (kind === BindingKind.Attribute || kind === BindingKind.StyleProperty) {
      if (value === null) {
        throw Error('Attribute, i18n attribute, & style element attributes must have a value');
      }
      if (trustedValueFn !== null && isStringLiteral(value)) {
        array.push(taggedTemplate(trustedValueFn, new TemplateLiteralExpr([new TemplateLiteralElementExpr(value.value)], []), undefined, value.sourceSpan));
      } else {
        array.push(value);
      }
    }
  }
  arrayFor(kind) {
    if (kind === BindingKind.Property || kind === BindingKind.TwoWayProperty) {
      this.propertyBindings ??= [];
      return this.propertyBindings;
    } else {
      if (!this.byKind.has(kind)) {
        this.byKind.set(kind, []);
      }
      return this.byKind.get(kind);
    }
  }
}
function getAttributeNameLiterals(namespace, name) {
  const nameLiteral = literal(name);
  if (namespace) {
    return [literal(0), literal(namespace), nameLiteral];
  }
  return [nameLiteral];
}
function serializeAttributes({
  attributes,
  bindings,
  classes,
  i18n,
  projectAs,
  styles,
  template
}) {
  const attrArray = [...attributes];
  if (projectAs !== null) {
    const parsedR3Selector = parseSelectorToR3Selector(projectAs)[0];
    attrArray.push(literal(5), literalOrArrayLiteral(parsedR3Selector));
  }
  if (classes.length > 0) {
    attrArray.push(literal(1), ...classes);
  }
  if (styles.length > 0) {
    attrArray.push(literal(2), ...styles);
  }
  if (bindings.length > 0) {
    attrArray.push(literal(3), ...bindings);
  }
  if (template.length > 0) {
    attrArray.push(literal(4), ...template);
  }
  if (i18n.length > 0) {
    attrArray.push(literal(6), ...i18n);
  }
  return literalArr(attrArray);
}

const ELIGIBLE_CONTROL_PROPERTIES = new Map([['formField', new Set([OpKind.Property])], ['formControl', new Set([OpKind.Property])], ['formControlName', new Set([OpKind.Property, OpKind.Attribute])], ['ngModel', new Set([OpKind.Attribute, OpKind.Property, OpKind.TwoWayProperty])]]);
function specializeControlProperties(job) {
  for (const unit of job.units) {
    processView(unit);
  }
}
function processView(view) {
  for (const op of view.update) {
    if (op.kind !== OpKind.Property && op.kind !== OpKind.TwoWayProperty && op.kind !== OpKind.Attribute) {
      continue;
    }
    const eligibleOps = ELIGIBLE_CONTROL_PROPERTIES.get(op.name);
    if (eligibleOps !== undefined && eligibleOps.has(op.kind)) {
      addControlInstruction(view, op);
    }
  }
}
const CONTROL_OP_CREATE_KINDS = new Set([OpKind.Container, OpKind.ContainerStart, OpKind.ContainerEnd, OpKind.Element, OpKind.ElementStart, OpKind.ElementEnd, OpKind.Template]);
function isRelevantCreateOp(createOp) {
  return CONTROL_OP_CREATE_KINDS.has(createOp.kind);
}
function findCreateInstruction(view, target) {
  let lastFoundOp = null;
  for (const createOp of view.create) {
    if (!isRelevantCreateOp(createOp) || createOp.xref !== target) {
      continue;
    }
    lastFoundOp = createOp;
  }
  return lastFoundOp;
}
function addControlInstruction(view, propertyOp) {
  const targetCreateOp = findCreateInstruction(view, propertyOp.target);
  if (targetCreateOp === null) {
    return;
  }
  const controlCreateOp = createControlCreateOp(propertyOp.sourceSpan);
  OpList.insertAfter(controlCreateOp, targetCreateOp);
  OpList.insertAfter(createControlOp(propertyOp.target, propertyOp.sourceSpan), propertyOp);
}

function lookupElement$1(elements, xref) {
  const el = elements.get(xref);
  if (el === undefined) {
    throw new Error('All attributes should have an element-like target.');
  }
  return el;
}
function convertAnimations(job) {
  const elements = new Map();
  for (const unit of job.units) {
    for (const op of unit.create) {
      if (!isElementOrContainerOp(op)) {
        continue;
      }
      elements.set(op.xref, op);
    }
  }
  for (const unit of job.units) {
    for (const op of unit.ops()) {
      if (op.kind === OpKind.AnimationBinding) {
        const createAnimationOp = getAnimationOp(op);
        if (job.kind === CompilationJobKind.Host) {
          unit.create.push(createAnimationOp);
        } else {
          OpList.insertAfter(createAnimationOp, lookupElement$1(elements, op.target));
        }
        OpList.remove(op);
      }
    }
  }
}
function getAnimationOp(op) {
  if (op.animationBindingKind === 0) {
    return createAnimationStringOp(op.name, op.target, op.name === 'animate.enter' ? "enter" : "leave", op.expression, op.securityContext, op.sourceSpan);
  } else {
    const expression = op.expression;
    return createAnimationOp(op.name, op.target, op.name === 'animate.enter' ? "enter" : "leave", [createStatementOp(new ReturnStatement(expression, expression.sourceSpan))], op.securityContext, op.sourceSpan);
  }
}

function convertI18nBindings(job) {
  const i18nAttributesByElem = new Map();
  for (const unit of job.units) {
    for (const op of unit.create) {
      if (op.kind === OpKind.I18nAttributes) {
        i18nAttributesByElem.set(op.target, op);
      }
    }
    for (const op of unit.update) {
      switch (op.kind) {
        case OpKind.Property:
        case OpKind.Attribute:
          if (op.i18nContext === null) {
            continue;
          }
          if (!(op.expression instanceof Interpolation)) {
            continue;
          }
          const i18nAttributesForElem = i18nAttributesByElem.get(op.target);
          if (i18nAttributesForElem === undefined) {
            throw new Error('AssertionError: An i18n attribute binding instruction requires the owning element to have an I18nAttributes create instruction');
          }
          if (i18nAttributesForElem.target !== op.target) {
            throw new Error('AssertionError: Expected i18nAttributes target element to match binding target element');
          }
          const ops = [];
          for (let i = 0; i < op.expression.expressions.length; i++) {
            const expr = op.expression.expressions[i];
            if (op.expression.i18nPlaceholders.length !== op.expression.expressions.length) {
              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`);
            }
            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));
          }
          OpList.replaceWithMany(op, ops);
          break;
      }
    }
  }
}

function createI18nContexts(job) {
  const attrContextByMessage = new Map();
  for (const unit of job.units) {
    for (const op of unit.ops()) {
      switch (op.kind) {
        case OpKind.Binding:
        case OpKind.Property:
        case OpKind.Attribute:
        case OpKind.ExtractedAttribute:
          if (op.i18nMessage === null) {
            continue;
          }
          if (!attrContextByMessage.has(op.i18nMessage)) {
            const i18nContext = createI18nContextOp(I18nContextKind.Attr, job.allocateXrefId(), null, op.i18nMessage, null);
            unit.create.push(i18nContext);
            attrContextByMessage.set(op.i18nMessage, i18nContext.xref);
          }
          op.i18nContext = attrContextByMessage.get(op.i18nMessage);
          break;
      }
    }
  }
  const blockContextByI18nBlock = new Map();
  for (const unit of job.units) {
    for (const op of unit.create) {
      switch (op.kind) {
        case OpKind.I18nStart:
          if (op.xref === op.root) {
            const contextOp = createI18nContextOp(I18nContextKind.RootI18n, job.allocateXrefId(), op.xref, op.message, null);
            unit.create.push(contextOp);
            op.context = contextOp.xref;
            blockContextByI18nBlock.set(op.xref, contextOp);
          }
          break;
      }
    }
  }
  for (const unit of job.units) {
    for (const op of unit.create) {
      if (op.kind === OpKind.I18nStart && op.xref !== op.root) {
        const rootContext = blockContextByI18nBlock.get(op.root);
        if (rootContext === undefined) {
          throw Error('AssertionError: Root i18n block i18n context should have been created.');
        }
        op.context = rootContext.xref;
        blockContextByI18nBlock.set(op.xref, rootContext);
      }
    }
  }
  let currentI18nOp = null;
  for (const unit of job.units) {
    for (const op of unit.create) {
      switch (op.kind) {
        case OpKind.I18nStart:
          currentI18nOp = op;
          break;
        case OpKind.I18nEnd:
          currentI18nOp = null;
          break;
        case OpKind.IcuStart:
          if (currentI18nOp === null) {
            throw Error('AssertionError: Unexpected ICU outside of an i18n block.');
          }
          if (op.message.id !== currentI18nOp.message.id) {
            const contextOp = createI18nContextOp(I18nContextKind.Icu, job.allocateXrefId(), currentI18nOp.root, op.message, null);
            unit.create.push(contextOp);
            op.context = contextOp.xref;
          } else {
            op.context = currentI18nOp.context;
            blockContextByI18nBlock.get(currentI18nOp.xref).contextKind = I18nContextKind.Icu;
          }
          break;
      }
    }
  }
}

function deduplicateTextBindings(job) {
  const seen = new Map();
  for (const unit of job.units) {
    for (const op of unit.update.reversed()) {
      if (op.kind === OpKind.Binding && op.isTextAttribute) {
        const seenForElement = seen.get(op.target) || new Set();
        if (seenForElement.has(op.name) && (op.name === 'style' || op.name === 'class')) {
          OpList.remove(op);
        }
        seenForElement.add(op.name);
        seen.set(op.target, seenForElement);
      }
    }
  }
}

function configureDeferInstructions(job) {
  for (const unit of job.units) {
    for (const op of unit.create) {
      if (op.kind !== OpKind.Defer) {
        continue;
      }
      if (op.placeholderMinimumTime !== null) {
        op.placeholderConfig = new ConstCollectedExpr(literalOrArrayLiteral([op.placeholderMinimumTime]));
      }
      if (op.loadingMinimumTime !== null || op.loadingAfterTime !== null) {
        op.loadingConfig = new ConstCollectedExpr(literalOrArrayLiteral([op.loadingMinimumTime, op.loadingAfterTime]));
      }
    }
  }
}

function insertIncrementalHydrationRuntime(job) {
  for (const unit of job.units) {
    for (const op of unit.create) {
      if (op.kind === OpKind.Defer && op.flags !== null && (op.flags & 1) !== 0) {
        OpList.insertBefore(createEnableIncrementalHydrationRuntimeOp(op.sourceSpan), op);
        break;
      }
    }
  }
}

function resolveDeferTargetNames(job) {
  const scopes = new Map();
  function getScopeForView(view) {
    if (scopes.has(view.xref)) {
      return scopes.get(view.xref);
    }
    const scope = new Scope$2();
    for (const op of view.create) {
      if (!isElementOrContainerOp(op) || op.localRefs === null) {
        continue;
      }
      if (!Array.isArray(op.localRefs)) {
        throw new Error('LocalRefs were already processed, but were needed to resolve defer targets.');
      }
      for (const ref of op.localRefs) {
        if (ref.target !== '') {
          continue;
        }
        scope.targets.set(ref.name, {
          xref: op.xref,
          slot: op.handle
        });
      }
    }
    scopes.set(view.xref, scope);
    return scope;
  }
  function resolveTrigger(deferOwnerView, op, placeholderView) {
    const triggerKind = op.trigger.kind;
    switch (triggerKind) {
      case DeferTriggerKind.Idle:
      case DeferTriggerKind.Never:
      case DeferTriggerKind.Immediate:
      case DeferTriggerKind.Timer:
        return;
      case DeferTriggerKind.Hover:
      case DeferTriggerKind.Interaction:
      case DeferTriggerKind.Viewport:
        if (op.trigger.targetName === null) {
          if (placeholderView === null) {
            throw new Error('defer on trigger with no target name must have a placeholder block');
          }
          const placeholder = job.views.get(placeholderView);
          if (placeholder == undefined) {
            throw new Error('AssertionError: could not find placeholder view for defer on trigger');
          }
          for (const placeholderOp of placeholder.create) {
            if (hasConsumesSlotTrait(placeholderOp) && (isElementOrContainerOp(placeholderOp) || placeholderOp.kind === OpKind.Projection)) {
              op.trigger.targetXref = placeholderOp.xref;
              op.trigger.targetView = placeholderView;
              op.trigger.targetSlotViewSteps = -1;
              op.trigger.targetSlot = placeholderOp.handle;
              return;
            }
          }
          return;
        }
        let view = placeholderView !== null ? job.views.get(placeholderView) : deferOwnerView;
        let step = placeholderView !== null ? -1 : 0;
        while (view !== null) {
          const scope = getScopeForView(view);
          if (scope.targets.has(op.trigger.targetName)) {
            const {
              xref,
              slot
            } = scope.targets.get(op.trigger.targetName);
            op.trigger.targetXref = xref;
            op.trigger.targetView = view.xref;
            op.trigger.targetSlotViewSteps = step;
            op.trigger.targetSlot = slot;
            return;
          }
          view = view.parent !== null ? job.views.get(view.parent) : null;
          step++;
        }
        break;
      default:
        {
          const unhandledTriggerKind = triggerKind;
          throw new Error(`Trigger kind ${unhandledTriggerKind} not handled`);
        }
    }
  }
  for (const unit of job.units) {
    const defers = new Map();
    for (const op of unit.create) {
      switch (op.kind) {
        case OpKind.Defer:
          defers.set(op.xref, op);
          break;
        case OpKind.DeferOn:
          const deferOp = defers.get(op.defer);
          resolveTrigger(unit, op, op.modifier === "hydrate" ? deferOp.mainView : deferOp.placeholderView);
          break;
      }
    }
  }
}
let Scope$2 = class Scope {
  targets = new Map();
};

const REPLACEMENTS = new Map([[OpKind.ElementEnd, [OpKind.ElementStart, OpKind.Element]], [OpKind.ContainerEnd, [OpKind.ContainerStart, OpKind.Container]], [OpKind.I18nEnd, [OpKind.I18nStart, OpKind.I18n]]]);
const IGNORED_OP_KINDS = new Set([OpKind.Pipe]);
function collapseEmptyInstructions(job) {
  for (const unit of job.units) {
    for (const op of unit.create) {
      const opReplacements = REPLACEMENTS.get(op.kind);
      if (opReplacements === undefined) {
        continue;
      }
      const [startKind, mergedKind] = opReplacements;
      let prevOp = op.prev;
      while (prevOp !== null && IGNORED_OP_KINDS.has(prevOp.kind)) {
        prevOp = prevOp.prev;
      }
      if (prevOp !== null && prevOp.kind === startKind) {
        prevOp.kind = mergedKind;
        OpList.remove(op);
      }
    }
  }
}

function expandSafeReads(job) {
  for (const unit of job.units) {
    for (const op of unit.ops()) {
      transformExpressionsInOp(op, (e, flags) => safeTransform(e, {
        job
      }, flags), VisitorContextFlag.None);
      transformExpressionsInOp(op, ternaryTransform, VisitorContextFlag.None);
    }
  }
}
function needsTemporaryInSafeAccess(e) {
  if (e instanceof UnaryOperatorExpr) {
    return needsTemporaryInSafeAccess(e.expr);
  } else if (e instanceof BinaryOperatorExpr) {
    return needsTemporaryInSafeAccess(e.lhs) || needsTemporaryInSafeAccess(e.rhs);
  } else if (e instanceof ConditionalExpr) {
    if (e.falseCase && needsTemporaryInSafeAccess(e.falseCase)) return true;
    return needsTemporaryInSafeAccess(e.condition) || needsTemporaryInSafeAccess(e.trueCase);
  } else if (e instanceof NotExpr) {
    return needsTemporaryInSafeAccess(e.condition);
  } else if (e instanceof AssignTemporaryExpr) {
    return needsTemporaryInSafeAccess(e.expr);
  } else if (e instanceof ReadPropExpr) {
    return needsTemporaryInSafeAccess(e.receiver);
  } else if (e instanceof ReadKeyExpr) {
    return needsTemporaryInSafeAccess(e.receiver) || needsTemporaryInSafeAccess(e.index);
  } else if (e instanceof ParenthesizedExpr) {
    return needsTemporaryInSafeAccess(e.expr);
  } else if (e instanceof SafeNavigationMigrationExpr) {
    return needsTemporaryInSafeAccess(e.expr);
  }
  return e instanceof InvokeFunctionExpr || e instanceof LiteralArrayExpr || e instanceof LiteralMapExpr || e instanceof PipeBindingExpr;
}
function temporariesIn(e) {
  const temporaries = new Set();
  transformExpressionsInExpression(e, e => {
    if (e instanceof AssignTemporaryExpr) {
      temporaries.add(e.xref);
    }
    return e;
  }, VisitorContextFlag.None);
  return temporaries;
}
function eliminateTemporaryAssignments(e, tmps, ctx) {
  transformExpressionsInExpression(e, e => {
    if (e instanceof AssignTemporaryExpr && tmps.has(e.xref)) {
      const read = new ReadTemporaryExpr(e.xref);
      return new AssignTemporaryExpr(read, read.xref);
    }
    return e;
  }, VisitorContextFlag.None);
  return e;
}
function safeTernaryWithTemporary(guard, body, ctx) {
  let result;
  if (needsTemporaryInSafeAccess(guard)) {
    const xref = ctx.job.allocateXrefId();
    result = [new AssignTemporaryExpr(guard, xref), new ReadTemporaryExpr(xref)];
  } else {
    result = [guard, guard.clone()];
    eliminateTemporaryAssignments(result[1], temporariesIn(result[0]));
  }
  return new SafeTernaryExpr(result[0], body(result[1]));
}
function isSafeAccessExpression(e) {
  return e instanceof SafePropertyReadExpr || e instanceof SafeKeyedReadExpr || e instanceof InvokeFunctionExpr && e.isOptional;
}
function isUnsafeAccessExpression(e) {
  return e instanceof ReadPropExpr || e instanceof ReadKeyExpr || e instanceof InvokeFunctionExpr && !e.isOptional;
}
function isAccessExpression(e) {
  return isSafeAccessExpression(e) || isUnsafeAccessExpression(e);
}
function deepestSafeTernary(e) {
  if (isAccessExpression(e) && e.receiver instanceof SafeTernaryExpr) {
    let st = e.receiver;
    while (st.expr instanceof SafeTernaryExpr) {
      st = st.expr;
    }
    return st;
  }
  return null;
}
function safeTransform(e, ctx, flags) {
  if (e instanceof SafeNavigationMigrationExpr) {
    return e.expr;
  }
  const useNullSemantics = ctx.job.legacyOptionalChaining || (flags & VisitorContextFlag.InSafeNavigationMigration) !== 0;
  if (!useNullSemantics) {
    if (e instanceof SafePropertyReadExpr) {
      return new ReadPropExpr(e.receiver, e.name, null, e.sourceSpan, [], true);
    }
    if (e instanceof SafeKeyedReadExpr) {
      return new ReadKeyExpr(e.receiver, e.index, null, e.sourceSpan, [], true);
    }
    return e;
  }
  if (!isAccessExpression(e)) {
    return e;
  }
  const dst = deepestSafeTernary(e);
  if (dst) {
    if (e instanceof InvokeFunctionExpr && !e.isOptional) {
      dst.expr = dst.expr.callFn(e.args);
      return e.receiver;
    }
    if (e instanceof ReadPropExpr) {
      dst.expr = dst.expr.prop(e.name);
      return e.receiver;
    }
    if (e instanceof ReadKeyExpr) {
      dst.expr = dst.expr.key(e.index);
      return e.receiver;
    }
    if (e instanceof InvokeFunctionExpr && e.isOptional) {
      dst.expr = safeTernaryWithTemporary(dst.expr, r => r.callFn(e.args), ctx);
      return e.receiver;
    }
    if (e instanceof SafePropertyReadExpr) {
      dst.expr = safeTernaryWithTemporary(dst.expr, r => r.prop(e.name), ctx);
      return e.receiver;
    }
    if (e instanceof SafeKeyedReadExpr) {
      dst.expr = safeTernaryWithTemporary(dst.expr, r => r.key(e.index), ctx);
      return e.receiver;
    }
  } else {
    if (e instanceof InvokeFunctionExpr && e.isOptional) {
      return safeTernaryWithTemporary(e.receiver, r => r.callFn(e.args), ctx);
    }
    if (e instanceof SafePropertyReadExpr) {
      return safeTernaryWithTemporary(e.receiver, r => r.prop(e.name), ctx);
    }
    if (e instanceof SafeKeyedReadExpr) {
      return safeTernaryWithTemporary(e.receiver, r => r.key(e.index), ctx);
    }
  }
  return e;
}
function ternaryTransform(e) {
  if (!(e instanceof SafeTernaryExpr)) {
    return e;
  }
  return new ParenthesizedExpr(new ConditionalExpr(new BinaryOperatorExpr(BinaryOperator.Equals, e.guard, NULL_EXPR), NULL_EXPR, e.expr));
}

const ESCAPE$1 = '\uFFFD';
const ELEMENT_MARKER = '#';
const TEMPLATE_MARKER = '*';
const TAG_CLOSE_MARKER = '/';
const CONTEXT_MARKER = ':';
const LIST_START_MARKER = '[';
const LIST_END_MARKER = ']';
const LIST_DELIMITER = '|';
function extractI18nMessages(job) {
  const i18nMessagesByContext = new Map();
  const i18nBlocks = new Map();
  const i18nContexts = new Map();
  for (const unit of job.units) {
    for (const op of unit.create) {
      switch (op.kind) {
        case OpKind.I18nContext:
          const i18nMessageOp = createI18nMessage(job, op);
          unit.create.push(i18nMessageOp);
          i18nMessagesByContext.set(op.xref, i18nMessageOp);
          i18nContexts.set(op.xref, op);
          break;
        case OpKind.I18nStart:
          i18nBlocks.set(op.xref, op);
          break;
      }
    }
  }
  let currentIcu = null;
  for (const unit of job.units) {
    for (const op of unit.create) {
      switch (op.kind) {
        case OpKind.IcuStart:
          currentIcu = op;
          OpList.remove(op);
          const icuContext = i18nContexts.get(op.context);
          if (icuContext.contextKind !== I18nContextKind.Icu) {
            continue;
          }
          const i18nBlock = i18nBlocks.get(icuContext.i18nBlock);
          if (i18nBlock.context === icuContext.xref) {
            continue;
          }
          const rootI18nBlock = i18nBlocks.get(i18nBlock.root);
          const rootMessage = i18nMessagesByContext.get(rootI18nBlock.context);
          if (rootMessage === undefined) {
            throw Error('AssertionError: ICU sub-message should belong to a root message.');
          }
          const subMessage = i18nMessagesByContext.get(icuContext.xref);
          subMessage.messagePlaceholder = op.messagePlaceholder;
          rootMessage.subMessages.push(subMessage.xref);
          break;
        case OpKind.IcuEnd:
          currentIcu = null;
          OpList.remove(op);
          break;
        case OpKind.IcuPlaceholder:
          if (currentIcu === null || currentIcu.context == null) {
            throw Error('AssertionError: Unexpected ICU placeholder outside of i18n context');
          }
          const msg = i18nMessagesByContext.get(currentIcu.context);
          msg.postprocessingParams.set(op.name, literal(formatIcuPlaceholder(op)));
          OpList.remove(op);
          break;
      }
    }
  }
}
function createI18nMessage(job, context, messagePlaceholder) {
  let formattedParams = formatParams(context.params);
  const formattedPostprocessingParams = formatParams(context.postprocessingParams);
  let needsPostprocessing = [...context.params.values()].some(v => v.length > 1);
  return createI18nMessageOp(job.allocateXrefId(), context.xref, context.i18nBlock, context.message, null, formattedParams, formattedPostprocessingParams, needsPostprocessing);
}
function formatIcuPlaceholder(op) {
  if (op.strings.length !== op.expressionPlaceholders.length + 1) {
    throw Error(`AssertionError: Invalid ICU placeholder with ${op.strings.length} strings and ${op.expressionPlaceholders.length} expressions`);
  }
  const values = op.expressionPlaceholders.map(formatValue);
  return op.strings.flatMap((str, i) => [str, values[i] || '']).join('');
}
function formatParams(params) {
  const formattedParams = new Map();
  for (const [placeholder, placeholderValues] of params) {
    const serializedValues = formatParamValues(placeholderValues);
    if (serializedValues !== null) {
      formattedParams.set(placeholder, literal(serializedValues));
    }
  }
  return formattedParams;
}
function formatParamValues(values) {
  if (values.length === 0) {
    return null;
  }
  const serializedValues = values.map(value => formatValue(value));
  return serializedValues.length === 1 ? serializedValues[0] : `${LIST_START_MARKER}${serializedValues.join(LIST_DELIMITER)}${LIST_END_MARKER}`;
}
function formatValue(value) {
  if (value.flags & I18nParamValueFlags.ElementTag && value.flags & I18nParamValueFlags.TemplateTag) {
    if (typeof value.value !== 'object') {
      throw Error('AssertionError: Expected i18n param value to have an element and template slot');
    }
    const elementValue = formatValue({
      ...value,
      value: value.value.element,
      flags: value.flags & ~I18nParamValueFlags.TemplateTag
    });
    const templateValue = formatValue({
      ...value,
      value: value.value.template,
      flags: value.flags & ~I18nParamValueFlags.ElementTag
    });
    if (value.flags & I18nParamValueFlags.OpenTag && value.flags & I18nParamValueFlags.CloseTag) {
      return `${templateValue}${elementValue}${templateValue}`;
    }
    return value.flags & I18nParamValueFlags.CloseTag ? `${elementValue}${templateValue}` : `${templateValue}${elementValue}`;
  }
  if (value.flags & I18nParamValueFlags.OpenTag && value.flags & I18nParamValueFlags.CloseTag) {
    return `${formatValue({
      ...value,
      flags: value.flags & ~I18nParamValueFlags.CloseTag
    })}${formatValue({
      ...value,
      flags: value.flags & ~I18nParamValueFlags.OpenTag
    })}`;
  }
  if (value.flags === I18nParamValueFlags.None) {
    return `${value.value}`;
  }
  let tagMarker = '';
  let closeMarker = '';
  if (value.flags & I18nParamValueFlags.ElementTag) {
    tagMarker = ELEMENT_MARKER;
  } else if (value.flags & I18nParamValueFlags.TemplateTag) {
    tagMarker = TEMPLATE_MARKER;
  }
  if (tagMarker !== '') {
    closeMarker = value.flags & I18nParamValueFlags.CloseTag ? TAG_CLOSE_MARKER : '';
  }
  const context = value.subTemplateIndex === null ? '' : `${CONTEXT_MARKER}${value.subTemplateIndex}`;
  return `${ESCAPE$1}${closeMarker}${tagMarker}${value.value}${context}${ESCAPE$1}`;
}

function generateAdvance(job) {
  for (const unit of job.units) {
    const slotMap = new Map();
    for (const op of unit.create) {
      if (!hasConsumesSlotTrait(op)) {
        continue;
      } else if (op.handle.slot === null) {
        throw new Error(`AssertionError: expected slots to have been allocated before generating advance() calls`);
      }
      slotMap.set(op.xref, op.handle.slot);
    }
    let slotContext = 0;
    for (const op of unit.update) {
      let consumer = null;
      if (hasDependsOnSlotContextTrait(op)) {
        consumer = op;
      } else {
        visitExpressionsInOp(op, expr => {
          if (consumer === null && hasDependsOnSlotContextTrait(expr)) {
            consumer = expr;
          }
        });
      }
      if (consumer === null) {
        continue;
      }
      if (!slotMap.has(consumer.target)) {
        throw new Error(`AssertionError: reference to unknown slot for target ${consumer.target}`);
      }
      const slot = slotMap.get(consumer.target);
      if (slotContext !== slot) {
        const delta = slot - slotContext;
        if (delta < 0) {
          throw new Error(`AssertionError: slot counter should never need to move backwards`);
        }
        OpList.insertBefore(createAdvanceOp(delta, consumer.sourceSpan), op);
        slotContext = slot;
      }
    }
  }
}

function generateArrowFunctions(job) {
  for (const unit of job.units) {
    for (const op of unit.create) {
      if (op.kind !== OpKind.Animation && op.kind !== OpKind.AnimationListener && op.kind !== OpKind.Listener && op.kind !== OpKind.TwoWayListener) {
        addArrowFunctions(unit, op);
      }
    }
    for (const op of unit.update) {
      addArrowFunctions(unit, op);
    }
  }
}
function addArrowFunctions(unit, op) {
  transformExpressionsInOp(op, (expr, flags) => {
    if (!(expr instanceof ArrowFunctionExpr$1) || flags & VisitorContextFlag.InChildOperation) {
      return expr;
    }
    if (Array.isArray(expr.body)) {
      throw new Error('AssertionError: unexpected multi-line arrow function');
    }
    const arrowFunction = new ArrowFunctionExpr(expr.params, expr.body);
    unit.functions.add(arrowFunction);
    return arrowFunction;
  }, VisitorContextFlag.None);
}

function generateLocalLetReferences(job) {
  for (const unit of job.units) {
    for (const op of unit.update) {
      if (op.kind !== OpKind.StoreLet) {
        continue;
      }
      const variable = {
        kind: SemanticVariableKind.Identifier,
        name: null,
        identifier: op.declaredName,
        local: true
      };
      OpList.replace(op, createVariableOp(job.allocateXrefId(), variable, new StoreLetExpr(op.target, op.value, op.sourceSpan), VariableFlags.None));
    }
  }
}

function generateProjectionDefs(job) {
  const share = true;
  const selectors = [];
  let projectionSlotIndex = 0;
  for (const unit of job.units) {
    for (const op of unit.create) {
      if (op.kind === OpKind.Projection) {
        selectors.push(op.selector);
        op.projectionSlotIndex = projectionSlotIndex++;
      }
    }
  }
  if (selectors.length > 0) {
    let defExpr = null;
    if (selectors.length > 1 || selectors[0] !== '*') {
      const def = selectors.map(s => s === '*' ? s : parseSelectorToR3Selector(s));
      defExpr = job.pool.getConstLiteral(literalOrArrayLiteral(def), share);
    }
    job.contentSelectors = job.pool.getConstLiteral(literalOrArrayLiteral(selectors), share);
    job.root.create.prepend([createProjectionDefOp(defExpr)]);
  }
}

function generateVariables(job) {
  recursivelyProcessView(job.root, null);
}
function recursivelyProcessView(view, parentScope) {
  const scope = getScopeForView(view, parentScope);
  for (const op of view.create) {
    switch (op.kind) {
      case OpKind.ConditionalCreate:
      case OpKind.ConditionalBranchCreate:
      case OpKind.Template:
        recursivelyProcessView(view.job.views.get(op.xref), scope);
        break;
      case OpKind.Projection:
        if (op.fallbackView !== null) {
          recursivelyProcessView(view.job.views.get(op.fallbackView), scope);
        }
        break;
      case OpKind.RepeaterCreate:
        recursivelyProcessView(view.job.views.get(op.xref), scope);
        if (op.emptyView) {
          recursivelyProcessView(view.job.views.get(op.emptyView), scope);
        }
        if (op.trackByOps !== null) {
          op.trackByOps.prepend(generateVariablesInScopeForView(view, scope, false));
        }
        break;
      case OpKind.Animation:
      case OpKind.AnimationListener:
      case OpKind.Listener:
      case OpKind.TwoWayListener:
        op.handlerOps.prepend(generateVariablesInScopeForView(view, scope, true));
        break;
    }
  }
  view.create.prepend(generateVariablesInScopeForView(view, scope, false));
  view.update.prepend(generateVariablesInScopeForView(view, scope, false));
  for (const expr of view.functions) {
    expr.ops.prepend(generateVariablesInScopeForView(view, getScopeForView(view, parentScope), true));
  }
}
function getScopeForView(view, parent) {
  const scope = {
    view: view.xref,
    viewContextVariable: {
      kind: SemanticVariableKind.Context,
      name: null,
      view: view.xref
    },
    contextVariables: new Map(),
    aliases: view.aliases,
    references: [],
    letDeclarations: [],
    parent
  };
  for (const identifier of view.contextVariables.keys()) {
    scope.contextVariables.set(identifier, {
      kind: SemanticVariableKind.Identifier,
      name: null,
      identifier,
      local: false
    });
  }
  for (const op of view.create) {
    switch (op.kind) {
      case OpKind.ElementStart:
      case OpKind.ConditionalCreate:
      case OpKind.ConditionalBranchCreate:
      case OpKind.Template:
        if (!Array.isArray(op.localRefs)) {
          throw new Error(`AssertionError: expected localRefs to be an array`);
        }
        for (let offset = 0; offset < op.localRefs.length; offset++) {
          scope.references.push({
            name: op.localRefs[offset].name,
            targetId: op.xref,
            targetSlot: op.handle,
            offset,
            variable: {
              kind: SemanticVariableKind.Identifier,
              name: null,
              identifier: op.localRefs[offset].name,
              local: false
            }
          });
        }
        break;
      case OpKind.DeclareLet:
        scope.letDeclarations.push({
          targetId: op.xref,
          targetSlot: op.handle,
          variable: {
            kind: SemanticVariableKind.Identifier,
            name: null,
            identifier: op.declaredName,
            local: false
          }
        });
        break;
    }
  }
  return scope;
}
function generateVariablesInScopeForView(view, scope, isCallback) {
  const newOps = [];
  if (scope.view !== view.xref) {
    newOps.push(createVariableOp(view.job.allocateXrefId(), scope.viewContextVariable, new NextContextExpr(), VariableFlags.None));
  }
  const scopeView = view.job.views.get(scope.view);
  for (const [name, value] of scopeView.contextVariables) {
    const context = new ContextExpr(scope.view);
    let variable;
    if (value === CTX_REF) {
      variable = context;
    } else if (typeof value === 'number') {
      variable = new ReadKeyExpr(context, literal(value));
    } else {
      variable = new ReadPropExpr(context, value);
    }
    newOps.push(createVariableOp(view.job.allocateXrefId(), scope.contextVariables.get(name), variable, VariableFlags.None));
  }
  for (const alias of scopeView.aliases) {
    newOps.push(createVariableOp(view.job.allocateXrefId(), alias, alias.expression.clone(), VariableFlags.AlwaysInline));
  }
  for (const ref of scope.references) {
    newOps.push(createVariableOp(view.job.allocateXrefId(), ref.variable, new ReferenceExpr(ref.targetId, ref.targetSlot, ref.offset), VariableFlags.None));
  }
  if (scope.view !== view.xref || isCallback) {
    for (const decl of scope.letDeclarations) {
      newOps.push(createVariableOp(view.job.allocateXrefId(), decl.variable, new ContextLetReferenceExpr(decl.targetId, decl.targetSlot), VariableFlags.None));
    }
  }
  if (scope.parent !== null) {
    newOps.push(...generateVariablesInScopeForView(view, scope.parent, false));
  }
  return newOps;
}

function collectConstExpressions(job) {
  for (const unit of job.units) {
    for (const op of unit.ops()) {
      transformExpressionsInOp(op, expr => {
        if (!(expr instanceof ConstCollectedExpr)) {
          return expr;
        }
        return literal(job.addConst(expr.expr));
      }, VisitorContextFlag.None);
    }
  }
}

const STYLE_DOT = 'style.';
const CLASS_DOT = 'class.';
const STYLE_BANG = 'style!';
const CLASS_BANG = 'class!';
const BANG_IMPORTANT = '!important';
function parseHostStyleProperties(job) {
  for (const op of job.root.update) {
    if (!(op.kind === OpKind.Binding && op.bindingKind === BindingKind.Property)) {
      continue;
    }
    if (op.name.endsWith(BANG_IMPORTANT)) {
      op.name = op.name.substring(0, op.name.length - BANG_IMPORTANT.length);
    }
    if (op.name.startsWith(STYLE_DOT)) {
      op.bindingKind = BindingKind.StyleProperty;
      op.name = op.name.substring(STYLE_DOT.length);
      if (!isCssCustomProperty(op.name)) {
        op.name = hyphenate$1(op.name);
      } else {
        op.name = namespaceCssVariable(op.name);
      }
      const {
        property,
        suffix
      } = parseProperty(op.name);
      op.name = property;
      op.unit = suffix;
    } else if (op.name.startsWith(STYLE_BANG)) {
      op.bindingKind = BindingKind.StyleProperty;
      op.name = 'style';
    } else if (op.name.startsWith(CLASS_DOT)) {
      op.bindingKind = BindingKind.ClassName;
      op.name = parseProperty(op.name.substring(CLASS_DOT.length)).property;
    } else if (op.name.startsWith(CLASS_BANG)) {
      op.bindingKind = BindingKind.ClassName;
      op.name = parseProperty(op.name.substring(CLASS_BANG.length)).property;
    }
  }
}
function isCssCustomProperty(name) {
  return name.startsWith('--');
}
function hyphenate$1(value) {
  return value.replace(/[a-z][A-Z]/g, v => {
    return v.charAt(0) + '-' + v.charAt(1);
  }).toLowerCase();
}
function parseProperty(name) {
  const overrideIndex = name.indexOf('!important');
  if (overrideIndex !== -1) {
    name = overrideIndex > 0 ? name.substring(0, overrideIndex) : '';
  }
  let suffix = null;
  let property = name;
  const unitIndex = name.lastIndexOf('.');
  if (unitIndex > 0) {
    suffix = name.slice(unitIndex + 1);
    property = name.substring(0, unitIndex);
  }
  return {
    property,
    suffix
  };
}

function mapLiteral(obj, quoted = false) {
  return literalMap(Object.keys(obj).map(key => ({
    key,
    quoted,
    value: obj[key]
  })));
}

class IcuSerializerVisitor {
  visitText(text) {
    return text.value;
  }
  visitContainer(container) {
    return container.children.map(child => child.visit(this)).join('');
  }
  visitIcu(icu) {
    const strCases = Object.keys(icu.cases).map(k => `${k} {${icu.cases[k].visit(this)}}`);
    const result = `{${icu.expressionPlaceholder}, ${icu.type}, ${strCases.join(' ')}}`;
    return result;
  }
  visitTagPlaceholder(ph) {
    return ph.isVoid ? this.formatPh(ph.startName) : `${this.formatPh(ph.startName)}${ph.children.map(child => child.visit(this)).join('')}${this.formatPh(ph.closeName)}`;
  }
  visitPlaceholder(ph) {
    return this.formatPh(ph.name);
  }
  visitBlockPlaceholder(ph) {
    return `${this.formatPh(ph.startName)}${ph.children.map(child => child.visit(this)).join('')}${this.formatPh(ph.closeName)}`;
  }
  visitIcuPlaceholder(ph, context) {
    return this.formatPh(ph.name);
  }
  formatPh(value) {
    return `{${formatI18nPlaceholderName(value, false)}}`;
  }
}
const serializer = new IcuSerializerVisitor();
function serializeIcuNode(icu) {
  return icu.visit(serializer);
}

class NodeWithI18n {
  sourceSpan;
  i18n;
  constructor(sourceSpan, i18n) {
    this.sourceSpan = sourceSpan;
    this.i18n = i18n;
  }
}
class Text extends NodeWithI18n {
  value;
  tokens;
  constructor(value, sourceSpan, tokens, i18n) {
    super(sourceSpan, i18n);
    this.value = value;
    this.tokens = tokens;
  }
  visit(visitor, context) {
    return visitor.visitText(this, context);
  }
}
class Expansion extends NodeWithI18n {
  switchValue;
  type;
  cases;
  switchValueSourceSpan;
  constructor(switchValue, type, cases, sourceSpan, switchValueSourceSpan, i18n) {
    super(sourceSpan, i18n);
    this.switchValue = switchValue;
    this.type = type;
    this.cases = cases;
    this.switchValueSourceSpan = switchValueSourceSpan;
  }
  visit(visitor, context) {
    return visitor.visitExpansion(this, context);
  }
}
class ExpansionCase {
  value;
  expression;
  sourceSpan;
  valueSourceSpan;
  expSourceSpan;
  constructor(value, expression, sourceSpan, valueSourceSpan, expSourceSpan) {
    this.value = value;
    this.expression = expression;
    this.sourceSpan = sourceSpan;
    this.valueSourceSpan = valueSourceSpan;
    this.expSourceSpan = expSourceSpan;
  }
  visit(visitor, context) {
    return visitor.visitExpansionCase(this, context);
  }
}
class Attribute extends NodeWithI18n {
  name;
  value;
  keySpan;
  valueSpan;
  valueTokens;
  constructor(name, value, sourceSpan, keySpan, valueSpan, valueTokens, i18n) {
    super(sourceSpan, i18n);
    this.name = name;
    this.value = value;
    this.keySpan = keySpan;
    this.valueSpan = valueSpan;
    this.valueTokens = valueTokens;
  }
  visit(visitor, context) {
    return visitor.visitAttribute(this, context);
  }
}
class StartTagComment {
  value;
  type;
  sourceSpan;
  constructor(value, type, sourceSpan) {
    this.value = value;
    this.type = type;
    this.sourceSpan = sourceSpan;
  }
  visit(visitor, context) {
    return visitor.visitStartTagComment ? visitor.visitStartTagComment(this, context) : undefined;
  }
}
class Element extends NodeWithI18n {
  name;
  attrs;
  directives;
  children;
  isSelfClosing;
  startSourceSpan;
  endSourceSpan;
  isVoid;
  comments;
  constructor(name, attrs, directives, children, isSelfClosing, sourceSpan, startSourceSpan, endSourceSpan = null, isVoid, i18n, comments = []) {
    super(sourceSpan, i18n);
    this.name = name;
    this.attrs = attrs;
    this.directives = directives;
    this.children = children;
    this.isSelfClosing = isSelfClosing;
    this.startSourceSpan = startSourceSpan;
    this.endSourceSpan = endSourceSpan;
    this.isVoid = isVoid;
    this.comments = comments;
  }
  visit(visitor, context) {
    return visitor.visitElement(this, context);
  }
}
class Comment {
  value;
  sourceSpan;
  constructor(value, sourceSpan) {
    this.value = value;
    this.sourceSpan = sourceSpan;
  }
  visit(visitor, context) {
    return visitor.visitComment(this, context);
  }
}
class Block extends NodeWithI18n {
  name;
  parameters;
  children;
  nameSpan;
  startSourceSpan;
  endSourceSpan;
  constructor(name, parameters, children, sourceSpan, nameSpan, startSourceSpan, endSourceSpan = null, i18n) {
    super(sourceSpan, i18n);
    this.name = name;
    this.parameters = parameters;
    this.children = children;
    this.nameSpan = nameSpan;
    this.startSourceSpan = startSourceSpan;
    this.endSourceSpan = endSourceSpan;
  }
  visit(visitor, context) {
    return visitor.visitBlock(this, context);
  }
}
class Component extends NodeWithI18n {
  componentName;
  tagName;
  fullName;
  attrs;
  directives;
  children;
  isSelfClosing;
  startSourceSpan;
  endSourceSpan;
  comments;
  constructor(componentName, tagName, fullName, attrs, directives, children, isSelfClosing, sourceSpan, startSourceSpan, endSourceSpan = null, i18n, comments = []) {
    super(sourceSpan, i18n);
    this.componentName = componentName;
    this.tagName = tagName;
    this.fullName = fullName;
    this.attrs = attrs;
    this.directives = directives;
    this.children = children;
    this.isSelfClosing = isSelfClosing;
    this.startSourceSpan = startSourceSpan;
    this.endSourceSpan = endSourceSpan;
    this.comments = comments;
  }
  visit(visitor, context) {
    return visitor.visitComponent(this, context);
  }
}
class Directive {
  name;
  attrs;
  sourceSpan;
  startSourceSpan;
  endSourceSpan;
  constructor(name, attrs, sourceSpan, startSourceSpan, endSourceSpan = null) {
    this.name = name;
    this.attrs = attrs;
    this.sourceSpan = sourceSpan;
    this.startSourceSpan = startSourceSpan;
    this.endSourceSpan = endSourceSpan;
  }
  visit(visitor, context) {
    return visitor.visitDirective(this, context);
  }
}
class BlockParameter {
  expression;
  sourceSpan;
  constructor(expression, sourceSpan) {
    this.expression = expression;
    this.sourceSpan = sourceSpan;
  }
  visit(visitor, context) {
    return visitor.visitBlockParameter(this, context);
  }
}
class LetDeclaration {
  name;
  value;
  sourceSpan;
  nameSpan;
  valueSpan;
  constructor(name, value, sourceSpan, nameSpan, valueSpan) {
    this.name = name;
    this.value = value;
    this.sourceSpan = sourceSpan;
    this.nameSpan = nameSpan;
    this.valueSpan = valueSpan;
  }
  visit(visitor, context) {
    return visitor.visitLetDeclaration(this, context);
  }
}
function visitAll(visitor, nodes, context = null) {
  const result = [];
  const visit = visitor.visit ? ast => visitor.visit(ast, context) || ast.visit(visitor, context) : ast => ast.visit(visitor, context);
  nodes.forEach(ast => {
    const astResult = visit(ast);
    if (astResult) {
      result.push(astResult);
    }
  });
  return result;
}
class RecursiveVisitor {
  constructor() {}
  visitElement(ast, context) {
    this.visitChildren(context, visit => {
      visit(ast.attrs);
      visit(ast.directives);
      visit(ast.comments);
      visit(ast.children);
    });
  }
  visitAttribute(ast, context) {}
  visitStartTagComment(ast, context) {}
  visitText(ast, context) {}
  visitComment(ast, context) {}
  visitExpansion(ast, context) {
    return this.visitChildren(context, visit => {
      visit(ast.cases);
    });
  }
  visitExpansionCase(ast, context) {}
  visitBlock(block, context) {
    this.visitChildren(context, visit => {
      visit(block.parameters);
      visit(block.children);
    });
  }
  visitBlockParameter(ast, context) {}
  visitLetDeclaration(decl, context) {}
  visitComponent(component, context) {
    this.visitChildren(context, visit => {
      visit(component.attrs);
      visit(component.comments);
      visit(component.children);
    });
  }
  visitDirective(directive, context) {
    this.visitChildren(context, visit => {
      visit(directive.attrs);
    });
  }
  visitChildren(context, cb) {
    let results = [];
    let t = this;
    function visit(children) {
      if (children) results.push(visitAll(t, children, context));
    }
    cb(visit);
    return Array.prototype.concat.apply([], results);
  }
}

const NAMED_ENTITIES = {
  'AElig': '\u00C6',
  'AMP': '\u0026',
  'amp': '\u0026',
  'Aacute': '\u00C1',
  'Abreve': '\u0102',
  'Acirc': '\u00C2',
  'Acy': '\u0410',
  'Afr': '\uD835\uDD04',
  'Agrave': '\u00C0',
  'Alpha': '\u0391',
  'Amacr': '\u0100',
  'And': '\u2A53',
  'Aogon': '\u0104',
  'Aopf': '\uD835\uDD38',
  'ApplyFunction': '\u2061',
  'af': '\u2061',
  'Aring': '\u00C5',
  'angst': '\u00C5',
  'Ascr': '\uD835\uDC9C',
  'Assign': '\u2254',
  'colone': '\u2254',
  'coloneq': '\u2254',
  'Atilde': '\u00C3',
  'Auml': '\u00C4',
  'Backslash': '\u2216',
  'setminus': '\u2216',
  'setmn': '\u2216',
  'smallsetminus': '\u2216',
  'ssetmn': '\u2216',
  'Barv': '\u2AE7',
  'Barwed': '\u2306',
  'doublebarwedge': '\u2306',
  'Bcy': '\u0411',
  'Because': '\u2235',
  'becaus': '\u2235',
  'because': '\u2235',
  'Bernoullis': '\u212C',
  'Bscr': '\u212C',
  'bernou': '\u212C',
  'Beta': '\u0392',
  'Bfr': '\uD835\uDD05',
  'Bopf': '\uD835\uDD39',
  'Breve': '\u02D8',
  'breve': '\u02D8',
  'Bumpeq': '\u224E',
  'HumpDownHump': '\u224E',
  'bump': '\u224E',
  'CHcy': '\u0427',
  'COPY': '\u00A9',
  'copy': '\u00A9',
  'Cacute': '\u0106',
  'Cap': '\u22D2',
  'CapitalDifferentialD': '\u2145',
  'DD': '\u2145',
  'Cayleys': '\u212D',
  'Cfr': '\u212D',
  'Ccaron': '\u010C',
  'Ccedil': '\u00C7',
  'Ccirc': '\u0108',
  'Cconint': '\u2230',
  'Cdot': '\u010A',
  'Cedilla': '\u00B8',
  'cedil': '\u00B8',
  'CenterDot': '\u00B7',
  'centerdot': '\u00B7',
  'middot': '\u00B7',
  'Chi': '\u03A7',
  'CircleDot': '\u2299',
  'odot': '\u2299',
  'CircleMinus': '\u2296',
  'ominus': '\u2296',
  'CirclePlus': '\u2295',
  'oplus': '\u2295',
  'CircleTimes': '\u2297',
  'otimes': '\u2297',
  'ClockwiseContourIntegral': '\u2232',
  'cwconint': '\u2232',
  'CloseCurlyDoubleQuote': '\u201D',
  'rdquo': '\u201D',
  'rdquor': '\u201D',
  'CloseCurlyQuote': '\u2019',
  'rsquo': '\u2019',
  'rsquor': '\u2019',
  'Colon': '\u2237',
  'Proportion': '\u2237',
  'Colone': '\u2A74',
  'Congruent': '\u2261',
  'equiv': '\u2261',
  'Conint': '\u222F',
  'DoubleContourIntegral': '\u222F',
  'ContourIntegral': '\u222E',
  'conint': '\u222E',
  'oint': '\u222E',
  'Copf': '\u2102',
  'complexes': '\u2102',
  'Coproduct': '\u2210',
  'coprod': '\u2210',
  'CounterClockwiseContourIntegral': '\u2233',
  'awconint': '\u2233',
  'Cross': '\u2A2F',
  'Cscr': '\uD835\uDC9E',
  'Cup': '\u22D3',
  'CupCap': '\u224D',
  'asympeq': '\u224D',
  'DDotrahd': '\u2911',
  'DJcy': '\u0402',
  'DScy': '\u0405',
  'DZcy': '\u040F',
  'Dagger': '\u2021',
  'ddagger': '\u2021',
  'Darr': '\u21A1',
  'Dashv': '\u2AE4',
  'DoubleLeftTee': '\u2AE4',
  'Dcaron': '\u010E',
  'Dcy': '\u0414',
  'Del': '\u2207',
  'nabla': '\u2207',
  'Delta': '\u0394',
  'Dfr': '\uD835\uDD07',
  'DiacriticalAcute': '\u00B4',
  'acute': '\u00B4',
  'DiacriticalDot': '\u02D9',
  'dot': '\u02D9',
  'DiacriticalDoubleAcute': '\u02DD',
  'dblac': '\u02DD',
  'DiacriticalGrave': '\u0060',
  'grave': '\u0060',
  'DiacriticalTilde': '\u02DC',
  'tilde': '\u02DC',
  'Diamond': '\u22C4',
  'diam': '\u22C4',
  'diamond': '\u22C4',
  'DifferentialD': '\u2146',
  'dd': '\u2146',
  'Dopf': '\uD835\uDD3B',
  'Dot': '\u00A8',
  'DoubleDot': '\u00A8',
  'die': '\u00A8',
  'uml': '\u00A8',
  'DotDot': '\u20DC',
  'DotEqual': '\u2250',
  'doteq': '\u2250',
  'esdot': '\u2250',
  'DoubleDownArrow': '\u21D3',
  'Downarrow': '\u21D3',
  'dArr': '\u21D3',
  'DoubleLeftArrow': '\u21D0',
  'Leftarrow': '\u21D0',
  'lArr': '\u21D0',
  'DoubleLeftRightArrow': '\u21D4',
  'Leftrightarrow': '\u21D4',
  'hArr': '\u21D4',
  'iff': '\u21D4',
  'DoubleLongLeftArrow': '\u27F8',
  'Longleftarrow': '\u27F8',
  'xlArr': '\u27F8',
  'DoubleLongLeftRightArrow': '\u27FA',
  'Longleftrightarrow': '\u27FA',
  'xhArr': '\u27FA',
  'DoubleLongRightArrow': '\u27F9',
  'Longrightarrow': '\u27F9',
  'xrArr': '\u27F9',
  'DoubleRightArrow': '\u21D2',
  'Implies': '\u21D2',
  'Rightarrow': '\u21D2',
  'rArr': '\u21D2',
  'DoubleRightTee': '\u22A8',
  'vDash': '\u22A8',
  'DoubleUpArrow': '\u21D1',
  'Uparrow': '\u21D1',
  'uArr': '\u21D1',
  'DoubleUpDownArrow': '\u21D5',
  'Updownarrow': '\u21D5',
  'vArr': '\u21D5',
  'DoubleVerticalBar': '\u2225',
  'par': '\u2225',
  'parallel': '\u2225',
  'shortparallel': '\u2225',
  'spar': '\u2225',
  'DownArrow': '\u2193',
  'ShortDownArrow': '\u2193',
  'darr': '\u2193',
  'downarrow': '\u2193',
  'DownArrowBar': '\u2913',
  'DownArrowUpArrow': '\u21F5',
  'duarr': '\u21F5',
  'DownBreve': '\u0311',
  'DownLeftRightVector': '\u2950',
  'DownLeftTeeVector': '\u295E',
  'DownLeftVector': '\u21BD',
  'leftharpoondown': '\u21BD',
  'lhard': '\u21BD',
  'DownLeftVectorBar': '\u2956',
  'DownRightTeeVector': '\u295F',
  'DownRightVector': '\u21C1',
  'rhard': '\u21C1',
  'rightharpoondown': '\u21C1',
  'DownRightVectorBar': '\u2957',
  'DownTee': '\u22A4',
  'top': '\u22A4',
  'DownTeeArrow': '\u21A7',
  'mapstodown': '\u21A7',
  'Dscr': '\uD835\uDC9F',
  'Dstrok': '\u0110',
  'ENG': '\u014A',
  'ETH': '\u00D0',
  'Eacute': '\u00C9',
  'Ecaron': '\u011A',
  'Ecirc': '\u00CA',
  'Ecy': '\u042D',
  'Edot': '\u0116',
  'Efr': '\uD835\uDD08',
  'Egrave': '\u00C8',
  'Element': '\u2208',
  'in': '\u2208',
  'isin': '\u2208',
  'isinv': '\u2208',
  'Emacr': '\u0112',
  'EmptySmallSquare': '\u25FB',
  'EmptyVerySmallSquare': '\u25AB',
  'Eogon': '\u0118',
  'Eopf': '\uD835\uDD3C',
  'Epsilon': '\u0395',
  'Equal': '\u2A75',
  'EqualTilde': '\u2242',
  'eqsim': '\u2242',
  'esim': '\u2242',
  'Equilibrium': '\u21CC',
  'rightleftharpoons': '\u21CC',
  'rlhar': '\u21CC',
  'Escr': '\u2130',
  'expectation': '\u2130',
  'Esim': '\u2A73',
  'Eta': '\u0397',
  'Euml': '\u00CB',
  'Exists': '\u2203',
  'exist': '\u2203',
  'ExponentialE': '\u2147',
  'ee': '\u2147',
  'exponentiale': '\u2147',
  'Fcy': '\u0424',
  'Ffr': '\uD835\uDD09',
  'FilledSmallSquare': '\u25FC',
  'FilledVerySmallSquare': '\u25AA',
  'blacksquare': '\u25AA',
  'squarf': '\u25AA',
  'squf': '\u25AA',
  'Fopf': '\uD835\uDD3D',
  'ForAll': '\u2200',
  'forall': '\u2200',
  'Fouriertrf': '\u2131',
  'Fscr': '\u2131',
  'GJcy': '\u0403',
  'GT': '\u003E',
  'gt': '\u003E',
  'Gamma': '\u0393',
  'Gammad': '\u03DC',
  'Gbreve': '\u011E',
  'Gcedil': '\u0122',
  'Gcirc': '\u011C',
  'Gcy': '\u0413',
  'Gdot': '\u0120',
  'Gfr': '\uD835\uDD0A',
  'Gg': '\u22D9',
  'ggg': '\u22D9',
  'Gopf': '\uD835\uDD3E',
  'GreaterEqual': '\u2265',
  'ge': '\u2265',
  'geq': '\u2265',
  'GreaterEqualLess': '\u22DB',
  'gel': '\u22DB',
  'gtreqless': '\u22DB',
  'GreaterFullEqual': '\u2267',
  'gE': '\u2267',
  'geqq': '\u2267',
  'GreaterGreater': '\u2AA2',
  'GreaterLess': '\u2277',
  'gl': '\u2277',
  'gtrless': '\u2277',
  'GreaterSlantEqual': '\u2A7E',
  'geqslant': '\u2A7E',
  'ges': '\u2A7E',
  'GreaterTilde': '\u2273',
  'gsim': '\u2273',
  'gtrsim': '\u2273',
  'Gscr': '\uD835\uDCA2',
  'Gt': '\u226B',
  'NestedGreaterGreater': '\u226B',
  'gg': '\u226B',
  'HARDcy': '\u042A',
  'Hacek': '\u02C7',
  'caron': '\u02C7',
  'Hat': '\u005E',
  'Hcirc': '\u0124',
  'Hfr': '\u210C',
  'Poincareplane': '\u210C',
  'HilbertSpace': '\u210B',
  'Hscr': '\u210B',
  'hamilt': '\u210B',
  'Hopf': '\u210D',
  'quaternions': '\u210D',
  'HorizontalLine': '\u2500',
  'boxh': '\u2500',
  'Hstrok': '\u0126',
  'HumpEqual': '\u224F',
  'bumpe': '\u224F',
  'bumpeq': '\u224F',
  'IEcy': '\u0415',
  'IJlig': '\u0132',
  'IOcy': '\u0401',
  'Iacute': '\u00CD',
  'Icirc': '\u00CE',
  'Icy': '\u0418',
  'Idot': '\u0130',
  'Ifr': '\u2111',
  'Im': '\u2111',
  'image': '\u2111',
  'imagpart': '\u2111',
  'Igrave': '\u00CC',
  'Imacr': '\u012A',
  'ImaginaryI': '\u2148',
  'ii': '\u2148',
  'Int': '\u222C',
  'Integral': '\u222B',
  'int': '\u222B',
  'Intersection': '\u22C2',
  'bigcap': '\u22C2',
  'xcap': '\u22C2',
  'InvisibleComma': '\u2063',
  'ic': '\u2063',
  'InvisibleTimes': '\u2062',
  'it': '\u2062',
  'Iogon': '\u012E',
  'Iopf': '\uD835\uDD40',
  'Iota': '\u0399',
  'Iscr': '\u2110',
  'imagline': '\u2110',
  'Itilde': '\u0128',
  'Iukcy': '\u0406',
  'Iuml': '\u00CF',
  'Jcirc': '\u0134',
  'Jcy': '\u0419',
  'Jfr': '\uD835\uDD0D',
  'Jopf': '\uD835\uDD41',
  'Jscr': '\uD835\uDCA5',
  'Jsercy': '\u0408',
  'Jukcy': '\u0404',
  'KHcy': '\u0425',
  'KJcy': '\u040C',
  'Kappa': '\u039A',
  'Kcedil': '\u0136',
  'Kcy': '\u041A',
  'Kfr': '\uD835\uDD0E',
  'Kopf': '\uD835\uDD42',
  'Kscr': '\uD835\uDCA6',
  'LJcy': '\u0409',
  'LT': '\u003C',
  'lt': '\u003C',
  'Lacute': '\u0139',
  'Lambda': '\u039B',
  'Lang': '\u27EA',
  'Laplacetrf': '\u2112',
  'Lscr': '\u2112',
  'lagran': '\u2112',
  'Larr': '\u219E',
  'twoheadleftarrow': '\u219E',
  'Lcaron': '\u013D',
  'Lcedil': '\u013B',
  'Lcy': '\u041B',
  'LeftAngleBracket': '\u27E8',
  'lang': '\u27E8',
  'langle': '\u27E8',
  'LeftArrow': '\u2190',
  'ShortLeftArrow': '\u2190',
  'larr': '\u2190',
  'leftarrow': '\u2190',
  'slarr': '\u2190',
  'LeftArrowBar': '\u21E4',
  'larrb': '\u21E4',
  'LeftArrowRightArrow': '\u21C6',
  'leftrightarrows': '\u21C6',
  'lrarr': '\u21C6',
  'LeftCeiling': '\u2308',
  'lceil': '\u2308',
  'LeftDoubleBracket': '\u27E6',
  'lobrk': '\u27E6',
  'LeftDownTeeVector': '\u2961',
  'LeftDownVector': '\u21C3',
  'dharl': '\u21C3',
  'downharpoonleft': '\u21C3',
  'LeftDownVectorBar': '\u2959',
  'LeftFloor': '\u230A',
  'lfloor': '\u230A',
  'LeftRightArrow': '\u2194',
  'harr': '\u2194',
  'leftrightarrow': '\u2194',
  'LeftRightVector': '\u294E',
  'LeftTee': '\u22A3',
  'dashv': '\u22A3',
  'LeftTeeArrow': '\u21A4',
  'mapstoleft': '\u21A4',
  'LeftTeeVector': '\u295A',
  'LeftTriangle': '\u22B2',
  'vartriangleleft': '\u22B2',
  'vltri': '\u22B2',
  'LeftTriangleBar': '\u29CF',
  'LeftTriangleEqual': '\u22B4',
  'ltrie': '\u22B4',
  'trianglelefteq': '\u22B4',
  'LeftUpDownVector': '\u2951',
  'LeftUpTeeVector': '\u2960',
  'LeftUpVector': '\u21BF',
  'uharl': '\u21BF',
  'upharpoonleft': '\u21BF',
  'LeftUpVectorBar': '\u2958',
  'LeftVector': '\u21BC',
  'leftharpoonup': '\u21BC',
  'lharu': '\u21BC',
  'LeftVectorBar': '\u2952',
  'LessEqualGreater': '\u22DA',
  'leg': '\u22DA',
  'lesseqgtr': '\u22DA',
  'LessFullEqual': '\u2266',
  'lE': '\u2266',
  'leqq': '\u2266',
  'LessGreater': '\u2276',
  'lessgtr': '\u2276',
  'lg': '\u2276',
  'LessLess': '\u2AA1',
  'LessSlantEqual': '\u2A7D',
  'leqslant': '\u2A7D',
  'les': '\u2A7D',
  'LessTilde': '\u2272',
  'lesssim': '\u2272',
  'lsim': '\u2272',
  'Lfr': '\uD835\uDD0F',
  'Ll': '\u22D8',
  'Lleftarrow': '\u21DA',
  'lAarr': '\u21DA',
  'Lmidot': '\u013F',
  'LongLeftArrow': '\u27F5',
  'longleftarrow': '\u27F5',
  'xlarr': '\u27F5',
  'LongLeftRightArrow': '\u27F7',
  'longleftrightarrow': '\u27F7',
  'xharr': '\u27F7',
  'LongRightArrow': '\u27F6',
  'longrightarrow': '\u27F6',
  'xrarr': '\u27F6',
  'Lopf': '\uD835\uDD43',
  'LowerLeftArrow': '\u2199',
  'swarr': '\u2199',
  'swarrow': '\u2199',
  'LowerRightArrow': '\u2198',
  'searr': '\u2198',
  'searrow': '\u2198',
  'Lsh': '\u21B0',
  'lsh': '\u21B0',
  'Lstrok': '\u0141',
  'Lt': '\u226A',
  'NestedLessLess': '\u226A',
  'll': '\u226A',
  'Map': '\u2905',
  'Mcy': '\u041C',
  'MediumSpace': '\u205F',
  'Mellintrf': '\u2133',
  'Mscr': '\u2133',
  'phmmat': '\u2133',
  'Mfr': '\uD835\uDD10',
  'MinusPlus': '\u2213',
  'mnplus': '\u2213',
  'mp': '\u2213',
  'Mopf': '\uD835\uDD44',
  'Mu': '\u039C',
  'NJcy': '\u040A',
  'Nacute': '\u0143',
  'Ncaron': '\u0147',
  'Ncedil': '\u0145',
  'Ncy': '\u041D',
  'NegativeMediumSpace': '\u200B',
  'NegativeThickSpace': '\u200B',
  'NegativeThinSpace': '\u200B',
  'NegativeVeryThinSpace': '\u200B',
  'ZeroWidthSpace': '\u200B',
  'NewLine': '\u000A',
  'Nfr': '\uD835\uDD11',
  'NoBreak': '\u2060',
  'NonBreakingSpace': '\u00A0',
  'nbsp': '\u00A0',
  'Nopf': '\u2115',
  'naturals': '\u2115',
  'Not': '\u2AEC',
  'NotCongruent': '\u2262',
  'nequiv': '\u2262',
  'NotCupCap': '\u226D',
  'NotDoubleVerticalBar': '\u2226',
  'npar': '\u2226',
  'nparallel': '\u2226',
  'nshortparallel': '\u2226',
  'nspar': '\u2226',
  'NotElement': '\u2209',
  'notin': '\u2209',
  'notinva': '\u2209',
  'NotEqual': '\u2260',
  'ne': '\u2260',
  'NotEqualTilde': '\u2242\u0338',
  'nesim': '\u2242\u0338',
  'NotExists': '\u2204',
  'nexist': '\u2204',
  'nexists': '\u2204',
  'NotGreater': '\u226F',
  'ngt': '\u226F',
  'ngtr': '\u226F',
  'NotGreaterEqual': '\u2271',
  'nge': '\u2271',
  'ngeq': '\u2271',
  'NotGreaterFullEqual': '\u2267\u0338',
  'ngE': '\u2267\u0338',
  'ngeqq': '\u2267\u0338',
  'NotGreaterGreater': '\u226B\u0338',
  'nGtv': '\u226B\u0338',
  'NotGreaterLess': '\u2279',
  'ntgl': '\u2279',
  'NotGreaterSlantEqual': '\u2A7E\u0338',
  'ngeqslant': '\u2A7E\u0338',
  'nges': '\u2A7E\u0338',
  'NotGreaterTilde': '\u2275',
  'ngsim': '\u2275',
  'NotHumpDownHump': '\u224E\u0338',
  'nbump': '\u224E\u0338',
  'NotHumpEqual': '\u224F\u0338',
  'nbumpe': '\u224F\u0338',
  'NotLeftTriangle': '\u22EA',
  'nltri': '\u22EA',
  'ntriangleleft': '\u22EA',
  'NotLeftTriangleBar': '\u29CF\u0338',
  'NotLeftTriangleEqual': '\u22EC',
  'nltrie': '\u22EC',
  'ntrianglelefteq': '\u22EC',
  'NotLess': '\u226E',
  'nless': '\u226E',
  'nlt': '\u226E',
  'NotLessEqual': '\u2270',
  'nle': '\u2270',
  'nleq': '\u2270',
  'NotLessGreater': '\u2278',
  'ntlg': '\u2278',
  'NotLessLess': '\u226A\u0338',
  'nLtv': '\u226A\u0338',
  'NotLessSlantEqual': '\u2A7D\u0338',
  'nleqslant': '\u2A7D\u0338',
  'nles': '\u2A7D\u0338',
  'NotLessTilde': '\u2274',
  'nlsim': '\u2274',
  'NotNestedGreaterGreater': '\u2AA2\u0338',
  'NotNestedLessLess': '\u2AA1\u0338',
  'NotPrecedes': '\u2280',
  'npr': '\u2280',
  'nprec': '\u2280',
  'NotPrecedesEqual': '\u2AAF\u0338',
  'npre': '\u2AAF\u0338',
  'npreceq': '\u2AAF\u0338',
  'NotPrecedesSlantEqual': '\u22E0',
  'nprcue': '\u22E0',
  'NotReverseElement': '\u220C',
  'notni': '\u220C',
  'notniva': '\u220C',
  'NotRightTriangle': '\u22EB',
  'nrtri': '\u22EB',
  'ntriangleright': '\u22EB',
  'NotRightTriangleBar': '\u29D0\u0338',
  'NotRightTriangleEqual': '\u22ED',
  'nrtrie': '\u22ED',
  'ntrianglerighteq': '\u22ED',
  'NotSquareSubset': '\u228F\u0338',
  'NotSquareSubsetEqual': '\u22E2',
  'nsqsube': '\u22E2',
  'NotSquareSuperset': '\u2290\u0338',
  'NotSquareSupersetEqual': '\u22E3',
  'nsqsupe': '\u22E3',
  'NotSubset': '\u2282\u20D2',
  'nsubset': '\u2282\u20D2',
  'vnsub': '\u2282\u20D2',
  'NotSubsetEqual': '\u2288',
  'nsube': '\u2288',
  'nsubseteq': '\u2288',
  'NotSucceeds': '\u2281',
  'nsc': '\u2281',
  'nsucc': '\u2281',
  'NotSucceedsEqual': '\u2AB0\u0338',
  'nsce': '\u2AB0\u0338',
  'nsucceq': '\u2AB0\u0338',
  'NotSucceedsSlantEqual': '\u22E1',
  'nsccue': '\u22E1',
  'NotSucceedsTilde': '\u227F\u0338',
  'NotSuperset': '\u2283\u20D2',
  'nsupset': '\u2283\u20D2',
  'vnsup': '\u2283\u20D2',
  'NotSupersetEqual': '\u2289',
  'nsupe': '\u2289',
  'nsupseteq': '\u2289',
  'NotTilde': '\u2241',
  'nsim': '\u2241',
  'NotTildeEqual': '\u2244',
  'nsime': '\u2244',
  'nsimeq': '\u2244',
  'NotTildeFullEqual': '\u2247',
  'ncong': '\u2247',
  'NotTildeTilde': '\u2249',
  'nap': '\u2249',
  'napprox': '\u2249',
  'NotVerticalBar': '\u2224',
  'nmid': '\u2224',
  'nshortmid': '\u2224',
  'nsmid': '\u2224',
  'Nscr': '\uD835\uDCA9',
  'Ntilde': '\u00D1',
  'Nu': '\u039D',
  'OElig': '\u0152',
  'Oacute': '\u00D3',
  'Ocirc': '\u00D4',
  'Ocy': '\u041E',
  'Odblac': '\u0150',
  'Ofr': '\uD835\uDD12',
  'Ograve': '\u00D2',
  'Omacr': '\u014C',
  'Omega': '\u03A9',
  'ohm': '\u03A9',
  'Omicron': '\u039F',
  'Oopf': '\uD835\uDD46',
  'OpenCurlyDoubleQuote': '\u201C',
  'ldquo': '\u201C',
  'OpenCurlyQuote': '\u2018',
  'lsquo': '\u2018',
  'Or': '\u2A54',
  'Oscr': '\uD835\uDCAA',
  'Oslash': '\u00D8',
  'Otilde': '\u00D5',
  'Otimes': '\u2A37',
  'Ouml': '\u00D6',
  'OverBar': '\u203E',
  'oline': '\u203E',
  'OverBrace': '\u23DE',
  'OverBracket': '\u23B4',
  'tbrk': '\u23B4',
  'OverParenthesis': '\u23DC',
  'PartialD': '\u2202',
  'part': '\u2202',
  'Pcy': '\u041F',
  'Pfr': '\uD835\uDD13',
  'Phi': '\u03A6',
  'Pi': '\u03A0',
  'PlusMinus': '\u00B1',
  'plusmn': '\u00B1',
  'pm': '\u00B1',
  'Popf': '\u2119',
  'primes': '\u2119',
  'Pr': '\u2ABB',
  'Precedes': '\u227A',
  'pr': '\u227A',
  'prec': '\u227A',
  'PrecedesEqual': '\u2AAF',
  'pre': '\u2AAF',
  'preceq': '\u2AAF',
  'PrecedesSlantEqual': '\u227C',
  'prcue': '\u227C',
  'preccurlyeq': '\u227C',
  'PrecedesTilde': '\u227E',
  'precsim': '\u227E',
  'prsim': '\u227E',
  'Prime': '\u2033',
  'Product': '\u220F',
  'prod': '\u220F',
  'Proportional': '\u221D',
  'prop': '\u221D',
  'propto': '\u221D',
  'varpropto': '\u221D',
  'vprop': '\u221D',
  'Pscr': '\uD835\uDCAB',
  'Psi': '\u03A8',
  'QUOT': '\u0022',
  'quot': '\u0022',
  'Qfr': '\uD835\uDD14',
  'Qopf': '\u211A',
  'rationals': '\u211A',
  'Qscr': '\uD835\uDCAC',
  'RBarr': '\u2910',
  'drbkarow': '\u2910',
  'REG': '\u00AE',
  'circledR': '\u00AE',
  'reg': '\u00AE',
  'Racute': '\u0154',
  'Rang': '\u27EB',
  'Rarr': '\u21A0',
  'twoheadrightarrow': '\u21A0',
  'Rarrtl': '\u2916',
  'Rcaron': '\u0158',
  'Rcedil': '\u0156',
  'Rcy': '\u0420',
  'Re': '\u211C',
  'Rfr': '\u211C',
  'real': '\u211C',
  'realpart': '\u211C',
  'ReverseElement': '\u220B',
  'SuchThat': '\u220B',
  'ni': '\u220B',
  'niv': '\u220B',
  'ReverseEquilibrium': '\u21CB',
  'leftrightharpoons': '\u21CB',
  'lrhar': '\u21CB',
  'ReverseUpEquilibrium': '\u296F',
  'duhar': '\u296F',
  'Rho': '\u03A1',
  'RightAngleBracket': '\u27E9',
  'rang': '\u27E9',
  'rangle': '\u27E9',
  'RightArrow': '\u2192',
  'ShortRightArrow': '\u2192',
  'rarr': '\u2192',
  'rightarrow': '\u2192',
  'srarr': '\u2192',
  'RightArrowBar': '\u21E5',
  'rarrb': '\u21E5',
  'RightArrowLeftArrow': '\u21C4',
  'rightleftarrows': '\u21C4',
  'rlarr': '\u21C4',
  'RightCeiling': '\u2309',
  'rceil': '\u2309',
  'RightDoubleBracket': '\u27E7',
  'robrk': '\u27E7',
  'RightDownTeeVector': '\u295D',
  'RightDownVector': '\u21C2',
  'dharr': '\u21C2',
  'downharpoonright': '\u21C2',
  'RightDownVectorBar': '\u2955',
  'RightFloor': '\u230B',
  'rfloor': '\u230B',
  'RightTee': '\u22A2',
  'vdash': '\u22A2',
  'RightTeeArrow': '\u21A6',
  'map': '\u21A6',
  'mapsto': '\u21A6',
  'RightTeeVector': '\u295B',
  'RightTriangle': '\u22B3',
  'vartriangleright': '\u22B3',
  'vrtri': '\u22B3',
  'RightTriangleBar': '\u29D0',
  'RightTriangleEqual': '\u22B5',
  'rtrie': '\u22B5',
  'trianglerighteq': '\u22B5',
  'RightUpDownVector': '\u294F',
  'RightUpTeeVector': '\u295C',
  'RightUpVector': '\u21BE',
  'uharr': '\u21BE',
  'upharpoonright': '\u21BE',
  'RightUpVectorBar': '\u2954',
  'RightVector': '\u21C0',
  'rharu': '\u21C0',
  'rightharpoonup': '\u21C0',
  'RightVectorBar': '\u2953',
  'Ropf': '\u211D',
  'reals': '\u211D',
  'RoundImplies': '\u2970',
  'Rrightarrow': '\u21DB',
  'rAarr': '\u21DB',
  'Rscr': '\u211B',
  'realine': '\u211B',
  'Rsh': '\u21B1',
  'rsh': '\u21B1',
  'RuleDelayed': '\u29F4',
  'SHCHcy': '\u0429',
  'SHcy': '\u0428',
  'SOFTcy': '\u042C',
  'Sacute': '\u015A',
  'Sc': '\u2ABC',
  'Scaron': '\u0160',
  'Scedil': '\u015E',
  'Scirc': '\u015C',
  'Scy': '\u0421',
  'Sfr': '\uD835\uDD16',
  'ShortUpArrow': '\u2191',
  'UpArrow': '\u2191',
  'uarr': '\u2191',
  'uparrow': '\u2191',
  'Sigma': '\u03A3',
  'SmallCircle': '\u2218',
  'compfn': '\u2218',
  'Sopf': '\uD835\uDD4A',
  'Sqrt': '\u221A',
  'radic': '\u221A',
  'Square': '\u25A1',
  'squ': '\u25A1',
  'square': '\u25A1',
  'SquareIntersection': '\u2293',
  'sqcap': '\u2293',
  'SquareSubset': '\u228F',
  'sqsub': '\u228F',
  'sqsubset': '\u228F',
  'SquareSubsetEqual': '\u2291',
  'sqsube': '\u2291',
  'sqsubseteq': '\u2291',
  'SquareSuperset': '\u2290',
  'sqsup': '\u2290',
  'sqsupset': '\u2290',
  'SquareSupersetEqual': '\u2292',
  'sqsupe': '\u2292',
  'sqsupseteq': '\u2292',
  'SquareUnion': '\u2294',
  'sqcup': '\u2294',
  'Sscr': '\uD835\uDCAE',
  'Star': '\u22C6',
  'sstarf': '\u22C6',
  'Sub': '\u22D0',
  'Subset': '\u22D0',
  'SubsetEqual': '\u2286',
  'sube': '\u2286',
  'subseteq': '\u2286',
  'Succeeds': '\u227B',
  'sc': '\u227B',
  'succ': '\u227B',
  'SucceedsEqual': '\u2AB0',
  'sce': '\u2AB0',
  'succeq': '\u2AB0',
  'SucceedsSlantEqual': '\u227D',
  'sccue': '\u227D',
  'succcurlyeq': '\u227D',
  'SucceedsTilde': '\u227F',
  'scsim': '\u227F',
  'succsim': '\u227F',
  'Sum': '\u2211',
  'sum': '\u2211',
  'Sup': '\u22D1',
  'Supset': '\u22D1',
  'Superset': '\u2283',
  'sup': '\u2283',
  'supset': '\u2283',
  'SupersetEqual': '\u2287',
  'supe': '\u2287',
  'supseteq': '\u2287',
  'THORN': '\u00DE',
  'TRADE': '\u2122',
  'trade': '\u2122',
  'TSHcy': '\u040B',
  'TScy': '\u0426',
  'Tab': '\u0009',
  'Tau': '\u03A4',
  'Tcaron': '\u0164',
  'Tcedil': '\u0162',
  'Tcy': '\u0422',
  'Tfr': '\uD835\uDD17',
  'Therefore': '\u2234',
  'there4': '\u2234',
  'therefore': '\u2234',
  'Theta': '\u0398',
  'ThickSpace': '\u205F\u200A',
  'ThinSpace': '\u2009',
  'thinsp': '\u2009',
  'Tilde': '\u223C',
  'sim': '\u223C',
  'thicksim': '\u223C',
  'thksim': '\u223C',
  'TildeEqual': '\u2243',
  'sime': '\u2243',
  'simeq': '\u2243',
  'TildeFullEqual': '\u2245',
  'cong': '\u2245',
  'TildeTilde': '\u2248',
  'ap': '\u2248',
  'approx': '\u2248',
  'asymp': '\u2248',
  'thickapprox': '\u2248',
  'thkap': '\u2248',
  'Topf': '\uD835\uDD4B',
  'TripleDot': '\u20DB',
  'tdot': '\u20DB',
  'Tscr': '\uD835\uDCAF',
  'Tstrok': '\u0166',
  'Uacute': '\u00DA',
  'Uarr': '\u219F',
  'Uarrocir': '\u2949',
  'Ubrcy': '\u040E',
  'Ubreve': '\u016C',
  'Ucirc': '\u00DB',
  'Ucy': '\u0423',
  'Udblac': '\u0170',
  'Ufr': '\uD835\uDD18',
  'Ugrave': '\u00D9',
  'Umacr': '\u016A',
  'UnderBar': '\u005F',
  'lowbar': '\u005F',
  'UnderBrace': '\u23DF',
  'UnderBracket': '\u23B5',
  'bbrk': '\u23B5',
  'UnderParenthesis': '\u23DD',
  'Union': '\u22C3',
  'bigcup': '\u22C3',
  'xcup': '\u22C3',
  'UnionPlus': '\u228E',
  'uplus': '\u228E',
  'Uogon': '\u0172',
  'Uopf': '\uD835\uDD4C',
  'UpArrowBar': '\u2912',
  'UpArrowDownArrow': '\u21C5',
  'udarr': '\u21C5',
  'UpDownArrow': '\u2195',
  'updownarrow': '\u2195',
  'varr': '\u2195',
  'UpEquilibrium': '\u296E',
  'udhar': '\u296E',
  'UpTee': '\u22A5',
  'bot': '\u22A5',
  'bottom': '\u22A5',
  'perp': '\u22A5',
  'UpTeeArrow': '\u21A5',
  'mapstoup': '\u21A5',
  'UpperLeftArrow': '\u2196',
  'nwarr': '\u2196',
  'nwarrow': '\u2196',
  'UpperRightArrow': '\u2197',
  'nearr': '\u2197',
  'nearrow': '\u2197',
  'Upsi': '\u03D2',
  'upsih': '\u03D2',
  'Upsilon': '\u03A5',
  'Uring': '\u016E',
  'Uscr': '\uD835\uDCB0',
  'Utilde': '\u0168',
  'Uuml': '\u00DC',
  'VDash': '\u22AB',
  'Vbar': '\u2AEB',
  'Vcy': '\u0412',
  'Vdash': '\u22A9',
  'Vdashl': '\u2AE6',
  'Vee': '\u22C1',
  'bigvee': '\u22C1',
  'xvee': '\u22C1',
  'Verbar': '\u2016',
  'Vert': '\u2016',
  'VerticalBar': '\u2223',
  'mid': '\u2223',
  'shortmid': '\u2223',
  'smid': '\u2223',
  'VerticalLine': '\u007C',
  'verbar': '\u007C',
  'vert': '\u007C',
  'VerticalSeparator': '\u2758',
  'VerticalTilde': '\u2240',
  'wr': '\u2240',
  'wreath': '\u2240',
  'VeryThinSpace': '\u200A',
  'hairsp': '\u200A',
  'Vfr': '\uD835\uDD19',
  'Vopf': '\uD835\uDD4D',
  'Vscr': '\uD835\uDCB1',
  'Vvdash': '\u22AA',
  'Wcirc': '\u0174',
  'Wedge': '\u22C0',
  'bigwedge': '\u22C0',
  'xwedge': '\u22C0',
  'Wfr': '\uD835\uDD1A',
  'Wopf': '\uD835\uDD4E',
  'Wscr': '\uD835\uDCB2',
  'Xfr': '\uD835\uDD1B',
  'Xi': '\u039E',
  'Xopf': '\uD835\uDD4F',
  'Xscr': '\uD835\uDCB3',
  'YAcy': '\u042F',
  'YIcy': '\u0407',
  'YUcy': '\u042E',
  'Yacute': '\u00DD',
  'Ycirc': '\u0176',
  'Ycy': '\u042B',
  'Yfr': '\uD835\uDD1C',
  'Yopf': '\uD835\uDD50',
  'Yscr': '\uD835\uDCB4',
  'Yuml': '\u0178',
  'ZHcy': '\u0416',
  'Zacute': '\u0179',
  'Zcaron': '\u017D',
  'Zcy': '\u0417',
  'Zdot': '\u017B',
  'Zeta': '\u0396',
  'Zfr': '\u2128',
  'zeetrf': '\u2128',
  'Zopf': '\u2124',
  'integers': '\u2124',
  'Zscr': '\uD835\uDCB5',
  'aacute': '\u00E1',
  'abreve': '\u0103',
  'ac': '\u223E',
  'mstpos': '\u223E',
  'acE': '\u223E\u0333',
  'acd': '\u223F',
  'acirc': '\u00E2',
  'acy': '\u0430',
  'aelig': '\u00E6',
  'afr': '\uD835\uDD1E',
  'agrave': '\u00E0',
  'alefsym': '\u2135',
  'aleph': '\u2135',
  'alpha': '\u03B1',
  'amacr': '\u0101',
  'amalg': '\u2A3F',
  'and': '\u2227',
  'wedge': '\u2227',
  'andand': '\u2A55',
  'andd': '\u2A5C',
  'andslope': '\u2A58',
  'andv': '\u2A5A',
  'ang': '\u2220',
  'angle': '\u2220',
  'ange': '\u29A4',
  'angmsd': '\u2221',
  'measuredangle': '\u2221',
  'angmsdaa': '\u29A8',
  'angmsdab': '\u29A9',
  'angmsdac': '\u29AA',
  'angmsdad': '\u29AB',
  'angmsdae': '\u29AC',
  'angmsdaf': '\u29AD',
  'angmsdag': '\u29AE',
  'angmsdah': '\u29AF',
  'angrt': '\u221F',
  'angrtvb': '\u22BE',
  'angrtvbd': '\u299D',
  'angsph': '\u2222',
  'angzarr': '\u237C',
  'aogon': '\u0105',
  'aopf': '\uD835\uDD52',
  'apE': '\u2A70',
  'apacir': '\u2A6F',
  'ape': '\u224A',
  'approxeq': '\u224A',
  'apid': '\u224B',
  'apos': '\u0027',
  'aring': '\u00E5',
  'ascr': '\uD835\uDCB6',
  'ast': '\u002A',
  'midast': '\u002A',
  'atilde': '\u00E3',
  'auml': '\u00E4',
  'awint': '\u2A11',
  'bNot': '\u2AED',
  'backcong': '\u224C',
  'bcong': '\u224C',
  'backepsilon': '\u03F6',
  'bepsi': '\u03F6',
  'backprime': '\u2035',
  'bprime': '\u2035',
  'backsim': '\u223D',
  'bsim': '\u223D',
  'backsimeq': '\u22CD',
  'bsime': '\u22CD',
  'barvee': '\u22BD',
  'barwed': '\u2305',
  'barwedge': '\u2305',
  'bbrktbrk': '\u23B6',
  'bcy': '\u0431',
  'bdquo': '\u201E',
  'ldquor': '\u201E',
  'bemptyv': '\u29B0',
  'beta': '\u03B2',
  'beth': '\u2136',
  'between': '\u226C',
  'twixt': '\u226C',
  'bfr': '\uD835\uDD1F',
  'bigcirc': '\u25EF',
  'xcirc': '\u25EF',
  'bigodot': '\u2A00',
  'xodot': '\u2A00',
  'bigoplus': '\u2A01',
  'xoplus': '\u2A01',
  'bigotimes': '\u2A02',
  'xotime': '\u2A02',
  'bigsqcup': '\u2A06',
  'xsqcup': '\u2A06',
  'bigstar': '\u2605',
  'starf': '\u2605',
  'bigtriangledown': '\u25BD',
  'xdtri': '\u25BD',
  'bigtriangleup': '\u25B3',
  'xutri': '\u25B3',
  'biguplus': '\u2A04',
  'xuplus': '\u2A04',
  'bkarow': '\u290D',
  'rbarr': '\u290D',
  'blacklozenge': '\u29EB',
  'lozf': '\u29EB',
  'blacktriangle': '\u25B4',
  'utrif': '\u25B4',
  'blacktriangledown': '\u25BE',
  'dtrif': '\u25BE',
  'blacktriangleleft': '\u25C2',
  'ltrif': '\u25C2',
  'blacktriangleright': '\u25B8',
  'rtrif': '\u25B8',
  'blank': '\u2423',
  'blk12': '\u2592',
  'blk14': '\u2591',
  'blk34': '\u2593',
  'block': '\u2588',
  'bne': '\u003D\u20E5',
  'bnequiv': '\u2261\u20E5',
  'bnot': '\u2310',
  'bopf': '\uD835\uDD53',
  'bowtie': '\u22C8',
  'boxDL': '\u2557',
  'boxDR': '\u2554',
  'boxDl': '\u2556',
  'boxDr': '\u2553',
  'boxH': '\u2550',
  'boxHD': '\u2566',
  'boxHU': '\u2569',
  'boxHd': '\u2564',
  'boxHu': '\u2567',
  'boxUL': '\u255D',
  'boxUR': '\u255A',
  'boxUl': '\u255C',
  'boxUr': '\u2559',
  'boxV': '\u2551',
  'boxVH': '\u256C',
  'boxVL': '\u2563',
  'boxVR': '\u2560',
  'boxVh': '\u256B',
  'boxVl': '\u2562',
  'boxVr': '\u255F',
  'boxbox': '\u29C9',
  'boxdL': '\u2555',
  'boxdR': '\u2552',
  'boxdl': '\u2510',
  'boxdr': '\u250C',
  'boxhD': '\u2565',
  'boxhU': '\u2568',
  'boxhd': '\u252C',
  'boxhu': '\u2534',
  'boxminus': '\u229F',
  'minusb': '\u229F',
  'boxplus': '\u229E',
  'plusb': '\u229E',
  'boxtimes': '\u22A0',
  'timesb': '\u22A0',
  'boxuL': '\u255B',
  'boxuR': '\u2558',
  'boxul': '\u2518',
  'boxur': '\u2514',
  'boxv': '\u2502',
  'boxvH': '\u256A',
  'boxvL': '\u2561',
  'boxvR': '\u255E',
  'boxvh': '\u253C',
  'boxvl': '\u2524',
  'boxvr': '\u251C',
  'brvbar': '\u00A6',
  'bscr': '\uD835\uDCB7',
  'bsemi': '\u204F',
  'bsol': '\u005C',
  'bsolb': '\u29C5',
  'bsolhsub': '\u27C8',
  'bull': '\u2022',
  'bullet': '\u2022',
  'bumpE': '\u2AAE',
  'cacute': '\u0107',
  'cap': '\u2229',
  'capand': '\u2A44',
  'capbrcup': '\u2A49',
  'capcap': '\u2A4B',
  'capcup': '\u2A47',
  'capdot': '\u2A40',
  'caps': '\u2229\uFE00',
  'caret': '\u2041',
  'ccaps': '\u2A4D',
  'ccaron': '\u010D',
  'ccedil': '\u00E7',
  'ccirc': '\u0109',
  'ccups': '\u2A4C',
  'ccupssm': '\u2A50',
  'cdot': '\u010B',
  'cemptyv': '\u29B2',
  'cent': '\u00A2',
  'cfr': '\uD835\uDD20',
  'chcy': '\u0447',
  'check': '\u2713',
  'checkmark': '\u2713',
  'chi': '\u03C7',
  'cir': '\u25CB',
  'cirE': '\u29C3',
  'circ': '\u02C6',
  'circeq': '\u2257',
  'cire': '\u2257',
  'circlearrowleft': '\u21BA',
  'olarr': '\u21BA',
  'circlearrowright': '\u21BB',
  'orarr': '\u21BB',
  'circledS': '\u24C8',
  'oS': '\u24C8',
  'circledast': '\u229B',
  'oast': '\u229B',
  'circledcirc': '\u229A',
  'ocir': '\u229A',
  'circleddash': '\u229D',
  'odash': '\u229D',
  'cirfnint': '\u2A10',
  'cirmid': '\u2AEF',
  'cirscir': '\u29C2',
  'clubs': '\u2663',
  'clubsuit': '\u2663',
  'colon': '\u003A',
  'comma': '\u002C',
  'commat': '\u0040',
  'comp': '\u2201',
  'complement': '\u2201',
  'congdot': '\u2A6D',
  'copf': '\uD835\uDD54',
  'copysr': '\u2117',
  'crarr': '\u21B5',
  'cross': '\u2717',
  'cscr': '\uD835\uDCB8',
  'csub': '\u2ACF',
  'csube': '\u2AD1',
  'csup': '\u2AD0',
  'csupe': '\u2AD2',
  'ctdot': '\u22EF',
  'cudarrl': '\u2938',
  'cudarrr': '\u2935',
  'cuepr': '\u22DE',
  'curlyeqprec': '\u22DE',
  'cuesc': '\u22DF',
  'curlyeqsucc': '\u22DF',
  'cularr': '\u21B6',
  'curvearrowleft': '\u21B6',
  'cularrp': '\u293D',
  'cup': '\u222A',
  'cupbrcap': '\u2A48',
  'cupcap': '\u2A46',
  'cupcup': '\u2A4A',
  'cupdot': '\u228D',
  'cupor': '\u2A45',
  'cups': '\u222A\uFE00',
  'curarr': '\u21B7',
  'curvearrowright': '\u21B7',
  'curarrm': '\u293C',
  'curlyvee': '\u22CE',
  'cuvee': '\u22CE',
  'curlywedge': '\u22CF',
  'cuwed': '\u22CF',
  'curren': '\u00A4',
  'cwint': '\u2231',
  'cylcty': '\u232D',
  'dHar': '\u2965',
  'dagger': '\u2020',
  'daleth': '\u2138',
  'dash': '\u2010',
  'hyphen': '\u2010',
  'dbkarow': '\u290F',
  'rBarr': '\u290F',
  'dcaron': '\u010F',
  'dcy': '\u0434',
  'ddarr': '\u21CA',
  'downdownarrows': '\u21CA',
  'ddotseq': '\u2A77',
  'eDDot': '\u2A77',
  'deg': '\u00B0',
  'delta': '\u03B4',
  'demptyv': '\u29B1',
  'dfisht': '\u297F',
  'dfr': '\uD835\uDD21',
  'diamondsuit': '\u2666',
  'diams': '\u2666',
  'digamma': '\u03DD',
  'gammad': '\u03DD',
  'disin': '\u22F2',
  'div': '\u00F7',
  'divide': '\u00F7',
  'divideontimes': '\u22C7',
  'divonx': '\u22C7',
  'djcy': '\u0452',
  'dlcorn': '\u231E',
  'llcorner': '\u231E',
  'dlcrop': '\u230D',
  'dollar': '\u0024',
  'dopf': '\uD835\uDD55',
  'doteqdot': '\u2251',
  'eDot': '\u2251',
  'dotminus': '\u2238',
  'minusd': '\u2238',
  'dotplus': '\u2214',
  'plusdo': '\u2214',
  'dotsquare': '\u22A1',
  'sdotb': '\u22A1',
  'drcorn': '\u231F',
  'lrcorner': '\u231F',
  'drcrop': '\u230C',
  'dscr': '\uD835\uDCB9',
  'dscy': '\u0455',
  'dsol': '\u29F6',
  'dstrok': '\u0111',
  'dtdot': '\u22F1',
  'dtri': '\u25BF',
  'triangledown': '\u25BF',
  'dwangle': '\u29A6',
  'dzcy': '\u045F',
  'dzigrarr': '\u27FF',
  'eacute': '\u00E9',
  'easter': '\u2A6E',
  'ecaron': '\u011B',
  'ecir': '\u2256',
  'eqcirc': '\u2256',
  'ecirc': '\u00EA',
  'ecolon': '\u2255',
  'eqcolon': '\u2255',
  'ecy': '\u044D',
  'edot': '\u0117',
  'efDot': '\u2252',
  'fallingdotseq': '\u2252',
  'efr': '\uD835\uDD22',
  'eg': '\u2A9A',
  'egrave': '\u00E8',
  'egs': '\u2A96',
  'eqslantgtr': '\u2A96',
  'egsdot': '\u2A98',
  'el': '\u2A99',
  'elinters': '\u23E7',
  'ell': '\u2113',
  'els': '\u2A95',
  'eqslantless': '\u2A95',
  'elsdot': '\u2A97',
  'emacr': '\u0113',
  'empty': '\u2205',
  'emptyset': '\u2205',
  'emptyv': '\u2205',
  'varnothing': '\u2205',
  'emsp13': '\u2004',
  'emsp14': '\u2005',
  'emsp': '\u2003',
  'eng': '\u014B',
  'ensp': '\u2002',
  'eogon': '\u0119',
  'eopf': '\uD835\uDD56',
  'epar': '\u22D5',
  'eparsl': '\u29E3',
  'eplus': '\u2A71',
  'epsi': '\u03B5',
  'epsilon': '\u03B5',
  'epsiv': '\u03F5',
  'straightepsilon': '\u03F5',
  'varepsilon': '\u03F5',
  'equals': '\u003D',
  'equest': '\u225F',
  'questeq': '\u225F',
  'equivDD': '\u2A78',
  'eqvparsl': '\u29E5',
  'erDot': '\u2253',
  'risingdotseq': '\u2253',
  'erarr': '\u2971',
  'escr': '\u212F',
  'eta': '\u03B7',
  'eth': '\u00F0',
  'euml': '\u00EB',
  'euro': '\u20AC',
  'excl': '\u0021',
  'fcy': '\u0444',
  'female': '\u2640',
  'ffilig': '\uFB03',
  'fflig': '\uFB00',
  'ffllig': '\uFB04',
  'ffr': '\uD835\uDD23',
  'filig': '\uFB01',
  'fjlig': '\u0066\u006A',
  'flat': '\u266D',
  'fllig': '\uFB02',
  'fltns': '\u25B1',
  'fnof': '\u0192',
  'fopf': '\uD835\uDD57',
  'fork': '\u22D4',
  'pitchfork': '\u22D4',
  'forkv': '\u2AD9',
  'fpartint': '\u2A0D',
  'frac12': '\u00BD',
  'half': '\u00BD',
  'frac13': '\u2153',
  'frac14': '\u00BC',
  'frac15': '\u2155',
  'frac16': '\u2159',
  'frac18': '\u215B',
  'frac23': '\u2154',
  'frac25': '\u2156',
  'frac34': '\u00BE',
  'frac35': '\u2157',
  'frac38': '\u215C',
  'frac45': '\u2158',
  'frac56': '\u215A',
  'frac58': '\u215D',
  'frac78': '\u215E',
  'frasl': '\u2044',
  'frown': '\u2322',
  'sfrown': '\u2322',
  'fscr': '\uD835\uDCBB',
  'gEl': '\u2A8C',
  'gtreqqless': '\u2A8C',
  'gacute': '\u01F5',
  'gamma': '\u03B3',
  'gap': '\u2A86',
  'gtrapprox': '\u2A86',
  'gbreve': '\u011F',
  'gcirc': '\u011D',
  'gcy': '\u0433',
  'gdot': '\u0121',
  'gescc': '\u2AA9',
  'gesdot': '\u2A80',
  'gesdoto': '\u2A82',
  'gesdotol': '\u2A84',
  'gesl': '\u22DB\uFE00',
  'gesles': '\u2A94',
  'gfr': '\uD835\uDD24',
  'gimel': '\u2137',
  'gjcy': '\u0453',
  'glE': '\u2A92',
  'gla': '\u2AA5',
  'glj': '\u2AA4',
  'gnE': '\u2269',
  'gneqq': '\u2269',
  'gnap': '\u2A8A',
  'gnapprox': '\u2A8A',
  'gne': '\u2A88',
  'gneq': '\u2A88',
  'gnsim': '\u22E7',
  'gopf': '\uD835\uDD58',
  'gscr': '\u210A',
  'gsime': '\u2A8E',
  'gsiml': '\u2A90',
  'gtcc': '\u2AA7',
  'gtcir': '\u2A7A',
  'gtdot': '\u22D7',
  'gtrdot': '\u22D7',
  'gtlPar': '\u2995',
  'gtquest': '\u2A7C',
  'gtrarr': '\u2978',
  'gvertneqq': '\u2269\uFE00',
  'gvnE': '\u2269\uFE00',
  'hardcy': '\u044A',
  'harrcir': '\u2948',
  'harrw': '\u21AD',
  'leftrightsquigarrow': '\u21AD',
  'hbar': '\u210F',
  'hslash': '\u210F',
  'planck': '\u210F',
  'plankv': '\u210F',
  'hcirc': '\u0125',
  'hearts': '\u2665',
  'heartsuit': '\u2665',
  'hellip': '\u2026',
  'mldr': '\u2026',
  'hercon': '\u22B9',
  'hfr': '\uD835\uDD25',
  'hksearow': '\u2925',
  'searhk': '\u2925',
  'hkswarow': '\u2926',
  'swarhk': '\u2926',
  'hoarr': '\u21FF',
  'homtht': '\u223B',
  'hookleftarrow': '\u21A9',
  'larrhk': '\u21A9',
  'hookrightarrow': '\u21AA',
  'rarrhk': '\u21AA',
  'hopf': '\uD835\uDD59',
  'horbar': '\u2015',
  'hscr': '\uD835\uDCBD',
  'hstrok': '\u0127',
  'hybull': '\u2043',
  'iacute': '\u00ED',
  'icirc': '\u00EE',
  'icy': '\u0438',
  'iecy': '\u0435',
  'iexcl': '\u00A1',
  'ifr': '\uD835\uDD26',
  'igrave': '\u00EC',
  'iiiint': '\u2A0C',
  'qint': '\u2A0C',
  'iiint': '\u222D',
  'tint': '\u222D',
  'iinfin': '\u29DC',
  'iiota': '\u2129',
  'ijlig': '\u0133',
  'imacr': '\u012B',
  'imath': '\u0131',
  'inodot': '\u0131',
  'imof': '\u22B7',
  'imped': '\u01B5',
  'incare': '\u2105',
  'infin': '\u221E',
  'infintie': '\u29DD',
  'intcal': '\u22BA',
  'intercal': '\u22BA',
  'intlarhk': '\u2A17',
  'intprod': '\u2A3C',
  'iprod': '\u2A3C',
  'iocy': '\u0451',
  'iogon': '\u012F',
  'iopf': '\uD835\uDD5A',
  'iota': '\u03B9',
  'iquest': '\u00BF',
  'iscr': '\uD835\uDCBE',
  'isinE': '\u22F9',
  'isindot': '\u22F5',
  'isins': '\u22F4',
  'isinsv': '\u22F3',
  'itilde': '\u0129',
  'iukcy': '\u0456',
  'iuml': '\u00EF',
  'jcirc': '\u0135',
  'jcy': '\u0439',
  'jfr': '\uD835\uDD27',
  'jmath': '\u0237',
  'jopf': '\uD835\uDD5B',
  'jscr': '\uD835\uDCBF',
  'jsercy': '\u0458',
  'jukcy': '\u0454',
  'kappa': '\u03BA',
  'kappav': '\u03F0',
  'varkappa': '\u03F0',
  'kcedil': '\u0137',
  'kcy': '\u043A',
  'kfr': '\uD835\uDD28',
  'kgreen': '\u0138',
  'khcy': '\u0445',
  'kjcy': '\u045C',
  'kopf': '\uD835\uDD5C',
  'kscr': '\uD835\uDCC0',
  'lAtail': '\u291B',
  'lBarr': '\u290E',
  'lEg': '\u2A8B',
  'lesseqqgtr': '\u2A8B',
  'lHar': '\u2962',
  'lacute': '\u013A',
  'laemptyv': '\u29B4',
  'lambda': '\u03BB',
  'langd': '\u2991',
  'lap': '\u2A85',
  'lessapprox': '\u2A85',
  'laquo': '\u00AB',
  'larrbfs': '\u291F',
  'larrfs': '\u291D',
  'larrlp': '\u21AB',
  'looparrowleft': '\u21AB',
  'larrpl': '\u2939',
  'larrsim': '\u2973',
  'larrtl': '\u21A2',
  'leftarrowtail': '\u21A2',
  'lat': '\u2AAB',
  'latail': '\u2919',
  'late': '\u2AAD',
  'lates': '\u2AAD\uFE00',
  'lbarr': '\u290C',
  'lbbrk': '\u2772',
  'lbrace': '\u007B',
  'lcub': '\u007B',
  'lbrack': '\u005B',
  'lsqb': '\u005B',
  'lbrke': '\u298B',
  'lbrksld': '\u298F',
  'lbrkslu': '\u298D',
  'lcaron': '\u013E',
  'lcedil': '\u013C',
  'lcy': '\u043B',
  'ldca': '\u2936',
  'ldrdhar': '\u2967',
  'ldrushar': '\u294B',
  'ldsh': '\u21B2',
  'le': '\u2264',
  'leq': '\u2264',
  'leftleftarrows': '\u21C7',
  'llarr': '\u21C7',
  'leftthreetimes': '\u22CB',
  'lthree': '\u22CB',
  'lescc': '\u2AA8',
  'lesdot': '\u2A7F',
  'lesdoto': '\u2A81',
  'lesdotor': '\u2A83',
  'lesg': '\u22DA\uFE00',
  'lesges': '\u2A93',
  'lessdot': '\u22D6',
  'ltdot': '\u22D6',
  'lfisht': '\u297C',
  'lfr': '\uD835\uDD29',
  'lgE': '\u2A91',
  'lharul': '\u296A',
  'lhblk': '\u2584',
  'ljcy': '\u0459',
  'llhard': '\u296B',
  'lltri': '\u25FA',
  'lmidot': '\u0140',
  'lmoust': '\u23B0',
  'lmoustache': '\u23B0',
  'lnE': '\u2268',
  'lneqq': '\u2268',
  'lnap': '\u2A89',
  'lnapprox': '\u2A89',
  'lne': '\u2A87',
  'lneq': '\u2A87',
  'lnsim': '\u22E6',
  'loang': '\u27EC',
  'loarr': '\u21FD',
  'longmapsto': '\u27FC',
  'xmap': '\u27FC',
  'looparrowright': '\u21AC',
  'rarrlp': '\u21AC',
  'lopar': '\u2985',
  'lopf': '\uD835\uDD5D',
  'loplus': '\u2A2D',
  'lotimes': '\u2A34',
  'lowast': '\u2217',
  'loz': '\u25CA',
  'lozenge': '\u25CA',
  'lpar': '\u0028',
  'lparlt': '\u2993',
  'lrhard': '\u296D',
  'lrm': '\u200E',
  'lrtri': '\u22BF',
  'lsaquo': '\u2039',
  'lscr': '\uD835\uDCC1',
  'lsime': '\u2A8D',
  'lsimg': '\u2A8F',
  'lsquor': '\u201A',
  'sbquo': '\u201A',
  'lstrok': '\u0142',
  'ltcc': '\u2AA6',
  'ltcir': '\u2A79',
  'ltimes': '\u22C9',
  'ltlarr': '\u2976',
  'ltquest': '\u2A7B',
  'ltrPar': '\u2996',
  'ltri': '\u25C3',
  'triangleleft': '\u25C3',
  'lurdshar': '\u294A',
  'luruhar': '\u2966',
  'lvertneqq': '\u2268\uFE00',
  'lvnE': '\u2268\uFE00',
  'mDDot': '\u223A',
  'macr': '\u00AF',
  'strns': '\u00AF',
  'male': '\u2642',
  'malt': '\u2720',
  'maltese': '\u2720',
  'marker': '\u25AE',
  'mcomma': '\u2A29',
  'mcy': '\u043C',
  'mdash': '\u2014',
  'mfr': '\uD835\uDD2A',
  'mho': '\u2127',
  'micro': '\u00B5',
  'midcir': '\u2AF0',
  'minus': '\u2212',
  'minusdu': '\u2A2A',
  'mlcp': '\u2ADB',
  'models': '\u22A7',
  'mopf': '\uD835\uDD5E',
  'mscr': '\uD835\uDCC2',
  'mu': '\u03BC',
  'multimap': '\u22B8',
  'mumap': '\u22B8',
  'nGg': '\u22D9\u0338',
  'nGt': '\u226B\u20D2',
  'nLeftarrow': '\u21CD',
  'nlArr': '\u21CD',
  'nLeftrightarrow': '\u21CE',
  'nhArr': '\u21CE',
  'nLl': '\u22D8\u0338',
  'nLt': '\u226A\u20D2',
  'nRightarrow': '\u21CF',
  'nrArr': '\u21CF',
  'nVDash': '\u22AF',
  'nVdash': '\u22AE',
  'nacute': '\u0144',
  'nang': '\u2220\u20D2',
  'napE': '\u2A70\u0338',
  'napid': '\u224B\u0338',
  'napos': '\u0149',
  'natur': '\u266E',
  'natural': '\u266E',
  'ncap': '\u2A43',
  'ncaron': '\u0148',
  'ncedil': '\u0146',
  'ncongdot': '\u2A6D\u0338',
  'ncup': '\u2A42',
  'ncy': '\u043D',
  'ndash': '\u2013',
  'neArr': '\u21D7',
  'nearhk': '\u2924',
  'nedot': '\u2250\u0338',
  'nesear': '\u2928',
  'toea': '\u2928',
  'nfr': '\uD835\uDD2B',
  'nharr': '\u21AE',
  'nleftrightarrow': '\u21AE',
  'nhpar': '\u2AF2',
  'nis': '\u22FC',
  'nisd': '\u22FA',
  'njcy': '\u045A',
  'nlE': '\u2266\u0338',
  'nleqq': '\u2266\u0338',
  'nlarr': '\u219A',
  'nleftarrow': '\u219A',
  'nldr': '\u2025',
  'nopf': '\uD835\uDD5F',
  'not': '\u00AC',
  'notinE': '\u22F9\u0338',
  'notindot': '\u22F5\u0338',
  'notinvb': '\u22F7',
  'notinvc': '\u22F6',
  'notnivb': '\u22FE',
  'notnivc': '\u22FD',
  'nparsl': '\u2AFD\u20E5',
  'npart': '\u2202\u0338',
  'npolint': '\u2A14',
  'nrarr': '\u219B',
  'nrightarrow': '\u219B',
  'nrarrc': '\u2933\u0338',
  'nrarrw': '\u219D\u0338',
  'nscr': '\uD835\uDCC3',
  'nsub': '\u2284',
  'nsubE': '\u2AC5\u0338',
  'nsubseteqq': '\u2AC5\u0338',
  'nsup': '\u2285',
  'nsupE': '\u2AC6\u0338',
  'nsupseteqq': '\u2AC6\u0338',
  'ntilde': '\u00F1',
  'nu': '\u03BD',
  'num': '\u0023',
  'numero': '\u2116',
  'numsp': '\u2007',
  'nvDash': '\u22AD',
  'nvHarr': '\u2904',
  'nvap': '\u224D\u20D2',
  'nvdash': '\u22AC',
  'nvge': '\u2265\u20D2',
  'nvgt': '\u003E\u20D2',
  'nvinfin': '\u29DE',
  'nvlArr': '\u2902',
  'nvle': '\u2264\u20D2',
  'nvlt': '\u003C\u20D2',
  'nvltrie': '\u22B4\u20D2',
  'nvrArr': '\u2903',
  'nvrtrie': '\u22B5\u20D2',
  'nvsim': '\u223C\u20D2',
  'nwArr': '\u21D6',
  'nwarhk': '\u2923',
  'nwnear': '\u2927',
  'oacute': '\u00F3',
  'ocirc': '\u00F4',
  'ocy': '\u043E',
  'odblac': '\u0151',
  'odiv': '\u2A38',
  'odsold': '\u29BC',
  'oelig': '\u0153',
  'ofcir': '\u29BF',
  'ofr': '\uD835\uDD2C',
  'ogon': '\u02DB',
  'ograve': '\u00F2',
  'ogt': '\u29C1',
  'ohbar': '\u29B5',
  'olcir': '\u29BE',
  'olcross': '\u29BB',
  'olt': '\u29C0',
  'omacr': '\u014D',
  'omega': '\u03C9',
  'omicron': '\u03BF',
  'omid': '\u29B6',
  'oopf': '\uD835\uDD60',
  'opar': '\u29B7',
  'operp': '\u29B9',
  'or': '\u2228',
  'vee': '\u2228',
  'ord': '\u2A5D',
  'order': '\u2134',
  'orderof': '\u2134',
  'oscr': '\u2134',
  'ordf': '\u00AA',
  'ordm': '\u00BA',
  'origof': '\u22B6',
  'oror': '\u2A56',
  'orslope': '\u2A57',
  'orv': '\u2A5B',
  'oslash': '\u00F8',
  'osol': '\u2298',
  'otilde': '\u00F5',
  'otimesas': '\u2A36',
  'ouml': '\u00F6',
  'ovbar': '\u233D',
  'para': '\u00B6',
  'parsim': '\u2AF3',
  'parsl': '\u2AFD',
  'pcy': '\u043F',
  'percnt': '\u0025',
  'period': '\u002E',
  'permil': '\u2030',
  'pertenk': '\u2031',
  'pfr': '\uD835\uDD2D',
  'phi': '\u03C6',
  'phiv': '\u03D5',
  'straightphi': '\u03D5',
  'varphi': '\u03D5',
  'phone': '\u260E',
  'pi': '\u03C0',
  'piv': '\u03D6',
  'varpi': '\u03D6',
  'planckh': '\u210E',
  'plus': '\u002B',
  'plusacir': '\u2A23',
  'pluscir': '\u2A22',
  'plusdu': '\u2A25',
  'pluse': '\u2A72',
  'plussim': '\u2A26',
  'plustwo': '\u2A27',
  'pointint': '\u2A15',
  'popf': '\uD835\uDD61',
  'pound': '\u00A3',
  'prE': '\u2AB3',
  'prap': '\u2AB7',
  'precapprox': '\u2AB7',
  'precnapprox': '\u2AB9',
  'prnap': '\u2AB9',
  'precneqq': '\u2AB5',
  'prnE': '\u2AB5',
  'precnsim': '\u22E8',
  'prnsim': '\u22E8',
  'prime': '\u2032',
  'profalar': '\u232E',
  'profline': '\u2312',
  'profsurf': '\u2313',
  'prurel': '\u22B0',
  'pscr': '\uD835\uDCC5',
  'psi': '\u03C8',
  'puncsp': '\u2008',
  'qfr': '\uD835\uDD2E',
  'qopf': '\uD835\uDD62',
  'qprime': '\u2057',
  'qscr': '\uD835\uDCC6',
  'quatint': '\u2A16',
  'quest': '\u003F',
  'rAtail': '\u291C',
  'rHar': '\u2964',
  'race': '\u223D\u0331',
  'racute': '\u0155',
  'raemptyv': '\u29B3',
  'rangd': '\u2992',
  'range': '\u29A5',
  'raquo': '\u00BB',
  'rarrap': '\u2975',
  'rarrbfs': '\u2920',
  'rarrc': '\u2933',
  'rarrfs': '\u291E',
  'rarrpl': '\u2945',
  'rarrsim': '\u2974',
  'rarrtl': '\u21A3',
  'rightarrowtail': '\u21A3',
  'rarrw': '\u219D',
  'rightsquigarrow': '\u219D',
  'ratail': '\u291A',
  'ratio': '\u2236',
  'rbbrk': '\u2773',
  'rbrace': '\u007D',
  'rcub': '\u007D',
  'rbrack': '\u005D',
  'rsqb': '\u005D',
  'rbrke': '\u298C',
  'rbrksld': '\u298E',
  'rbrkslu': '\u2990',
  'rcaron': '\u0159',
  'rcedil': '\u0157',
  'rcy': '\u0440',
  'rdca': '\u2937',
  'rdldhar': '\u2969',
  'rdsh': '\u21B3',
  'rect': '\u25AD',
  'rfisht': '\u297D',
  'rfr': '\uD835\uDD2F',
  'rharul': '\u296C',
  'rho': '\u03C1',
  'rhov': '\u03F1',
  'varrho': '\u03F1',
  'rightrightarrows': '\u21C9',
  'rrarr': '\u21C9',
  'rightthreetimes': '\u22CC',
  'rthree': '\u22CC',
  'ring': '\u02DA',
  'rlm': '\u200F',
  'rmoust': '\u23B1',
  'rmoustache': '\u23B1',
  'rnmid': '\u2AEE',
  'roang': '\u27ED',
  'roarr': '\u21FE',
  'ropar': '\u2986',
  'ropf': '\uD835\uDD63',
  'roplus': '\u2A2E',
  'rotimes': '\u2A35',
  'rpar': '\u0029',
  'rpargt': '\u2994',
  'rppolint': '\u2A12',
  'rsaquo': '\u203A',
  'rscr': '\uD835\uDCC7',
  'rtimes': '\u22CA',
  'rtri': '\u25B9',
  'triangleright': '\u25B9',
  'rtriltri': '\u29CE',
  'ruluhar': '\u2968',
  'rx': '\u211E',
  'sacute': '\u015B',
  'scE': '\u2AB4',
  'scap': '\u2AB8',
  'succapprox': '\u2AB8',
  'scaron': '\u0161',
  'scedil': '\u015F',
  'scirc': '\u015D',
  'scnE': '\u2AB6',
  'succneqq': '\u2AB6',
  'scnap': '\u2ABA',
  'succnapprox': '\u2ABA',
  'scnsim': '\u22E9',
  'succnsim': '\u22E9',
  'scpolint': '\u2A13',
  'scy': '\u0441',
  'sdot': '\u22C5',
  'sdote': '\u2A66',
  'seArr': '\u21D8',
  'sect': '\u00A7',
  'semi': '\u003B',
  'seswar': '\u2929',
  'tosa': '\u2929',
  'sext': '\u2736',
  'sfr': '\uD835\uDD30',
  'sharp': '\u266F',
  'shchcy': '\u0449',
  'shcy': '\u0448',
  'shy': '\u00AD',
  'sigma': '\u03C3',
  'sigmaf': '\u03C2',
  'sigmav': '\u03C2',
  'varsigma': '\u03C2',
  'simdot': '\u2A6A',
  'simg': '\u2A9E',
  'simgE': '\u2AA0',
  'siml': '\u2A9D',
  'simlE': '\u2A9F',
  'simne': '\u2246',
  'simplus': '\u2A24',
  'simrarr': '\u2972',
  'smashp': '\u2A33',
  'smeparsl': '\u29E4',
  'smile': '\u2323',
  'ssmile': '\u2323',
  'smt': '\u2AAA',
  'smte': '\u2AAC',
  'smtes': '\u2AAC\uFE00',
  'softcy': '\u044C',
  'sol': '\u002F',
  'solb': '\u29C4',
  'solbar': '\u233F',
  'sopf': '\uD835\uDD64',
  'spades': '\u2660',
  'spadesuit': '\u2660',
  'sqcaps': '\u2293\uFE00',
  'sqcups': '\u2294\uFE00',
  'sscr': '\uD835\uDCC8',
  'star': '\u2606',
  'sub': '\u2282',
  'subset': '\u2282',
  'subE': '\u2AC5',
  'subseteqq': '\u2AC5',
  'subdot': '\u2ABD',
  'subedot': '\u2AC3',
  'submult': '\u2AC1',
  'subnE': '\u2ACB',
  'subsetneqq': '\u2ACB',
  'subne': '\u228A',
  'subsetneq': '\u228A',
  'subplus': '\u2ABF',
  'subrarr': '\u2979',
  'subsim': '\u2AC7',
  'subsub': '\u2AD5',
  'subsup': '\u2AD3',
  'sung': '\u266A',
  'sup1': '\u00B9',
  'sup2': '\u00B2',
  'sup3': '\u00B3',
  'supE': '\u2AC6',
  'supseteqq': '\u2AC6',
  'supdot': '\u2ABE',
  'supdsub': '\u2AD8',
  'supedot': '\u2AC4',
  'suphsol': '\u27C9',
  'suphsub': '\u2AD7',
  'suplarr': '\u297B',
  'supmult': '\u2AC2',
  'supnE': '\u2ACC',
  'supsetneqq': '\u2ACC',
  'supne': '\u228B',
  'supsetneq': '\u228B',
  'supplus': '\u2AC0',
  'supsim': '\u2AC8',
  'supsub': '\u2AD4',
  'supsup': '\u2AD6',
  'swArr': '\u21D9',
  'swnwar': '\u292A',
  'szlig': '\u00DF',
  'target': '\u2316',
  'tau': '\u03C4',
  'tcaron': '\u0165',
  'tcedil': '\u0163',
  'tcy': '\u0442',
  'telrec': '\u2315',
  'tfr': '\uD835\uDD31',
  'theta': '\u03B8',
  'thetasym': '\u03D1',
  'thetav': '\u03D1',
  'vartheta': '\u03D1',
  'thorn': '\u00FE',
  'times': '\u00D7',
  'timesbar': '\u2A31',
  'timesd': '\u2A30',
  'topbot': '\u2336',
  'topcir': '\u2AF1',
  'topf': '\uD835\uDD65',
  'topfork': '\u2ADA',
  'tprime': '\u2034',
  'triangle': '\u25B5',
  'utri': '\u25B5',
  'triangleq': '\u225C',
  'trie': '\u225C',
  'tridot': '\u25EC',
  'triminus': '\u2A3A',
  'triplus': '\u2A39',
  'trisb': '\u29CD',
  'tritime': '\u2A3B',
  'trpezium': '\u23E2',
  'tscr': '\uD835\uDCC9',
  'tscy': '\u0446',
  'tshcy': '\u045B',
  'tstrok': '\u0167',
  'uHar': '\u2963',
  'uacute': '\u00FA',
  'ubrcy': '\u045E',
  'ubreve': '\u016D',
  'ucirc': '\u00FB',
  'ucy': '\u0443',
  'udblac': '\u0171',
  'ufisht': '\u297E',
  'ufr': '\uD835\uDD32',
  'ugrave': '\u00F9',
  'uhblk': '\u2580',
  'ulcorn': '\u231C',
  'ulcorner': '\u231C',
  'ulcrop': '\u230F',
  'ultri': '\u25F8',
  'umacr': '\u016B',
  'uogon': '\u0173',
  'uopf': '\uD835\uDD66',
  'upsi': '\u03C5',
  'upsilon': '\u03C5',
  'upuparrows': '\u21C8',
  'uuarr': '\u21C8',
  'urcorn': '\u231D',
  'urcorner': '\u231D',
  'urcrop': '\u230E',
  'uring': '\u016F',
  'urtri': '\u25F9',
  'uscr': '\uD835\uDCCA',
  'utdot': '\u22F0',
  'utilde': '\u0169',
  'uuml': '\u00FC',
  'uwangle': '\u29A7',
  'vBar': '\u2AE8',
  'vBarv': '\u2AE9',
  'vangrt': '\u299C',
  'varsubsetneq': '\u228A\uFE00',
  'vsubne': '\u228A\uFE00',
  'varsubsetneqq': '\u2ACB\uFE00',
  'vsubnE': '\u2ACB\uFE00',
  'varsupsetneq': '\u228B\uFE00',
  'vsupne': '\u228B\uFE00',
  'varsupsetneqq': '\u2ACC\uFE00',
  'vsupnE': '\u2ACC\uFE00',
  'vcy': '\u0432',
  'veebar': '\u22BB',
  'veeeq': '\u225A',
  'vellip': '\u22EE',
  'vfr': '\uD835\uDD33',
  'vopf': '\uD835\uDD67',
  'vscr': '\uD835\uDCCB',
  'vzigzag': '\u299A',
  'wcirc': '\u0175',
  'wedbar': '\u2A5F',
  'wedgeq': '\u2259',
  'weierp': '\u2118',
  'wp': '\u2118',
  'wfr': '\uD835\uDD34',
  'wopf': '\uD835\uDD68',
  'wscr': '\uD835\uDCCC',
  'xfr': '\uD835\uDD35',
  'xi': '\u03BE',
  'xnis': '\u22FB',
  'xopf': '\uD835\uDD69',
  'xscr': '\uD835\uDCCD',
  'yacute': '\u00FD',
  'yacy': '\u044F',
  'ycirc': '\u0177',
  'ycy': '\u044B',
  'yen': '\u00A5',
  'yfr': '\uD835\uDD36',
  'yicy': '\u0457',
  'yopf': '\uD835\uDD6A',
  'yscr': '\uD835\uDCCE',
  'yucy': '\u044E',
  'yuml': '\u00FF',
  'zacute': '\u017A',
  'zcaron': '\u017E',
  'zcy': '\u0437',
  'zdot': '\u017C',
  'zeta': '\u03B6',
  'zfr': '\uD835\uDD37',
  'zhcy': '\u0436',
  'zigrarr': '\u21DD',
  'zopf': '\uD835\uDD6B',
  'zscr': '\uD835\uDCCF',
  'zwj': '\u200D',
  'zwnj': '\u200C'
};
const NGSP_UNICODE = '\uE500';
NAMED_ENTITIES['ngsp'] = NGSP_UNICODE;

class TokenizeResult {
  tokens;
  errors;
  nonNormalizedIcuExpressions;
  constructor(tokens, errors, nonNormalizedIcuExpressions) {
    this.tokens = tokens;
    this.errors = errors;
    this.nonNormalizedIcuExpressions = nonNormalizedIcuExpressions;
  }
}
function tokenize(source, url, getTagDefinition, options = {}) {
  const tokenizer = new _Tokenizer(new ParseSourceFile(source, url), getTagDefinition, options);
  tokenizer.tokenize();
  return new TokenizeResult(mergeTextTokens(tokenizer.tokens), tokenizer.errors, tokenizer.nonNormalizedIcuExpressions);
}
const _CR_OR_CRLF_REGEXP = /\r\n?/g;
function _unexpectedCharacterErrorMsg(charCode) {
  const char = charCode === $EOF ? 'EOF' : String.fromCharCode(charCode);
  return `Unexpected character "${char}"`;
}
function _unknownEntityErrorMsg(entitySrc) {
  return `Unknown entity "${entitySrc}" - use the "&#<decimal>;" or  "&#x<hex>;" syntax`;
}
function _unparsableEntityErrorMsg(type, entityStr) {
  return `Unable to parse entity "${entityStr}" - ${type} character reference entities must end with ";"`;
}
var CharacterReferenceType;
(function (CharacterReferenceType) {
  CharacterReferenceType["HEX"] = "hexadecimal";
  CharacterReferenceType["DEC"] = "decimal";
})(CharacterReferenceType || (CharacterReferenceType = {}));
const SUPPORTED_BLOCKS = ['@if', '@else', '@for', '@switch', '@case', '@default', '@empty', '@defer', '@placeholder', '@loading', '@error', '@content'];
const INTERPOLATION = {
  start: '{{',
  end: '}}'
};
const DEFAULT_NEVER_PATTERN = /^default[^\S\r\n]+never/;
const ELSE_IF_PATTERN = /^else[^\S\r\n]+if/;
class _Tokenizer {
  _getTagDefinition;
  _cursor;
  _tokenizeIcu;
  _leadingTriviaCodePoints;
  _currentTokenStart = null;
  _currentTokenType = null;
  _expansionCaseStack = [];
  _openDirectiveCount = 0;
  _inInterpolation = false;
  _preserveLineEndings;
  _i18nNormalizeLineEndingsInICUs;
  _tokenizeBlocks;
  _tokenizeLet;
  _selectorlessEnabled;
  tokens = [];
  errors = [];
  nonNormalizedIcuExpressions = [];
  constructor(_file, _getTagDefinition, options) {
    this._getTagDefinition = _getTagDefinition;
    this._tokenizeIcu = options.tokenizeExpansionForms || false;
    this._leadingTriviaCodePoints = options.leadingTriviaChars && options.leadingTriviaChars.map(c => c.codePointAt(0) || 0);
    const range = options.range || {
      endPos: _file.content.length,
      startPos: 0,
      startLine: 0,
      startCol: 0
    };
    this._cursor = options.escapedString ? new EscapedCharacterCursor(_file, range) : new PlainCharacterCursor(_file, range);
    this._preserveLineEndings = options.preserveLineEndings || false;
    this._i18nNormalizeLineEndingsInICUs = options.i18nNormalizeLineEndingsInICUs || false;
    this._tokenizeBlocks = options.tokenizeBlocks ?? true;
    this._tokenizeLet = options.tokenizeLet ?? true;
    this._selectorlessEnabled = options.selectorlessEnabled ?? false;
    try {
      this._cursor.init();
    } catch (e) {
      this.handleError(e);
    }
  }
  _processCarriageReturns(content) {
    if (this._preserveLineEndings) {
      return content;
    }
    return content.replace(_CR_OR_CRLF_REGEXP, '\n');
  }
  tokenize() {
    while (this._cursor.peek() !== $EOF) {
      const start = this._cursor.clone();
      try {
        if (this._attemptCharCode($LT)) {
          if (this._attemptCharCode($BANG)) {
            if (this._attemptCharCode($LBRACKET)) {
              this._consumeCdata(start);
            } else if (this._attemptCharCode($MINUS)) {
              this._consumeComment(start);
            } else {
              this._consumeDocType(start);
            }
          } else if (this._attemptCharCode($SLASH)) {
            this._consumeTagClose(start);
          } else if (this._attemptCharCode($QUESTION)) {
            this._consumeProcessingInstruction(start);
          } else {
            this._consumeTagOpen(start);
          }
        } else if (this._tokenizeLet && this._cursor.peek() === $AT && !this._inInterpolation && this._isLetStart()) {
          this._consumeLetDeclaration(start);
        } else if (this._tokenizeBlocks && this._isBlockStart()) {
          this._consumeBlockStart(start);
        } else if (this._tokenizeBlocks && !this._inInterpolation && !this._isInExpansionCase() && !this._isInExpansionForm() && this._attemptCharCode($RBRACE)) {
          this._consumeBlockEnd(start);
        } else if (!(this._tokenizeIcu && this._tokenizeExpansionForm())) {
          this._consumeWithInterpolation(5, 8, () => this._isTextEnd(), () => this._isTagStart());
        }
      } catch (e) {
        this.handleError(e);
      }
    }
    this._beginToken(43);
    this._endToken([]);
  }
  _getBlockName() {
    let spacesInNameAllowed = false;
    const nameCursor = this._cursor.clone();
    this._attemptCharCodeUntilFn(code => {
      if (isWhitespace(code)) {
        return !spacesInNameAllowed;
      }
      if (isBlockNameChar(code)) {
        spacesInNameAllowed = true;
        return false;
      }
      return true;
    });
    let result = this._cursor.getChars(nameCursor).trim();
    if (ELSE_IF_PATTERN.test(result)) {
      result = 'else if';
    } else if (DEFAULT_NEVER_PATTERN.test(result)) {
      result = 'default never';
    }
    return result;
  }
  _consumeBlockStart(start) {
    this._requireCharCode($AT);
    this._beginToken(25, start);
    const startToken = this._endToken([this._getBlockName()]);
    if (this._cursor.peek() === $LPAREN) {
      this._cursor.advance();
      this._consumeBlockParameters();
      this._attemptCharCodeUntilFn(isNotWhitespace);
      if (this._attemptCharCode($RPAREN)) {
        this._attemptCharCodeUntilFn(isNotWhitespace);
      } else {
        startToken.type = 29;
        return;
      }
    }
    if (startToken.parts[0] === 'default never' && this._attemptCharCode($SEMICOLON)) {
      this._beginToken(26);
      this._endToken([]);
      this._beginToken(27);
      this._endToken([]);
      return;
    }
    if (this._attemptCharCode($LBRACE)) {
      this._beginToken(26);
      this._endToken([]);
    } else if (this._isBlockStart() && (startToken.parts[0] === 'case' || startToken.parts[0] === 'default')) {
      this._beginToken(26);
      this._endToken([]);
      this._beginToken(27);
      this._endToken([]);
    } else {
      startToken.type = 29;
    }
  }
  _consumeBlockEnd(start) {
    this._beginToken(27, start);
    this._endToken([]);
  }
  _consumeBlockParameters() {
    this._attemptCharCodeUntilFn(isBlockParameterChar);
    while (this._cursor.peek() !== $RPAREN && this._cursor.peek() !== $EOF) {
      this._beginToken(28);
      const start = this._cursor.clone();
      let inQuote = null;
      let openParens = 0;
      while (this._cursor.peek() !== $SEMICOLON && this._cursor.peek() !== $EOF || inQuote !== null) {
        const char = this._cursor.peek();
        if (char === $BACKSLASH) {
          this._cursor.advance();
        } else if (char === inQuote) {
          inQuote = null;
        } else if (inQuote === null && isQuote(char)) {
          inQuote = char;
        } else if (char === $LPAREN && inQuote === null) {
          openParens++;
        } else if (char === $RPAREN && inQuote === null) {
          if (openParens === 0) {
            break;
          } else if (openParens > 0) {
            openParens--;
          }
        }
        this._cursor.advance();
      }
      this._endToken([this._cursor.getChars(start)]);
      this._attemptCharCodeUntilFn(isBlockParameterChar);
    }
  }
  _consumeLetDeclaration(start) {
    this._requireStr('@let');
    this._beginToken(30, start);
    if (isWhitespace(this._cursor.peek())) {
      this._attemptCharCodeUntilFn(isNotWhitespace);
    } else {
      const token = this._endToken([this._cursor.getChars(start)]);
      token.type = 33;
      return;
    }
    const startToken = this._endToken([this._getLetDeclarationName()]);
    this._attemptCharCodeUntilFn(isNotWhitespace);
    if (!this._attemptCharCode($EQ)) {
      startToken.type = 33;
      return;
    }
    this._attemptCharCodeUntilFn(code => isNotWhitespace(code) && !isNewLine(code));
    this._consumeLetDeclarationValue();
    const endChar = this._cursor.peek();
    if (endChar === $SEMICOLON) {
      this._beginToken(32);
      this._cursor.advance();
      this._endToken([]);
    } else {
      startToken.type = 33;
      startToken.sourceSpan = this._cursor.getSpan(start);
    }
  }
  _getLetDeclarationName() {
    const nameCursor = this._cursor.clone();
    let allowDigit = false;
    this._attemptCharCodeUntilFn(code => {
      if (isAsciiLetter(code) || code === $$ || code === $_ || allowDigit && isDigit(code)) {
        allowDigit = true;
        return false;
      }
      return true;
    });
    return this._cursor.getChars(nameCursor).trim();
  }
  _consumeLetDeclarationValue() {
    const start = this._cursor.clone();
    this._beginToken(31, start);
    this._attemptUntilIgnoreQuotes(char => char === $SEMICOLON);
    this._endToken([this._cursor.getChars(start)]);
  }
  _tokenizeExpansionForm() {
    if (this.isExpansionFormStart()) {
      this._consumeExpansionFormStart();
      return true;
    }
    if (isExpansionCaseStart(this._cursor.peek()) && this._isInExpansionForm()) {
      this._consumeExpansionCaseStart();
      return true;
    }
    if (this._cursor.peek() === $RBRACE) {
      if (this._isInExpansionCase()) {
        this._consumeExpansionCaseEnd();
        return true;
      }
      if (this._isInExpansionForm()) {
        this._consumeExpansionFormEnd();
        return true;
      }
    }
    return false;
  }
  _beginToken(type, start = this._cursor.clone()) {
    this._currentTokenStart = start;
    this._currentTokenType = type;
  }
  _endToken(parts, end) {
    if (this._currentTokenStart === null) {
      throw new ParseError(this._cursor.getSpan(end), 'Programming error - attempted to end a token when there was no start to the token');
    }
    if (this._currentTokenType === null) {
      throw new ParseError(this._cursor.getSpan(this._currentTokenStart), 'Programming error - attempted to end a token which has no token type');
    }
    const token = {
      type: this._currentTokenType,
      parts,
      sourceSpan: (end ?? this._cursor).getSpan(this._currentTokenStart, this._leadingTriviaCodePoints)
    };
    this.tokens.push(token);
    this._currentTokenStart = null;
    this._currentTokenType = null;
    return token;
  }
  _createError(msg, span) {
    if (this._isInExpansionForm()) {
      msg += ` (Do you have an unescaped "{" in your template? Use "{{ '{' }}") to escape it.)`;
    }
    const error = new ParseError(span, msg);
    this._currentTokenStart = null;
    this._currentTokenType = null;
    return error;
  }
  handleError(e) {
    if (e instanceof CursorError) {
      e = this._createError(e.msg, this._cursor.getSpan(e.cursor));
    }
    if (e instanceof ParseError) {
      this.errors.push(e);
    } else {
      throw e;
    }
  }
  _attemptCharCode(charCode) {
    if (this._cursor.peek() === charCode) {
      this._cursor.advance();
      return true;
    }
    return false;
  }
  _attemptCharCodeCaseInsensitive(charCode) {
    if (compareCharCodeCaseInsensitive(this._cursor.peek(), charCode)) {
      this._cursor.advance();
      return true;
    }
    return false;
  }
  _requireCharCode(charCode) {
    const location = this._cursor.clone();
    if (!this._attemptCharCode(charCode)) {
      throw this._createError(_unexpectedCharacterErrorMsg(this._cursor.peek()), this._cursor.getSpan(location));
    }
  }
  _attemptStr(chars) {
    const len = chars.length;
    if (this._cursor.charsLeft() < len) {
      return false;
    }
    const initialPosition = this._cursor.clone();
    for (let i = 0; i < len; i++) {
      if (!this._attemptCharCode(chars.charCodeAt(i))) {
        this._cursor = initialPosition;
        return false;
      }
    }
    return true;
  }
  _attemptStrCaseInsensitive(chars) {
    for (let i = 0; i < chars.length; i++) {
      if (!this._attemptCharCodeCaseInsensitive(chars.charCodeAt(i))) {
        return false;
      }
    }
    return true;
  }
  _requireStr(chars) {
    const location = this._cursor.clone();
    if (!this._attemptStr(chars)) {
      throw this._createError(_unexpectedCharacterErrorMsg(this._cursor.peek()), this._cursor.getSpan(location));
    }
  }
  _attemptCharCodeUntilFn(predicate) {
    while (!predicate(this._cursor.peek())) {
      this._cursor.advance();
    }
  }
  _requireCharCodeUntilFn(predicate, len) {
    const start = this._cursor.clone();
    this._attemptCharCodeUntilFn(predicate);
    if (this._cursor.diff(start) < len) {
      throw this._createError(_unexpectedCharacterErrorMsg(this._cursor.peek()), this._cursor.getSpan(start));
    }
  }
  _attemptUntilChar(char) {
    while (this._cursor.peek() !== char) {
      this._cursor.advance();
    }
  }
  _attemptUntilIgnoreQuotes(predicate) {
    while (this._cursor.peek() !== $EOF) {
      const char = this._cursor.peek();
      if (predicate(char)) {
        break;
      }
      if (isQuote(char)) {
        this._cursor.advance();
        this._attemptCharCodeUntilFn(inner => {
          if (inner === $BACKSLASH) {
            this._cursor.advance();
            return false;
          }
          return inner === char;
        });
      }
      this._cursor.advance();
    }
  }
  _readChar() {
    const char = String.fromCodePoint(this._cursor.peek());
    this._cursor.advance();
    return char;
  }
  _peekStr(chars) {
    const len = chars.length;
    if (this._cursor.charsLeft() < len) {
      return false;
    }
    const cursor = this._cursor.clone();
    for (let i = 0; i < len; i++) {
      if (cursor.peek() !== chars.charCodeAt(i)) {
        return false;
      }
      cursor.advance();
    }
    return true;
  }
  _isBlockStart() {
    return this._cursor.peek() === $AT && SUPPORTED_BLOCKS.some(blockName => this._peekStr(blockName));
  }
  _isLetStart() {
    return this._cursor.peek() === $AT && this._peekStr('@let');
  }
  _consumeEntity(textTokenType) {
    this._beginToken(9);
    const start = this._cursor.clone();
    this._cursor.advance();
    if (this._attemptCharCode($HASH)) {
      const isHex = this._attemptCharCode($x) || this._attemptCharCode($X);
      const codeStart = this._cursor.clone();
      this._attemptCharCodeUntilFn(isDigitEntityEnd);
      if (this._cursor.peek() != $SEMICOLON) {
        this._cursor.advance();
        const entityType = isHex ? CharacterReferenceType.HEX : CharacterReferenceType.DEC;
        throw this._createError(_unparsableEntityErrorMsg(entityType, this._cursor.getChars(start)), this._cursor.getSpan());
      }
      const strNum = this._cursor.getChars(codeStart);
      this._cursor.advance();
      try {
        const charCode = parseInt(strNum, isHex ? 16 : 10);
        this._endToken([String.fromCodePoint(charCode), this._cursor.getChars(start)]);
      } catch {
        throw this._createError(_unknownEntityErrorMsg(this._cursor.getChars(start)), this._cursor.getSpan());
      }
    } else {
      const nameStart = this._cursor.clone();
      this._attemptCharCodeUntilFn(isNamedEntityEnd);
      if (this._cursor.peek() != $SEMICOLON) {
        this._beginToken(textTokenType, start);
        this._cursor = nameStart;
        this._endToken(['&']);
      } else {
        const name = this._cursor.getChars(nameStart);
        this._cursor.advance();
        const char = Object.hasOwn(NAMED_ENTITIES, name) && NAMED_ENTITIES[name];
        if (!char) {
          throw this._createError(_unknownEntityErrorMsg(name), this._cursor.getSpan(start));
        }
        this._endToken([char, `&${name};`]);
      }
    }
  }
  _consumeRawText(consumeEntities, endMarkerPredicate) {
    this._beginToken(consumeEntities ? 6 : 7);
    const parts = [];
    while (true) {
      const tagCloseStart = this._cursor.clone();
      const foundEndMarker = endMarkerPredicate();
      this._cursor = tagCloseStart;
      if (foundEndMarker) {
        break;
      }
      if (consumeEntities && this._cursor.peek() === $AMPERSAND) {
        this._endToken([this._processCarriageReturns(parts.join(''))]);
        parts.length = 0;
        this._consumeEntity(6);
        this._beginToken(6);
      } else {
        parts.push(this._readChar());
      }
    }
    this._endToken([this._processCarriageReturns(parts.join(''))]);
  }
  _consumeComment(start) {
    this._beginToken(10, start);
    this._requireCharCode($MINUS);
    this._endToken([]);
    this._consumeRawText(false, () => this._attemptStr('-->'));
    this._beginToken(11);
    this._requireStr('-->');
    this._endToken([]);
  }
  _consumeCdata(start) {
    this._beginToken(13, start);
    this._requireStr('CDATA[');
    this._endToken([]);
    this._consumeRawText(false, () => this._attemptStr(']]>'));
    this._beginToken(14);
    this._requireStr(']]>');
    this._endToken([]);
  }
  _consumeDocType(start) {
    this._beginToken(19, start);
    const contentStart = this._cursor.clone();
    this._attemptUntilChar($GT);
    const content = this._cursor.getChars(contentStart);
    this._cursor.advance();
    this._endToken([content]);
  }
  _consumeProcessingInstruction(start) {
    this._beginToken(42, start);
    const contentStart = this._cursor.clone();
    this._attemptUntilIgnoreQuotes(char => char === $QUESTION || char === $GT);
    const endChar = this._cursor.peek();
    const content = this._cursor.getChars(contentStart);
    this._cursor.advance();
    if (endChar === $QUESTION) {
      this._requireCharCode($GT);
    }
    this._endToken([content]);
  }
  _consumePrefixAndName(endPredicate) {
    const nameOrPrefixStart = this._cursor.clone();
    let prefix = '';
    while (this._cursor.peek() !== $COLON && !isPrefixEnd(this._cursor.peek())) {
      this._cursor.advance();
    }
    let nameStart;
    if (this._cursor.peek() === $COLON) {
      prefix = this._cursor.getChars(nameOrPrefixStart);
      this._cursor.advance();
      nameStart = this._cursor.clone();
    } else {
      nameStart = nameOrPrefixStart;
    }
    this._requireCharCodeUntilFn(endPredicate, prefix === '' ? 0 : 1);
    const name = this._cursor.getChars(nameStart);
    return [prefix, name];
  }
  _consumeSingleLineComment(start) {
    const contentStart = this._cursor.clone();
    this._attemptCharCodeUntilFn(code => isNewLine(code) || code === $EOF);
    const spanEnd = this._cursor.clone();
    const content = spanEnd.getChars(contentStart);
    this._beginToken(12, start);
    this._endToken([content, 'single'], spanEnd);
    this._attemptCharCodeUntilFn(isNotWhitespace);
  }
  _consumeMultiLineComment(start) {
    const contentStart = this._cursor.clone();
    this._attemptCharCodeUntilFn(code => {
      if (code === $EOF) {
        return true;
      }
      if (code === $STAR) {
        const next = this._cursor.clone();
        next.advance();
        return next.peek() === $SLASH;
      }
      return false;
    });
    const contentEnd = this._cursor.clone();
    const content = contentEnd.getChars(contentStart);
    let spanEnd = contentEnd;
    if (this._attemptStr('*/')) {
      spanEnd = this._cursor.clone();
      this._attemptCharCodeUntilFn(isNotWhitespace);
    }
    this._beginToken(12, start);
    this._endToken([content, 'multi'], spanEnd);
  }
  _consumeTagOpen(start) {
    let tagName;
    let prefix;
    let closingTagName;
    let openToken;
    try {
      if (this._selectorlessEnabled && isSelectorlessNameStart(this._cursor.peek())) {
        openToken = this._consumeComponentOpenStart(start);
        [closingTagName, prefix, tagName] = openToken.parts;
        if (prefix) {
          closingTagName += `:${prefix}`;
        }
        if (tagName) {
          closingTagName += `:${tagName}`;
        }
        this._attemptCharCodeUntilFn(isNotWhitespace);
      } else {
        if (!isAsciiLetter(this._cursor.peek())) {
          throw this._createError(_unexpectedCharacterErrorMsg(this._cursor.peek()), this._cursor.getSpan(start));
        }
        openToken = this._consumeTagOpenStart(start);
        prefix = openToken.parts[0];
        tagName = closingTagName = openToken.parts[1];
        this._attemptCharCodeUntilFn(isNotWhitespace);
      }
      while (true) {
        const commentStart = this._cursor.clone();
        if (this._attemptStr('//')) {
          this._consumeSingleLineComment(commentStart);
          continue;
        }
        if (this._attemptStr('/*')) {
          this._consumeMultiLineComment(commentStart);
          continue;
        }
        if (isAttributeTerminator(this._cursor.peek())) {
          break;
        }
        if (this._selectorlessEnabled && this._cursor.peek() === $AT) {
          const start = this._cursor.clone();
          const nameStart = start.clone();
          nameStart.advance();
          if (isSelectorlessNameStart(nameStart.peek())) {
            this._consumeDirective(start, nameStart);
          }
        } else {
          this._consumeAttribute();
        }
      }
      if (openToken.type === 34) {
        this._consumeComponentOpenEnd();
      } else {
        this._consumeTagOpenEnd();
      }
    } catch (e) {
      if (e instanceof ParseError) {
        if (openToken) {
          openToken.type = openToken.type === 34 ? 38 : 4;
        } else {
          this._beginToken(5, start);
          this._endToken(['<']);
        }
        return;
      }
      throw e;
    }
    const contentTokenType = this._getTagDefinition(tagName).getContentType(prefix);
    if (contentTokenType === TagContentType.RAW_TEXT) {
      this._consumeRawTextWithTagClose(openToken, closingTagName, false);
    } else if (contentTokenType === TagContentType.ESCAPABLE_RAW_TEXT) {
      this._consumeRawTextWithTagClose(openToken, closingTagName, true);
    }
  }
  _consumeRawTextWithTagClose(openToken, tagName, consumeEntities) {
    this._consumeRawText(consumeEntities, () => {
      if (!this._attemptCharCode($LT)) return false;
      if (!this._attemptCharCode($SLASH)) return false;
      this._attemptCharCodeUntilFn(isNotWhitespace);
      if (!this._attemptStrCaseInsensitive(tagName)) return false;
      this._attemptCharCodeUntilFn(isNotWhitespace);
      return this._attemptCharCode($GT);
    });
    this._beginToken(openToken.type === 34 ? 37 : 3);
    this._requireCharCodeUntilFn(code => code === $GT, 3);
    this._cursor.advance();
    this._endToken(openToken.parts);
  }
  _consumeTagOpenStart(start) {
    this._beginToken(0, start);
    const parts = this._consumePrefixAndName(isNameEnd);
    return this._endToken(parts);
  }
  _consumeComponentOpenStart(start) {
    this._beginToken(34, start);
    const parts = this._consumeComponentName();
    return this._endToken(parts);
  }
  _consumeComponentName() {
    const nameStart = this._cursor.clone();
    while (isSelectorlessNameChar(this._cursor.peek())) {
      this._cursor.advance();
    }
    const name = this._cursor.getChars(nameStart);
    let prefix = '';
    let tagName = '';
    if (this._cursor.peek() === $COLON) {
      this._cursor.advance();
      [prefix, tagName] = this._consumePrefixAndName(isNameEnd);
    }
    return [name, prefix, tagName];
  }
  _consumeAttribute() {
    this._consumeAttributeName();
    this._attemptCharCodeUntilFn(isNotWhitespace);
    if (this._attemptCharCode($EQ)) {
      this._attemptCharCodeUntilFn(isNotWhitespace);
      this._consumeAttributeValue();
    }
    this._attemptCharCodeUntilFn(isNotWhitespace);
  }
  _consumeAttributeName() {
    const attrNameStart = this._cursor.peek();
    if (attrNameStart === $SQ || attrNameStart === $DQ) {
      throw this._createError(_unexpectedCharacterErrorMsg(attrNameStart), this._cursor.getSpan());
    }
    this._beginToken(15);
    let nameEndPredicate;
    if (this._openDirectiveCount > 0) {
      let openParens = 0;
      nameEndPredicate = code => {
        if (this._openDirectiveCount > 0) {
          if (code === $LPAREN) {
            openParens++;
          } else if (code === $RPAREN) {
            if (openParens === 0) {
              return true;
            }
            openParens--;
          }
        }
        return isNameEnd(code);
      };
    } else if (attrNameStart === $LBRACKET) {
      let openBrackets = 0;
      nameEndPredicate = code => {
        if (code === $LBRACKET) {
          openBrackets++;
        } else if (code === $RBRACKET) {
          openBrackets--;
        }
        return openBrackets <= 0 ? isNameEnd(code) : isNewLine(code);
      };
    } else {
      nameEndPredicate = isNameEnd;
    }
    const prefixAndName = this._consumePrefixAndName(nameEndPredicate);
    this._endToken(prefixAndName);
  }
  _consumeAttributeValue() {
    if (this._cursor.peek() === $SQ || this._cursor.peek() === $DQ) {
      const quoteChar = this._cursor.peek();
      this._consumeQuote(quoteChar);
      const endPredicate = () => this._cursor.peek() === quoteChar;
      this._consumeWithInterpolation(17, 18, endPredicate, endPredicate);
      this._consumeQuote(quoteChar);
    } else {
      const endPredicate = () => isNameEnd(this._cursor.peek());
      this._consumeWithInterpolation(17, 18, endPredicate, endPredicate);
    }
  }
  _consumeQuote(quoteChar) {
    this._beginToken(16);
    this._requireCharCode(quoteChar);
    this._endToken([String.fromCodePoint(quoteChar)]);
  }
  _consumeTagOpenEnd() {
    const tokenType = this._attemptCharCode($SLASH) ? 2 : 1;
    this._beginToken(tokenType);
    this._requireCharCode($GT);
    this._endToken([]);
  }
  _consumeComponentOpenEnd() {
    const tokenType = this._attemptCharCode($SLASH) ? 36 : 35;
    this._beginToken(tokenType);
    this._requireCharCode($GT);
    this._endToken([]);
  }
  _consumeTagClose(start) {
    if (this._selectorlessEnabled) {
      const clone = start.clone();
      while (clone.peek() !== $GT && !isSelectorlessNameStart(clone.peek())) {
        clone.advance();
      }
      if (isSelectorlessNameStart(clone.peek())) {
        this._beginToken(37, start);
        const parts = this._consumeComponentName();
        this._attemptCharCodeUntilFn(isNotWhitespace);
        this._requireCharCode($GT);
        this._endToken(parts);
        return;
      }
    }
    this._beginToken(3, start);
    this._attemptCharCodeUntilFn(isNotWhitespace);
    const prefixAndName = this._consumePrefixAndName(isNameEnd);
    this._attemptCharCodeUntilFn(isNotWhitespace);
    this._requireCharCode($GT);
    this._endToken(prefixAndName);
  }
  _consumeExpansionFormStart() {
    this._beginToken(20);
    this._requireCharCode($LBRACE);
    this._endToken([]);
    this._expansionCaseStack.push(20);
    this._beginToken(7);
    const condition = this._readUntil($COMMA);
    const normalizedCondition = this._processCarriageReturns(condition);
    if (this._i18nNormalizeLineEndingsInICUs) {
      this._endToken([normalizedCondition]);
    } else {
      const conditionToken = this._endToken([condition]);
      if (normalizedCondition !== condition) {
        this.nonNormalizedIcuExpressions.push(conditionToken);
      }
    }
    this._requireCharCode($COMMA);
    this._attemptCharCodeUntilFn(isNotWhitespace);
    this._beginToken(7);
    const type = this._readUntil($COMMA);
    this._endToken([type]);
    this._requireCharCode($COMMA);
    this._attemptCharCodeUntilFn(isNotWhitespace);
  }
  _consumeExpansionCaseStart() {
    this._beginToken(21);
    const value = this._readUntil($LBRACE).trim();
    this._endToken([value]);
    this._attemptCharCodeUntilFn(isNotWhitespace);
    this._beginToken(22);
    this._requireCharCode($LBRACE);
    this._endToken([]);
    this._attemptCharCodeUntilFn(isNotWhitespace);
    this._expansionCaseStack.push(22);
  }
  _consumeExpansionCaseEnd() {
    this._beginToken(23);
    this._requireCharCode($RBRACE);
    this._endToken([]);
    this._attemptCharCodeUntilFn(isNotWhitespace);
    this._expansionCaseStack.pop();
  }
  _consumeExpansionFormEnd() {
    this._beginToken(24);
    this._requireCharCode($RBRACE);
    this._endToken([]);
    this._expansionCaseStack.pop();
  }
  _consumeWithInterpolation(textTokenType, interpolationTokenType, endPredicate, endInterpolation) {
    this._beginToken(textTokenType);
    const parts = [];
    while (!endPredicate()) {
      const current = this._cursor.clone();
      if (this._attemptStr(INTERPOLATION.start)) {
        this._endToken([this._processCarriageReturns(parts.join(''))], current);
        parts.length = 0;
        this._consumeInterpolation(interpolationTokenType, current, endInterpolation);
        this._beginToken(textTokenType);
      } else if (this._cursor.peek() === $AMPERSAND) {
        this._endToken([this._processCarriageReturns(parts.join(''))]);
        parts.length = 0;
        this._consumeEntity(textTokenType);
        this._beginToken(textTokenType);
      } else {
        parts.push(this._readChar());
      }
    }
    this._inInterpolation = false;
    this._endToken([this._processCarriageReturns(parts.join(''))]);
  }
  _consumeInterpolation(interpolationTokenType, interpolationStart, prematureEndPredicate) {
    const parts = [];
    this._beginToken(interpolationTokenType, interpolationStart);
    parts.push(INTERPOLATION.start);
    const expressionStart = this._cursor.clone();
    let inQuote = null;
    let inComment = false;
    while (this._cursor.peek() !== $EOF && (prematureEndPredicate === null || !prematureEndPredicate())) {
      const current = this._cursor.clone();
      if (this._isTagStart()) {
        this._cursor = current;
        parts.push(this._getProcessedChars(expressionStart, current));
        this._endToken(parts);
        return;
      }
      if (inQuote === null) {
        if (this._attemptStr(INTERPOLATION.end)) {
          parts.push(this._getProcessedChars(expressionStart, current));
          parts.push(INTERPOLATION.end);
          this._endToken(parts);
          return;
        } else if (this._attemptStr('//')) {
          inComment = true;
        }
      }
      const char = this._cursor.peek();
      this._cursor.advance();
      if (char === $BACKSLASH) {
        this._cursor.advance();
      } else if (char === inQuote) {
        inQuote = null;
      } else if (!inComment && inQuote === null && isQuote(char)) {
        inQuote = char;
      }
    }
    parts.push(this._getProcessedChars(expressionStart, this._cursor));
    this._endToken(parts);
  }
  _consumeDirective(start, nameStart) {
    this._requireCharCode($AT);
    this._cursor.advance();
    while (isSelectorlessNameChar(this._cursor.peek())) {
      this._cursor.advance();
    }
    this._beginToken(39, start);
    const name = this._cursor.getChars(nameStart);
    this._endToken([name]);
    this._attemptCharCodeUntilFn(isNotWhitespace);
    if (this._cursor.peek() !== $LPAREN) {
      return;
    }
    this._openDirectiveCount++;
    this._beginToken(40);
    this._cursor.advance();
    this._endToken([]);
    this._attemptCharCodeUntilFn(isNotWhitespace);
    while (!isAttributeTerminator(this._cursor.peek()) && this._cursor.peek() !== $RPAREN) {
      this._consumeAttribute();
    }
    this._attemptCharCodeUntilFn(isNotWhitespace);
    this._openDirectiveCount--;
    if (this._cursor.peek() !== $RPAREN) {
      if (this._cursor.peek() === $GT || this._cursor.peek() === $SLASH) {
        return;
      }
      throw this._createError(_unexpectedCharacterErrorMsg(this._cursor.peek()), this._cursor.getSpan(start));
    }
    this._beginToken(41);
    this._cursor.advance();
    this._endToken([]);
    this._attemptCharCodeUntilFn(isNotWhitespace);
  }
  _getProcessedChars(start, end) {
    return this._processCarriageReturns(end.getChars(start));
  }
  _isTextEnd() {
    if (this._isTagStart() || this._cursor.peek() === $EOF) {
      return true;
    }
    if (this._tokenizeIcu && !this._inInterpolation) {
      if (this.isExpansionFormStart()) {
        return true;
      }
      if (this._cursor.peek() === $RBRACE && this._isInExpansionCase()) {
        return true;
      }
    }
    if (this._tokenizeBlocks && !this._inInterpolation && !this._isInExpansion() && (this._isBlockStart() || this._isLetStart() || this._cursor.peek() === $RBRACE)) {
      return true;
    }
    return false;
  }
  _isTagStart() {
    if (this._cursor.peek() === $LT) {
      const tmp = this._cursor.clone();
      tmp.advance();
      const code = tmp.peek();
      if ($a <= code && code <= $z || $A <= code && code <= $Z || code === $SLASH || code === $BANG || code === $QUESTION) {
        return true;
      }
    }
    return false;
  }
  _readUntil(char) {
    const start = this._cursor.clone();
    this._attemptUntilChar(char);
    return this._cursor.getChars(start);
  }
  _isInExpansion() {
    return this._isInExpansionCase() || this._isInExpansionForm();
  }
  _isInExpansionCase() {
    return this._expansionCaseStack.length > 0 && this._expansionCaseStack[this._expansionCaseStack.length - 1] === 22;
  }
  _isInExpansionForm() {
    return this._expansionCaseStack.length > 0 && this._expansionCaseStack[this._expansionCaseStack.length - 1] === 20;
  }
  isExpansionFormStart() {
    if (this._cursor.peek() !== $LBRACE) {
      return false;
    }
    const start = this._cursor.clone();
    const isInterpolation = this._attemptStr(INTERPOLATION.start);
    this._cursor = start;
    return !isInterpolation;
  }
}
function isNotWhitespace(code) {
  return !isWhitespace(code) || code === $EOF;
}
function isNameEnd(code) {
  return isWhitespace(code) || code === $GT || code === $LT || code === $SLASH || code === $SQ || code === $DQ || code === $EQ || code === $EOF;
}
function isPrefixEnd(code) {
  return (code < $a || $z < code) && (code < $A || $Z < code) && (code < $0 || code > $9);
}
function isDigitEntityEnd(code) {
  return code === $SEMICOLON || code === $EOF || !isAsciiHexDigit(code);
}
function isNamedEntityEnd(code) {
  return code === $SEMICOLON || code === $EOF || !(isAsciiLetter(code) || isDigit(code));
}
function isExpansionCaseStart(peek) {
  return peek !== $RBRACE;
}
function compareCharCodeCaseInsensitive(code1, code2) {
  return toUpperCaseCharCode(code1) === toUpperCaseCharCode(code2);
}
function toUpperCaseCharCode(code) {
  return code >= $a && code <= $z ? code - $a + $A : code;
}
function isBlockNameChar(code) {
  return isAsciiLetter(code) || isDigit(code) || code === $_;
}
function isBlockParameterChar(code) {
  return code !== $SEMICOLON && isNotWhitespace(code);
}
function isSelectorlessNameStart(code) {
  return code === $_ || code >= $A && code <= $Z;
}
function isSelectorlessNameChar(code) {
  return isAsciiLetter(code) || isDigit(code) || code === $_;
}
function isAttributeTerminator(code) {
  return code === $SLASH || code === $GT || code === $LT || code === $EOF;
}
function mergeTextTokens(srcTokens) {
  const dstTokens = [];
  let lastDstToken = undefined;
  for (let i = 0; i < srcTokens.length; i++) {
    const token = srcTokens[i];
    if (lastDstToken && lastDstToken.type === 5 && token.type === 5 || lastDstToken && lastDstToken.type === 17 && token.type === 17) {
      lastDstToken.parts[0] += token.parts[0];
      lastDstToken.sourceSpan.end = token.sourceSpan.end;
    } else {
      lastDstToken = token;
      dstTokens.push(lastDstToken);
    }
  }
  return dstTokens;
}
class PlainCharacterCursor {
  state;
  file;
  input;
  end;
  constructor(fileOrCursor, range) {
    if (fileOrCursor instanceof PlainCharacterCursor) {
      this.file = fileOrCursor.file;
      this.input = fileOrCursor.input;
      this.end = fileOrCursor.end;
      const state = fileOrCursor.state;
      this.state = {
        peek: state.peek,
        offset: state.offset,
        line: state.line,
        column: state.column
      };
    } else {
      if (!range) {
        throw new Error('Programming error: the range argument must be provided with a file argument.');
      }
      this.file = fileOrCursor;
      this.input = fileOrCursor.content;
      this.end = range.endPos;
      this.state = {
        peek: -1,
        offset: range.startPos,
        line: range.startLine,
        column: range.startCol
      };
    }
  }
  clone() {
    return new PlainCharacterCursor(this);
  }
  peek() {
    return this.state.peek;
  }
  charsLeft() {
    return this.end - this.state.offset;
  }
  diff(other) {
    return this.state.offset - other.state.offset;
  }
  advance() {
    this.advanceState(this.state);
  }
  init() {
    this.updatePeek(this.state);
  }
  getSpan(start, leadingTriviaCodePoints) {
    start = start || this;
    let fullStart = start;
    if (leadingTriviaCodePoints) {
      while (this.diff(start) > 0 && leadingTriviaCodePoints.indexOf(start.peek()) !== -1) {
        if (fullStart === start) {
          start = start.clone();
        }
        start.advance();
      }
    }
    const startLocation = this.locationFromCursor(start);
    const endLocation = this.locationFromCursor(this);
    const fullStartLocation = fullStart !== start ? this.locationFromCursor(fullStart) : startLocation;
    return new ParseSourceSpan(startLocation, endLocation, fullStartLocation);
  }
  getChars(start) {
    return this.input.substring(start.state.offset, this.state.offset);
  }
  charAt(pos) {
    return this.input.charCodeAt(pos);
  }
  advanceState(state) {
    if (state.offset >= this.end) {
      this.state = state;
      throw new CursorError('Unexpected character "EOF"', this);
    }
    const currentChar = this.charAt(state.offset);
    if (currentChar === $LF) {
      state.line++;
      state.column = 0;
    } else if (!isNewLine(currentChar)) {
      state.column++;
    }
    state.offset++;
    this.updatePeek(state);
  }
  updatePeek(state) {
    state.peek = state.offset >= this.end ? $EOF : this.charAt(state.offset);
  }
  locationFromCursor(cursor) {
    return new ParseLocation(cursor.file, cursor.state.offset, cursor.state.line, cursor.state.column);
  }
}
class EscapedCharacterCursor extends PlainCharacterCursor {
  internalState;
  constructor(fileOrCursor, range) {
    if (fileOrCursor instanceof EscapedCharacterCursor) {
      super(fileOrCursor);
      this.internalState = {
        ...fileOrCursor.internalState
      };
    } else {
      super(fileOrCursor, range);
      this.internalState = this.state;
    }
  }
  advance() {
    this.state = this.internalState;
    super.advance();
    this.processEscapeSequence();
  }
  init() {
    super.init();
    this.processEscapeSequence();
  }
  clone() {
    return new EscapedCharacterCursor(this);
  }
  getChars(start) {
    const cursor = start.clone();
    let chars = '';
    while (cursor.internalState.offset < this.internalState.offset) {
      chars += String.fromCodePoint(cursor.peek());
      cursor.advance();
    }
    return chars;
  }
  processEscapeSequence() {
    const peek = () => this.internalState.peek;
    if (peek() === $BACKSLASH) {
      this.internalState = {
        ...this.state
      };
      this.advanceState(this.internalState);
      if (peek() === $n) {
        this.state.peek = $LF;
      } else if (peek() === $r) {
        this.state.peek = $CR;
      } else if (peek() === $v) {
        this.state.peek = $VTAB;
      } else if (peek() === $t) {
        this.state.peek = $TAB;
      } else if (peek() === $b) {
        this.state.peek = $BSPACE;
      } else if (peek() === $f) {
        this.state.peek = $FF;
      } else if (peek() === $u) {
        this.advanceState(this.internalState);
        if (peek() === $LBRACE) {
          this.advanceState(this.internalState);
          const digitStart = this.clone();
          let length = 0;
          while (peek() !== $RBRACE) {
            this.advanceState(this.internalState);
            length++;
          }
          this.state.peek = this.decodeHexDigits(digitStart, length);
        } else {
          const digitStart = this.clone();
          this.advanceState(this.internalState);
          this.advanceState(this.internalState);
          this.advanceState(this.internalState);
          this.state.peek = this.decodeHexDigits(digitStart, 4);
        }
      } else if (peek() === $x) {
        this.advanceState(this.internalState);
        const digitStart = this.clone();
        this.advanceState(this.internalState);
        this.state.peek = this.decodeHexDigits(digitStart, 2);
      } else if (isOctalDigit(peek())) {
        let octal = '';
        let length = 0;
        let previous = this.clone();
        while (isOctalDigit(peek()) && length < 3) {
          previous = this.clone();
          octal += String.fromCodePoint(peek());
          this.advanceState(this.internalState);
          length++;
        }
        this.state.peek = parseInt(octal, 8);
        this.internalState = previous.internalState;
      } else if (isNewLine(this.internalState.peek)) {
        this.advanceState(this.internalState);
        this.state = this.internalState;
      } else {
        this.state.peek = this.internalState.peek;
      }
    }
  }
  decodeHexDigits(start, length) {
    const hex = this.input.slice(start.internalState.offset, start.internalState.offset + length);
    const charCode = parseInt(hex, 16);
    if (!isNaN(charCode)) {
      return charCode;
    } else {
      start.state = start.internalState;
      throw new CursorError('Invalid hexadecimal escape sequence', start);
    }
  }
}
class CursorError extends Error {
  msg;
  cursor;
  constructor(msg, cursor) {
    super(msg);
    this.msg = msg;
    this.cursor = cursor;
    Object.setPrototypeOf(this, new.target.prototype);
  }
}

class TreeError extends ParseError {
  elementName;
  static create(elementName, span, msg) {
    return new TreeError(elementName, span, msg);
  }
  constructor(elementName, span, msg) {
    super(span, msg);
    this.elementName = elementName;
  }
}
class ParseTreeResult {
  rootNodes;
  errors;
  constructor(rootNodes, errors) {
    this.rootNodes = rootNodes;
    this.errors = errors;
  }
}
let Parser$1 = class Parser {
  getTagDefinition;
  constructor(getTagDefinition) {
    this.getTagDefinition = getTagDefinition;
  }
  parse(source, url, options) {
    const tokenizeResult = tokenize(source, url, this.getTagDefinition, options);
    const parser = new _TreeBuilder(tokenizeResult.tokens, this.getTagDefinition);
    parser.build();
    return new ParseTreeResult(parser.rootNodes, [...tokenizeResult.errors, ...parser.errors]);
  }
};
class _TreeBuilder {
  tokens;
  tagDefinitionResolver;
  _index = -1;
  _peek;
  _containerStack = [];
  rootNodes = [];
  errors = [];
  constructor(tokens, tagDefinitionResolver) {
    this.tokens = tokens;
    this.tagDefinitionResolver = tagDefinitionResolver;
    this._advance();
  }
  build() {
    while (this._peek.type !== 43) {
      if (this._peek.type === 0 || this._peek.type === 4) {
        this._consumeElementStartTag(this._advance());
      } else if (this._peek.type === 3) {
        this._consumeElementEndTag(this._advance());
      } else if (this._peek.type === 13) {
        this._closeVoidElement();
        this._consumeCdata(this._advance());
      } else if (this._peek.type === 10) {
        this._closeVoidElement();
        this._consumeComment(this._advance());
      } else if (this._peek.type === 5 || this._peek.type === 7 || this._peek.type === 6) {
        this._closeVoidElement();
        this._consumeText(this._advance());
      } else if (this._peek.type === 20) {
        this._consumeExpansion(this._advance());
      } else if (this._peek.type === 25) {
        this._closeVoidElement();
        this._consumeBlockOpen(this._advance());
      } else if (this._peek.type === 27) {
        this._closeVoidElement();
        this._consumeBlockClose(this._advance());
      } else if (this._peek.type === 29) {
        this._closeVoidElement();
        this._consumeIncompleteBlock(this._advance());
      } else if (this._peek.type === 30) {
        this._closeVoidElement();
        this._consumeLet(this._advance());
      } else if (this._peek.type === 33) {
        this._closeVoidElement();
        this._consumeIncompleteLet(this._advance());
      } else if (this._peek.type === 34 || this._peek.type === 38) {
        this._consumeComponentStartTag(this._advance());
      } else if (this._peek.type === 37) {
        this._consumeComponentEndTag(this._advance());
      } else {
        this._advance();
      }
    }
    for (const leftoverContainer of this._containerStack) {
      if (leftoverContainer instanceof Block) {
        this.errors.push(TreeError.create(leftoverContainer.name, leftoverContainer.sourceSpan, `Unclosed block "${leftoverContainer.name}"`));
      }
    }
  }
  _advance() {
    const prev = this._peek;
    if (this._index < this.tokens.length - 1) {
      this._index++;
    }
    this._peek = this.tokens[this._index];
    return prev;
  }
  _advanceIf(type) {
    if (this._peek.type === type) {
      return this._advance();
    }
    return null;
  }
  _consumeCdata(_startToken) {
    this._consumeText(this._advance());
    this._advanceIf(14);
  }
  _consumeComment(token) {
    const text = this._advanceIf(7);
    const endToken = this._advanceIf(11);
    const value = text != null ? text.parts[0].trim() : null;
    const sourceSpan = endToken == null ? token.sourceSpan : new ParseSourceSpan(token.sourceSpan.start, endToken.sourceSpan.end, token.sourceSpan.fullStart);
    this._addToParent(new Comment(value, sourceSpan));
  }
  _consumeExpansion(token) {
    const switchValue = this._advance();
    const type = this._advance();
    const cases = [];
    while (this._peek.type === 21) {
      const expCase = this._parseExpansionCase();
      if (!expCase) return;
      cases.push(expCase);
    }
    if (this._peek.type !== 24) {
      this.errors.push(TreeError.create(null, this._peek.sourceSpan, `Invalid ICU message. Missing '}'.`));
      return;
    }
    const sourceSpan = new ParseSourceSpan(token.sourceSpan.start, this._peek.sourceSpan.end, token.sourceSpan.fullStart);
    this._addToParent(new Expansion(switchValue.parts[0], type.parts[0], cases, sourceSpan, switchValue.sourceSpan));
    this._advance();
  }
  _parseExpansionCase() {
    const value = this._advance();
    if (this._peek.type !== 22) {
      this.errors.push(TreeError.create(null, this._peek.sourceSpan, `Invalid ICU message. Missing '{'.`));
      return null;
    }
    const start = this._advance();
    const exp = this._collectExpansionExpTokens(start);
    if (!exp) return null;
    const end = this._advance();
    exp.push({
      type: 43,
      parts: [],
      sourceSpan: end.sourceSpan
    });
    const expansionCaseParser = new _TreeBuilder(exp, this.tagDefinitionResolver);
    expansionCaseParser.build();
    if (expansionCaseParser.errors.length > 0) {
      this.errors = this.errors.concat(expansionCaseParser.errors);
      return null;
    }
    const sourceSpan = new ParseSourceSpan(value.sourceSpan.start, end.sourceSpan.end, value.sourceSpan.fullStart);
    const expSourceSpan = new ParseSourceSpan(start.sourceSpan.start, end.sourceSpan.end, start.sourceSpan.fullStart);
    return new ExpansionCase(value.parts[0], expansionCaseParser.rootNodes, sourceSpan, value.sourceSpan, expSourceSpan);
  }
  _collectExpansionExpTokens(start) {
    const exp = [];
    const expansionFormStack = [22];
    while (true) {
      if (this._peek.type === 20 || this._peek.type === 22) {
        expansionFormStack.push(this._peek.type);
      }
      if (this._peek.type === 23) {
        if (lastOnStack(expansionFormStack, 22)) {
          expansionFormStack.pop();
          if (expansionFormStack.length === 0) return exp;
        } else {
          this.errors.push(TreeError.create(null, start.sourceSpan, `Invalid ICU message. Missing '}'.`));
          return null;
        }
      }
      if (this._peek.type === 24) {
        if (lastOnStack(expansionFormStack, 20)) {
          expansionFormStack.pop();
        } else {
          this.errors.push(TreeError.create(null, start.sourceSpan, `Invalid ICU message. Missing '}'.`));
          return null;
        }
      }
      if (this._peek.type === 43) {
        this.errors.push(TreeError.create(null, start.sourceSpan, `Invalid ICU message. Missing '}'.`));
        return null;
      }
      exp.push(this._advance());
    }
  }
  _consumeText(token) {
    const tokens = [token];
    const startSpan = token.sourceSpan;
    let text = token.parts[0];
    if (text.length > 0 && text[0] === '\n') {
      const parent = this._getContainer();
      if (parent != null && parent.children.length === 0 && this._getTagDefinition(parent)?.ignoreFirstLf) {
        text = text.substring(1);
        tokens[0] = {
          type: token.type,
          sourceSpan: token.sourceSpan,
          parts: [text]
        };
      }
    }
    while (this._peek.type === 8 || this._peek.type === 5 || this._peek.type === 9) {
      token = this._advance();
      tokens.push(token);
      if (token.type === 8) {
        text += token.parts.join('').replace(/&([^;]+);/g, decodeEntity);
      } else if (token.type === 9) {
        text += token.parts[0];
      } else {
        text += token.parts.join('');
      }
    }
    if (text.length > 0) {
      const endSpan = token.sourceSpan;
      this._addToParent(new Text(text, new ParseSourceSpan(startSpan.start, endSpan.end, startSpan.fullStart, startSpan.details), tokens));
    }
  }
  _closeVoidElement() {
    const el = this._getContainer();
    if (el !== null && this._getTagDefinition(el)?.isVoid) {
      this._containerStack.pop();
    }
  }
  _consumeElementStartTag(startTagToken) {
    const attrs = [];
    const directives = [];
    const comments = [];
    this._consumeAttributesAndDirectives(attrs, directives, comments);
    const fullName = this._getElementFullName(startTagToken, this._getClosestElementLikeParent());
    const tagDef = this._getTagDefinition(fullName);
    let selfClosing = false;
    if (this._peek.type === 2) {
      this._advance();
      selfClosing = true;
      if (!(tagDef?.canSelfClose || getNsPrefix(fullName) !== null || tagDef?.isVoid)) {
        this.errors.push(TreeError.create(fullName, startTagToken.sourceSpan, `Only void, custom and foreign elements can be self closed "${startTagToken.parts[1]}"`));
      }
    } else if (this._peek.type === 1) {
      this._advance();
      selfClosing = false;
    }
    const end = this._peek.sourceSpan.fullStart;
    const span = new ParseSourceSpan(startTagToken.sourceSpan.start, end, startTagToken.sourceSpan.fullStart);
    const startSpan = new ParseSourceSpan(startTagToken.sourceSpan.start, end, startTagToken.sourceSpan.fullStart);
    const el = new Element(fullName, attrs, directives, [], selfClosing, span, startSpan, undefined, tagDef?.isVoid ?? false, undefined, comments);
    const parent = this._getContainer();
    const isClosedByChild = parent !== null && !!this._getTagDefinition(parent)?.isClosedByChild(el.name);
    this._pushContainer(el, isClosedByChild);
    if (selfClosing) {
      this._popContainer(fullName, Element, span);
    } else if (startTagToken.type === 4) {
      this._popContainer(fullName, Element, null);
      this.errors.push(TreeError.create(fullName, span, `Opening tag "${fullName}" not terminated.`));
    }
  }
  _consumeComponentStartTag(startToken) {
    const componentName = startToken.parts[0];
    const attrs = [];
    const directives = [];
    const comments = [];
    this._consumeAttributesAndDirectives(attrs, directives, comments);
    const closestElement = this._getClosestElementLikeParent();
    const tagName = this._getComponentTagName(startToken, closestElement);
    const fullName = this._getComponentFullName(startToken, closestElement);
    const selfClosing = this._peek.type === 36;
    this._advance();
    const end = this._peek.sourceSpan.fullStart;
    const span = new ParseSourceSpan(startToken.sourceSpan.start, end, startToken.sourceSpan.fullStart);
    const startSpan = new ParseSourceSpan(startToken.sourceSpan.start, end, startToken.sourceSpan.fullStart);
    const node = new Component(componentName, tagName, fullName, attrs, directives, [], selfClosing, span, startSpan, undefined, undefined, comments);
    const parent = this._getContainer();
    const isClosedByChild = parent !== null && node.tagName !== null && !!this._getTagDefinition(parent)?.isClosedByChild(node.tagName);
    this._pushContainer(node, isClosedByChild);
    if (selfClosing) {
      this._popContainer(fullName, Component, span);
    } else if (startToken.type === 38) {
      this._popContainer(fullName, Component, null);
      this.errors.push(TreeError.create(fullName, span, `Opening tag "${fullName}" not terminated.`));
    }
  }
  _consumeAttributesAndDirectives(attributesResult, directivesResult, commentsResult) {
    while (this._peek.type === 15 || this._peek.type === 39 || this._peek.type === 12) {
      if (this._peek.type === 39) {
        directivesResult.push(this._consumeDirective(this._peek));
      } else if (this._peek.type === 15) {
        attributesResult.push(this._consumeAttr(this._advance()));
      } else {
        const commentToken = this._advance();
        commentsResult.push(new StartTagComment(commentToken.parts[0], commentToken.parts[1], commentToken.sourceSpan));
      }
    }
  }
  _consumeComponentEndTag(endToken) {
    const fullName = this._getComponentFullName(endToken, this._getClosestElementLikeParent());
    if (!this._popContainer(fullName, Component, endToken.sourceSpan)) {
      const container = this._containerStack[this._containerStack.length - 1];
      let suffix;
      if (container instanceof Component && container.componentName === endToken.parts[0]) {
        suffix = `, did you mean "${container.fullName}"?`;
      } else {
        suffix = '. It may happen when the tag has already been closed by another tag.';
      }
      const errMsg = `Unexpected closing tag "${fullName}"${suffix}`;
      this.errors.push(TreeError.create(fullName, endToken.sourceSpan, errMsg));
    }
  }
  _getTagDefinition(nodeOrName) {
    if (typeof nodeOrName === 'string') {
      return this.tagDefinitionResolver(nodeOrName);
    } else if (nodeOrName instanceof Element) {
      return this.tagDefinitionResolver(nodeOrName.name);
    } else if (nodeOrName instanceof Component && nodeOrName.tagName !== null) {
      return this.tagDefinitionResolver(nodeOrName.tagName);
    } else {
      return null;
    }
  }
  _pushContainer(node, isClosedByChild) {
    if (isClosedByChild) {
      this._containerStack.pop();
    }
    this._addToParent(node);
    this._containerStack.push(node);
  }
  _consumeElementEndTag(endTagToken) {
    const fullName = this._getElementFullName(endTagToken, this._getClosestElementLikeParent());
    if (this._getTagDefinition(fullName)?.isVoid) {
      this.errors.push(TreeError.create(fullName, endTagToken.sourceSpan, `Void elements do not have end tags "${endTagToken.parts[1]}"`));
    } else if (!this._popContainer(fullName, Element, endTagToken.sourceSpan)) {
      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`;
      this.errors.push(TreeError.create(fullName, endTagToken.sourceSpan, errMsg));
    }
  }
  _popContainer(expectedName, expectedType, endSourceSpan) {
    let unexpectedCloseTagDetected = false;
    for (let stackIndex = this._containerStack.length - 1; stackIndex >= 0; stackIndex--) {
      const node = this._containerStack[stackIndex];
      const nodeName = node instanceof Component ? node.fullName : node.name;
      if ((nodeName === expectedName || expectedName === null) && node instanceof expectedType) {
        node.endSourceSpan = endSourceSpan;
        node.sourceSpan.end = endSourceSpan !== null ? endSourceSpan.end : node.sourceSpan.end;
        this._containerStack.splice(stackIndex, this._containerStack.length - stackIndex);
        return !unexpectedCloseTagDetected;
      }
      if (node instanceof Block || !this._getTagDefinition(node)?.closedByParent) {
        unexpectedCloseTagDetected = true;
      }
    }
    return false;
  }
  _consumeAttr(attrName) {
    const fullName = mergeNsAndName(attrName.parts[0], attrName.parts[1]);
    let attrEnd = attrName.sourceSpan.end;
    if (this._peek.type === 16) {
      this._advance();
    }
    let value = '';
    const valueTokens = [];
    let valueStartSpan = undefined;
    let valueEnd = undefined;
    const nextTokenType = this._peek.type;
    if (nextTokenType === 17) {
      valueStartSpan = this._peek.sourceSpan;
      valueEnd = this._peek.sourceSpan.end;
      while (this._peek.type === 17 || this._peek.type === 18 || this._peek.type === 9) {
        const valueToken = this._advance();
        valueTokens.push(valueToken);
        if (valueToken.type === 18) {
          value += valueToken.parts.join('').replace(/&([^;]+);/g, decodeEntity);
        } else if (valueToken.type === 9) {
          value += valueToken.parts[0];
        } else {
          value += valueToken.parts.join('');
        }
        valueEnd = attrEnd = valueToken.sourceSpan.end;
      }
    }
    if (this._peek.type === 16) {
      const quoteToken = this._advance();
      attrEnd = quoteToken.sourceSpan.end;
    }
    const valueSpan = valueStartSpan && valueEnd && new ParseSourceSpan(valueStartSpan.start, valueEnd, valueStartSpan.fullStart);
    return new Attribute(fullName, value, new ParseSourceSpan(attrName.sourceSpan.start, attrEnd, attrName.sourceSpan.fullStart), attrName.sourceSpan, valueSpan, valueTokens.length > 0 ? valueTokens : undefined, undefined);
  }
  _consumeDirective(nameToken) {
    const attributes = [];
    let startSourceSpanEnd = nameToken.sourceSpan.end;
    let endSourceSpan = null;
    this._advance();
    if (this._peek.type === 40) {
      startSourceSpanEnd = this._peek.sourceSpan.end;
      this._advance();
      while (this._peek.type === 15) {
        attributes.push(this._consumeAttr(this._advance()));
      }
      if (this._peek.type === 41) {
        endSourceSpan = this._peek.sourceSpan;
        this._advance();
      } else {
        this.errors.push(TreeError.create(null, nameToken.sourceSpan, 'Unterminated directive definition'));
      }
    }
    const startSourceSpan = new ParseSourceSpan(nameToken.sourceSpan.start, startSourceSpanEnd, nameToken.sourceSpan.fullStart);
    const sourceSpan = new ParseSourceSpan(startSourceSpan.start, endSourceSpan === null ? nameToken.sourceSpan.end : endSourceSpan.end, startSourceSpan.fullStart);
    return new Directive(nameToken.parts[0], attributes, sourceSpan, startSourceSpan, endSourceSpan);
  }
  _consumeBlockOpen(token) {
    const parameters = [];
    while (this._peek.type === 28) {
      const paramToken = this._advance();
      parameters.push(new BlockParameter(paramToken.parts[0], paramToken.sourceSpan));
    }
    if (this._peek.type === 26) {
      this._advance();
    }
    const end = this._peek.sourceSpan.fullStart;
    const span = new ParseSourceSpan(token.sourceSpan.start, end, token.sourceSpan.fullStart);
    const startSpan = new ParseSourceSpan(token.sourceSpan.start, end, token.sourceSpan.fullStart);
    const block = new Block(token.parts[0], parameters, [], span, token.sourceSpan, startSpan);
    this._pushContainer(block, false);
  }
  _consumeBlockClose(token) {
    const initialStackLength = this._containerStack.length;
    const topNode = this._containerStack[initialStackLength - 1];
    if (!this._popContainer(null, Block, token.sourceSpan)) {
      if (this._containerStack.length < initialStackLength) {
        const nodeName = topNode instanceof Component ? topNode.fullName : topNode.name;
        this.errors.push(TreeError.create(null, token.sourceSpan, `Unexpected closing block. The block may have been closed earlier. ` + `Did you forget to close the <${nodeName}> element? ` + `If you meant to write the \`}\` character, you should use the "&#125;" ` + `HTML entity instead.`));
        return;
      }
      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.`));
    }
  }
  _consumeIncompleteBlock(token) {
    const parameters = [];
    while (this._peek.type === 28) {
      const paramToken = this._advance();
      parameters.push(new BlockParameter(paramToken.parts[0], paramToken.sourceSpan));
    }
    const end = this._peek.sourceSpan.fullStart;
    const span = new ParseSourceSpan(token.sourceSpan.start, end, token.sourceSpan.fullStart);
    const startSpan = new ParseSourceSpan(token.sourceSpan.start, end, token.sourceSpan.fullStart);
    const block = new Block(token.parts[0], parameters, [], span, token.sourceSpan, startSpan);
    this._pushContainer(block, false);
    this._popContainer(null, Block, null);
    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.`));
  }
  _consumeLet(startToken) {
    const name = startToken.parts[0];
    let valueToken;
    let endToken;
    if (this._peek.type !== 31) {
      this.errors.push(TreeError.create(startToken.parts[0], startToken.sourceSpan, `Invalid @let declaration "${name}". Declaration must have a value.`));
      return;
    } else {
      valueToken = this._advance();
    }
    if (this._peek.type !== 32) {
      this.errors.push(TreeError.create(startToken.parts[0], startToken.sourceSpan, `Unterminated @let declaration "${name}". Declaration must be terminated with a semicolon.`));
      return;
    } else {
      endToken = this._advance();
    }
    const end = endToken.sourceSpan.end;
    const span = new ParseSourceSpan(startToken.sourceSpan.start, end, startToken.sourceSpan.fullStart);
    const startOffset = startToken.sourceSpan.toString().lastIndexOf(name);
    const nameStart = startToken.sourceSpan.start.moveBy(startOffset);
    const nameSpan = new ParseSourceSpan(nameStart, startToken.sourceSpan.end);
    const node = new LetDeclaration(name, valueToken.parts[0], span, nameSpan, valueToken.sourceSpan);
    this._addToParent(node);
  }
  _consumeIncompleteLet(token) {
    const name = token.parts[0] ?? '';
    const nameString = name ? ` "${name}"` : '';
    if (name.length > 0) {
      const startOffset = token.sourceSpan.toString().lastIndexOf(name);
      const nameStart = token.sourceSpan.start.moveBy(startOffset);
      const nameSpan = new ParseSourceSpan(nameStart, token.sourceSpan.end);
      const valueSpan = new ParseSourceSpan(token.sourceSpan.start, token.sourceSpan.start.moveBy(0));
      const node = new LetDeclaration(name, '', token.sourceSpan, nameSpan, valueSpan);
      this._addToParent(node);
    }
    this.errors.push(TreeError.create(token.parts[0], token.sourceSpan, `Incomplete @let declaration${nameString}. ` + `@let declarations must be written as \`@let <name> = <value>;\``));
  }
  _getContainer() {
    return this._containerStack.length > 0 ? this._containerStack[this._containerStack.length - 1] : null;
  }
  _getClosestElementLikeParent() {
    for (let i = this._containerStack.length - 1; i > -1; i--) {
      const current = this._containerStack[i];
      if (current instanceof Element || current instanceof Component) {
        return current;
      }
    }
    return null;
  }
  _addToParent(node) {
    const parent = this._getContainer();
    if (parent === null) {
      this.rootNodes.push(node);
    } else {
      parent.children.push(node);
    }
  }
  _getElementFullName(token, parent) {
    const prefix = this._getPrefix(token, parent);
    return mergeNsAndName(prefix, token.parts[1]);
  }
  _getComponentFullName(token, parent) {
    const componentName = token.parts[0];
    const tagName = this._getComponentTagName(token, parent);
    if (tagName === null) {
      return componentName;
    }
    return tagName.startsWith(':') ? componentName + tagName : `${componentName}:${tagName}`;
  }
  _getComponentTagName(token, parent) {
    const prefix = this._getPrefix(token, parent);
    const tagName = token.parts[2];
    if (!prefix && !tagName) {
      return null;
    } else if (!prefix && tagName) {
      return tagName;
    } else {
      return mergeNsAndName(prefix, tagName || 'ng-component');
    }
  }
  _getPrefix(token, parent) {
    let prefix;
    let tagName;
    if (token.type === 34 || token.type === 38 || token.type === 37) {
      prefix = token.parts[1];
      tagName = token.parts[2];
    } else {
      prefix = token.parts[0];
      tagName = token.parts[1];
    }
    prefix = prefix || this._getTagDefinition(tagName)?.implicitNamespacePrefix || '';
    if (!prefix && parent) {
      const parentName = parent instanceof Element ? parent.name : parent.tagName;
      if (parentName !== null) {
        const parentTagName = splitNsName(parentName)[1];
        const parentTagDefinition = this._getTagDefinition(parentTagName);
        if (parentTagDefinition !== null && !parentTagDefinition.preventNamespaceInheritance) {
          prefix = getNsPrefix(parentName);
        }
      }
    }
    return prefix;
  }
}
function lastOnStack(stack, element) {
  return stack.length > 0 && stack[stack.length - 1] === element;
}
function decodeEntity(match, entity) {
  if (NAMED_ENTITIES[entity] !== undefined) {
    return NAMED_ENTITIES[entity] || match;
  }
  if (/^#x[a-f0-9]+$/i.test(entity)) {
    return String.fromCodePoint(parseInt(entity.slice(2), 16));
  }
  if (/^#\d+$/.test(entity)) {
    return String.fromCodePoint(parseInt(entity.slice(1), 10));
  }
  return match;
}

const PRESERVE_WS_ATTR_NAME = 'ngPreserveWhitespaces';
const SKIP_WS_TRIM_TAGS = new Set(['pre', 'template', 'textarea', 'script', 'style']);
const WS_CHARS = ' \f\n\r\t\v\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff';
const NO_WS_REGEXP = new RegExp(`[^${WS_CHARS}]`);
const WS_REPLACE_REGEXP = new RegExp(`[${WS_CHARS}]{2,}`, 'g');
function hasPreserveWhitespacesAttr(attrs) {
  return attrs.some(attr => attr.name === PRESERVE_WS_ATTR_NAME);
}
function replaceNgsp(value) {
  return value.replace(new RegExp(NGSP_UNICODE, 'g'), ' ');
}
class WhitespaceVisitor {
  preserveSignificantWhitespace;
  originalNodeMap;
  requireContext;
  icuExpansionDepth = 0;
  constructor(preserveSignificantWhitespace, originalNodeMap, requireContext = true) {
    this.preserveSignificantWhitespace = preserveSignificantWhitespace;
    this.originalNodeMap = originalNodeMap;
    this.requireContext = requireContext;
  }
  visitElement(element, context) {
    if (SKIP_WS_TRIM_TAGS.has(element.name) || hasPreserveWhitespacesAttr(element.attrs)) {
      const newElement = new Element(element.name, visitAllWithSiblings(this, element.attrs), visitAllWithSiblings(this, element.directives), element.children, element.isSelfClosing, element.sourceSpan, element.startSourceSpan, element.endSourceSpan, element.isVoid, element.i18n, element.comments);
      this.originalNodeMap?.set(newElement, element);
      return newElement;
    }
    const newElement = new Element(element.name, element.attrs, element.directives, visitAllWithSiblings(this, element.children), element.isSelfClosing, element.sourceSpan, element.startSourceSpan, element.endSourceSpan, element.isVoid, element.i18n, element.comments);
    this.originalNodeMap?.set(newElement, element);
    return newElement;
  }
  visitAttribute(attribute, context) {
    return attribute.name !== PRESERVE_WS_ATTR_NAME ? attribute : null;
  }
  visitText(text, context) {
    const isNotBlank = text.value.match(NO_WS_REGEXP);
    const hasExpansionSibling = context && (context.prev instanceof Expansion || context.next instanceof Expansion);
    const inIcuExpansion = this.icuExpansionDepth > 0;
    if (inIcuExpansion && this.preserveSignificantWhitespace) return text;
    if (isNotBlank || hasExpansionSibling) {
      const tokens = text.tokens.map(token => token.type === 5 ? createWhitespaceProcessedTextToken(token) : token);
      if (!this.preserveSignificantWhitespace && tokens.length > 0) {
        const firstToken = tokens[0];
        tokens.splice(0, 1, trimLeadingWhitespace(firstToken, context));
        const lastToken = tokens[tokens.length - 1];
        tokens.splice(tokens.length - 1, 1, trimTrailingWhitespace(lastToken, context));
      }
      const processed = processWhitespace(text.value);
      const value = this.preserveSignificantWhitespace ? processed : trimLeadingAndTrailingWhitespace(processed, context);
      const result = new Text(value, text.sourceSpan, tokens, text.i18n);
      this.originalNodeMap?.set(result, text);
      return result;
    }
    return null;
  }
  visitComment(comment, context) {
    return comment;
  }
  visitExpansion(expansion, context) {
    this.icuExpansionDepth++;
    let newExpansion;
    try {
      newExpansion = new Expansion(expansion.switchValue, expansion.type, visitAllWithSiblings(this, expansion.cases), expansion.sourceSpan, expansion.switchValueSourceSpan, expansion.i18n);
    } finally {
      this.icuExpansionDepth--;
    }
    this.originalNodeMap?.set(newExpansion, expansion);
    return newExpansion;
  }
  visitExpansionCase(expansionCase, context) {
    const newExpansionCase = new ExpansionCase(expansionCase.value, visitAllWithSiblings(this, expansionCase.expression), expansionCase.sourceSpan, expansionCase.valueSourceSpan, expansionCase.expSourceSpan);
    this.originalNodeMap?.set(newExpansionCase, expansionCase);
    return newExpansionCase;
  }
  visitBlock(block, context) {
    const newBlock = new Block(block.name, block.parameters, visitAllWithSiblings(this, block.children), block.sourceSpan, block.nameSpan, block.startSourceSpan, block.endSourceSpan);
    this.originalNodeMap?.set(newBlock, block);
    return newBlock;
  }
  visitBlockParameter(parameter, context) {
    return parameter;
  }
  visitLetDeclaration(decl, context) {
    return decl;
  }
  visitComponent(node, context) {
    if (node.tagName && SKIP_WS_TRIM_TAGS.has(node.tagName) || hasPreserveWhitespacesAttr(node.attrs)) {
      const newElement = new Component(node.componentName, node.tagName, node.fullName, visitAllWithSiblings(this, node.attrs), visitAllWithSiblings(this, node.directives), node.children, node.isSelfClosing, node.sourceSpan, node.startSourceSpan, node.endSourceSpan, node.i18n, node.comments);
      this.originalNodeMap?.set(newElement, node);
      return newElement;
    }
    const newElement = new Component(node.componentName, node.tagName, node.fullName, node.attrs, node.directives, visitAllWithSiblings(this, node.children), node.isSelfClosing, node.sourceSpan, node.startSourceSpan, node.endSourceSpan, node.i18n, node.comments);
    this.originalNodeMap?.set(newElement, node);
    return newElement;
  }
  visitDirective(directive, context) {
    return directive;
  }
  visit(_node, context) {
    if (this.requireContext && !context) {
      throw new Error(`WhitespaceVisitor requires context. Visit via \`visitAllWithSiblings\` to get this context.`);
    }
    return false;
  }
}
function trimLeadingWhitespace(token, context) {
  if (token.type !== 5) return token;
  const isFirstTokenInTag = !context?.prev;
  if (!isFirstTokenInTag) return token;
  return transformTextToken(token, text => text.trimStart());
}
function trimTrailingWhitespace(token, context) {
  if (token.type !== 5) return token;
  const isLastTokenInTag = !context?.next;
  if (!isLastTokenInTag) return token;
  return transformTextToken(token, text => text.trimEnd());
}
function trimLeadingAndTrailingWhitespace(text, context) {
  const isFirstTokenInTag = !context?.prev;
  const isLastTokenInTag = !context?.next;
  const maybeTrimmedStart = isFirstTokenInTag ? text.trimStart() : text;
  const maybeTrimmed = isLastTokenInTag ? maybeTrimmedStart.trimEnd() : maybeTrimmedStart;
  return maybeTrimmed;
}
function createWhitespaceProcessedTextToken({
  type,
  parts,
  sourceSpan
}) {
  return {
    type,
    parts: [processWhitespace(parts[0])],
    sourceSpan
  };
}
function transformTextToken({
  type,
  parts,
  sourceSpan
}, transform) {
  return {
    type,
    parts: [transform(parts[0])],
    sourceSpan
  };
}
function processWhitespace(text) {
  return replaceNgsp(text).replace(WS_REPLACE_REGEXP, ' ');
}
function visitAllWithSiblings(visitor, nodes) {
  const result = [];
  nodes.forEach((ast, i) => {
    const context = {
      prev: nodes[i - 1],
      next: nodes[i + 1]
    };
    const astResult = ast.visit(visitor, context);
    if (astResult) {
      result.push(astResult);
    }
  });
  return result;
}

var TokenType;
(function (TokenType) {
  TokenType[TokenType["Character"] = 0] = "Character";
  TokenType[TokenType["Identifier"] = 1] = "Identifier";
  TokenType[TokenType["PrivateIdentifier"] = 2] = "PrivateIdentifier";
  TokenType[TokenType["Keyword"] = 3] = "Keyword";
  TokenType[TokenType["String"] = 4] = "String";
  TokenType[TokenType["Operator"] = 5] = "Operator";
  TokenType[TokenType["Number"] = 6] = "Number";
  TokenType[TokenType["RegExpBody"] = 7] = "RegExpBody";
  TokenType[TokenType["RegExpFlags"] = 8] = "RegExpFlags";
  TokenType[TokenType["Error"] = 9] = "Error";
})(TokenType || (TokenType = {}));
var StringTokenKind;
(function (StringTokenKind) {
  StringTokenKind[StringTokenKind["Plain"] = 0] = "Plain";
  StringTokenKind[StringTokenKind["TemplateLiteralPart"] = 1] = "TemplateLiteralPart";
  StringTokenKind[StringTokenKind["TemplateLiteralEnd"] = 2] = "TemplateLiteralEnd";
})(StringTokenKind || (StringTokenKind = {}));
const KEYWORDS = ['var', 'let', 'as', 'null', 'undefined', 'true', 'false', 'if', 'else', 'this', 'typeof', 'void', 'in', 'instanceof'];
class Lexer {
  tokenize(text) {
    return new _Scanner(text).scan();
  }
}
class Token {
  index;
  end;
  type;
  numValue;
  strValue;
  constructor(index, end, type, numValue, strValue) {
    this.index = index;
    this.end = end;
    this.type = type;
    this.numValue = numValue;
    this.strValue = strValue;
  }
  isCharacter(code) {
    return this.type === TokenType.Character && this.numValue === code;
  }
  isNumber() {
    return this.type === TokenType.Number;
  }
  isString() {
    return this.type === TokenType.String;
  }
  isOperator(operator) {
    return this.type === TokenType.Operator && this.strValue === operator;
  }
  isIdentifier() {
    return this.type === TokenType.Identifier;
  }
  isPrivateIdentifier() {
    return this.type === TokenType.PrivateIdentifier;
  }
  isKeyword() {
    return this.type === TokenType.Keyword;
  }
  isKeywordLet() {
    return this.type === TokenType.Keyword && this.strValue === 'let';
  }
  isKeywordAs() {
    return this.type === TokenType.Keyword && this.strValue === 'as';
  }
  isKeywordNull() {
    return this.type === TokenType.Keyword && this.strValue === 'null';
  }
  isKeywordUndefined() {
    return this.type === TokenType.Keyword && this.strValue === 'undefined';
  }
  isKeywordTrue() {
    return this.type === TokenType.Keyword && this.strValue === 'true';
  }
  isKeywordFalse() {
    return this.type === TokenType.Keyword && this.strValue === 'false';
  }
  isKeywordThis() {
    return this.type === TokenType.Keyword && this.strValue === 'this';
  }
  isKeywordTypeof() {
    return this.type === TokenType.Keyword && this.strValue === 'typeof';
  }
  isKeywordVoid() {
    return this.type === TokenType.Keyword && this.strValue === 'void';
  }
  isKeywordIn() {
    return this.type === TokenType.Keyword && this.strValue === 'in';
  }
  isKeywordInstanceOf() {
    return this.type === TokenType.Keyword && this.strValue === 'instanceof';
  }
  isError() {
    return this.type === TokenType.Error;
  }
  isRegExpBody() {
    return this.type === TokenType.RegExpBody;
  }
  isRegExpFlags() {
    return this.type === TokenType.RegExpFlags;
  }
  toNumber() {
    return this.type === TokenType.Number ? this.numValue : -1;
  }
  isTemplateLiteralPart() {
    return this.isString() && this.kind === StringTokenKind.TemplateLiteralPart;
  }
  isTemplateLiteralEnd() {
    return this.isString() && this.kind === StringTokenKind.TemplateLiteralEnd;
  }
  isTemplateLiteralInterpolationStart() {
    return this.isOperator('${');
  }
  toString() {
    switch (this.type) {
      case TokenType.Character:
      case TokenType.Identifier:
      case TokenType.Keyword:
      case TokenType.Operator:
      case TokenType.PrivateIdentifier:
      case TokenType.String:
      case TokenType.Error:
      case TokenType.RegExpBody:
      case TokenType.RegExpFlags:
        return this.strValue;
      case TokenType.Number:
        return this.numValue.toString();
      default:
        return null;
    }
  }
}
class StringToken extends Token {
  kind;
  constructor(index, end, strValue, kind) {
    super(index, end, TokenType.String, 0, strValue);
    this.kind = kind;
  }
}
function newCharacterToken(index, end, code) {
  return new Token(index, end, TokenType.Character, code, String.fromCharCode(code));
}
function newIdentifierToken(index, end, text) {
  return new Token(index, end, TokenType.Identifier, 0, text);
}
function newPrivateIdentifierToken(index, end, text) {
  return new Token(index, end, TokenType.PrivateIdentifier, 0, text);
}
function newKeywordToken(index, end, text) {
  return new Token(index, end, TokenType.Keyword, 0, text);
}
function newOperatorToken(index, end, text) {
  return new Token(index, end, TokenType.Operator, 0, text);
}
function newNumberToken(index, end, n) {
  return new Token(index, end, TokenType.Number, n, '');
}
function newErrorToken(index, end, message) {
  return new Token(index, end, TokenType.Error, 0, message);
}
function newRegExpBodyToken(index, end, text) {
  return new Token(index, end, TokenType.RegExpBody, 0, text);
}
function newRegExpFlagsToken(index, end, text) {
  return new Token(index, end, TokenType.RegExpFlags, 0, text);
}
const EOF = new Token(-1, -1, TokenType.Character, 0, '');
class _Scanner {
  input;
  tokens = [];
  length;
  peek = 0;
  index = -1;
  braceStack = [];
  constructor(input) {
    this.input = input;
    this.length = input.length;
    this.advance();
  }
  scan() {
    let token = this.scanToken();
    while (token !== null) {
      this.tokens.push(token);
      token = this.scanToken();
    }
    return this.tokens;
  }
  advance() {
    this.peek = ++this.index >= this.length ? $EOF : this.input.charCodeAt(this.index);
  }
  scanToken() {
    const input = this.input;
    const length = this.length;
    let peek = this.peek;
    let index = this.index;
    while (peek <= $SPACE) {
      if (++index >= length) {
        peek = $EOF;
        break;
      } else {
        peek = input.charCodeAt(index);
      }
    }
    this.peek = peek;
    this.index = index;
    if (index >= length) {
      return null;
    }
    if (isIdentifierStart(peek)) {
      return this.scanIdentifier();
    }
    if (isDigit(peek)) {
      return this.scanNumber(index);
    }
    const start = index;
    switch (peek) {
      case $PERIOD:
        this.advance();
        if (isDigit(this.peek)) {
          return this.scanNumber(start);
        }
        if (this.peek !== $PERIOD) {
          return newCharacterToken(start, this.index, $PERIOD);
        }
        this.advance();
        if (this.peek === $PERIOD) {
          this.advance();
          return newOperatorToken(start, this.index, '...');
        }
        return this.error(`Unexpected character [${String.fromCharCode(peek)}]`, 0);
      case $LPAREN:
      case $RPAREN:
      case $LBRACKET:
      case $RBRACKET:
      case $COMMA:
      case $COLON:
      case $SEMICOLON:
        return this.scanCharacter(start, peek);
      case $LBRACE:
        return this.scanOpenBrace(start, peek);
      case $RBRACE:
        return this.scanCloseBrace(start, peek);
      case $SQ:
      case $DQ:
        return this.scanString();
      case $BT:
        this.advance();
        return this.scanTemplateLiteralPart(start);
      case $HASH:
        return this.scanPrivateIdentifier();
      case $PLUS:
        return this.scanComplexOperator(start, '+', $EQ, '=');
      case $MINUS:
        return this.scanComplexOperator(start, '-', $EQ, '=');
      case $SLASH:
        return this.isStartOfRegex() ? this.scanRegex(index) : this.scanComplexOperator(start, '/', $EQ, '=');
      case $PERCENT:
        return this.scanComplexOperator(start, '%', $EQ, '=');
      case $CARET:
        return this.scanOperator(start, '^');
      case $STAR:
        return this.scanStar(start);
      case $QUESTION:
        return this.scanQuestion(start);
      case $LT:
      case $GT:
        return this.scanComplexOperator(start, String.fromCharCode(peek), $EQ, '=');
      case $BANG:
        return this.scanComplexOperator(start, '!', $EQ, '=', $EQ, '=');
      case $EQ:
        return this.scanEquals(start);
      case $AMPERSAND:
        return this.scanComplexOperator(start, '&', $AMPERSAND, '&', $EQ, '=');
      case $BAR:
        return this.scanComplexOperator(start, '|', $BAR, '|', $EQ, '=');
      case $NBSP:
        while (isWhitespace(this.peek)) this.advance();
        return this.scanToken();
    }
    this.advance();
    return this.error(`Unexpected character [${String.fromCharCode(peek)}]`, 0);
  }
  scanCharacter(start, code) {
    this.advance();
    return newCharacterToken(start, this.index, code);
  }
  scanOperator(start, str) {
    this.advance();
    return newOperatorToken(start, this.index, str);
  }
  scanOpenBrace(start, code) {
    this.braceStack.push('expression');
    this.advance();
    return newCharacterToken(start, this.index, code);
  }
  scanCloseBrace(start, code) {
    this.advance();
    const currentBrace = this.braceStack.pop();
    if (currentBrace === 'interpolation') {
      this.tokens.push(newCharacterToken(start, this.index, $RBRACE));
      return this.scanTemplateLiteralPart(this.index);
    }
    return newCharacterToken(start, this.index, code);
  }
  scanComplexOperator(start, one, twoCode, two, threeCode, three) {
    this.advance();
    let str = one;
    if (this.peek == twoCode) {
      this.advance();
      str += two;
    }
    if (threeCode != null && this.peek == threeCode) {
      this.advance();
      str += three;
    }
    return newOperatorToken(start, this.index, str);
  }
  scanEquals(start) {
    this.advance();
    let str = '=';
    if (this.peek === $EQ) {
      this.advance();
      str += '=';
    } else if (this.peek === $GT) {
      this.advance();
      str += '>';
      return newOperatorToken(start, this.index, str);
    }
    if (this.peek === $EQ) {
      this.advance();
      str += '=';
    }
    return newOperatorToken(start, this.index, str);
  }
  scanIdentifier() {
    const start = this.index;
    this.advance();
    while (isIdentifierPart(this.peek)) this.advance();
    const str = this.input.substring(start, this.index);
    return KEYWORDS.indexOf(str) > -1 ? newKeywordToken(start, this.index, str) : newIdentifierToken(start, this.index, str);
  }
  scanPrivateIdentifier() {
    const start = this.index;
    this.advance();
    if (!isIdentifierStart(this.peek)) {
      return this.error('Invalid character [#]', -1);
    }
    while (isIdentifierPart(this.peek)) this.advance();
    const identifierName = this.input.substring(start, this.index);
    return newPrivateIdentifierToken(start, this.index, identifierName);
  }
  scanNumber(start) {
    let simple = this.index === start;
    let hasSeparators = false;
    this.advance();
    while (true) {
      if (isDigit(this.peek)) ; else if (this.peek === $_) {
        if (!isDigit(this.input.charCodeAt(this.index - 1)) || !isDigit(this.input.charCodeAt(this.index + 1))) {
          return this.error('Invalid numeric separator', 0);
        }
        hasSeparators = true;
      } else if (this.peek === $PERIOD) {
        simple = false;
      } else if (isExponentStart(this.peek)) {
        this.advance();
        if (isExponentSign(this.peek)) this.advance();
        if (!isDigit(this.peek)) return this.error('Invalid exponent', -1);
        simple = false;
      } else {
        break;
      }
      this.advance();
    }
    let str = this.input.substring(start, this.index);
    if (hasSeparators) {
      str = str.replace(/_/g, '');
    }
    const value = simple ? parseIntAutoRadix(str) : parseFloat(str);
    return newNumberToken(start, this.index, value);
  }
  scanString() {
    const start = this.index;
    const quote = this.peek;
    this.advance();
    let buffer = '';
    let marker = this.index;
    const input = this.input;
    while (this.peek != quote) {
      if (this.peek == $BACKSLASH) {
        const result = this.scanStringBackslash(buffer, marker);
        if (typeof result !== 'string') {
          return result;
        }
        buffer = result;
        marker = this.index;
      } else if (this.peek == $EOF) {
        return this.error('Unterminated quote', 0);
      } else {
        this.advance();
      }
    }
    const last = input.substring(marker, this.index);
    this.advance();
    return new StringToken(start, this.index, buffer + last, StringTokenKind.Plain);
  }
  scanQuestion(start) {
    this.advance();
    let operator = '?';
    if (this.peek === $QUESTION) {
      operator += '?';
      this.advance();
      if (this.peek === $EQ) {
        operator += '=';
        this.advance();
      }
    } else if (this.peek === $PERIOD) {
      operator += '.';
      this.advance();
    }
    return newOperatorToken(start, this.index, operator);
  }
  scanTemplateLiteralPart(start) {
    let buffer = '';
    let marker = this.index;
    while (this.peek !== $BT) {
      if (this.peek === $BACKSLASH) {
        const result = this.scanStringBackslash(buffer, marker);
        if (typeof result !== 'string') {
          return result;
        }
        buffer = result;
        marker = this.index;
      } else if (this.peek === $$) {
        const dollar = this.index;
        this.advance();
        if (this.peek === $LBRACE) {
          this.braceStack.push('interpolation');
          this.tokens.push(new StringToken(start, dollar, buffer + this.input.substring(marker, dollar), StringTokenKind.TemplateLiteralPart));
          this.advance();
          return newOperatorToken(dollar, this.index, this.input.substring(dollar, this.index));
        }
      } else if (this.peek === $EOF) {
        return this.error('Unterminated template literal', 0);
      } else {
        this.advance();
      }
    }
    const last = this.input.substring(marker, this.index);
    this.advance();
    return new StringToken(start, this.index, buffer + last, StringTokenKind.TemplateLiteralEnd);
  }
  error(message, offset) {
    const position = this.index + offset;
    return newErrorToken(position, this.index, `Lexer Error: ${message} at column ${position} in expression [${this.input}]`);
  }
  scanStringBackslash(buffer, marker) {
    buffer += this.input.substring(marker, this.index);
    let unescapedCode;
    this.advance();
    if (this.peek === $u) {
      const hex = this.input.substring(this.index + 1, this.index + 5);
      if (/^[0-9a-f]+$/i.test(hex)) {
        unescapedCode = parseInt(hex, 16);
      } else {
        return this.error(`Invalid unicode escape [\\u${hex}]`, 0);
      }
      for (let i = 0; i < 5; i++) {
        this.advance();
      }
    } else {
      unescapedCode = unescape(this.peek);
      this.advance();
    }
    buffer += String.fromCharCode(unescapedCode);
    return buffer;
  }
  scanStar(start) {
    this.advance();
    let operator = '*';
    if (this.peek === $STAR) {
      operator += '*';
      this.advance();
      if (this.peek === $EQ) {
        operator += '=';
        this.advance();
      }
    } else if (this.peek === $EQ) {
      operator += '=';
      this.advance();
    }
    return newOperatorToken(start, this.index, operator);
  }
  isStartOfRegex() {
    if (this.tokens.length === 0) {
      return true;
    }
    const prevToken = this.tokens[this.tokens.length - 1];
    if (prevToken.isOperator('!')) {
      const beforePrevToken = this.tokens.length > 1 ? this.tokens[this.tokens.length - 2] : null;
      const isNegation = beforePrevToken === null || beforePrevToken.type !== TokenType.Identifier && !beforePrevToken.isCharacter($RPAREN) && !beforePrevToken.isCharacter($RBRACKET);
      return isNegation;
    }
    return prevToken.type === TokenType.Operator || prevToken.isCharacter($LPAREN) || prevToken.isCharacter($LBRACKET) || prevToken.isCharacter($COMMA) || prevToken.isCharacter($COLON);
  }
  scanRegex(tokenStart) {
    this.advance();
    const textStart = this.index;
    let inEscape = false;
    let inCharacterClass = false;
    while (true) {
      const peek = this.peek;
      if (peek === $EOF) {
        return this.error('Unterminated regular expression', 0);
      }
      if (inEscape) {
        inEscape = false;
      } else if (peek === $BACKSLASH) {
        inEscape = true;
      } else if (peek === $LBRACKET) {
        inCharacterClass = true;
      } else if (peek === $RBRACKET) {
        inCharacterClass = false;
      } else if (peek === $SLASH && !inCharacterClass) {
        break;
      }
      this.advance();
    }
    const value = this.input.substring(textStart, this.index);
    this.advance();
    const bodyToken = newRegExpBodyToken(tokenStart, this.index, value);
    const flagsToken = this.scanRegexFlags(this.index);
    if (flagsToken !== null) {
      this.tokens.push(bodyToken);
      return flagsToken;
    }
    return bodyToken;
  }
  scanRegexFlags(start) {
    if (!isAsciiLetter(this.peek)) {
      return null;
    }
    while (isAsciiLetter(this.peek)) {
      this.advance();
    }
    return newRegExpFlagsToken(start, this.index, this.input.substring(start, this.index));
  }
}
function isIdentifierStart(code) {
  return $a <= code && code <= $z || $A <= code && code <= $Z || code == $_ || code == $$;
}
function isIdentifierPart(code) {
  return isAsciiLetter(code) || isDigit(code) || code == $_ || code == $$;
}
function isExponentStart(code) {
  return code == $e || code == $E;
}
function isExponentSign(code) {
  return code == $MINUS || code == $PLUS;
}
function unescape(code) {
  switch (code) {
    case $n:
      return $LF;
    case $f:
      return $FF;
    case $r:
      return $CR;
    case $t:
      return $TAB;
    case $v:
      return $VTAB;
    default:
      return code;
  }
}
function parseIntAutoRadix(text) {
  const result = parseInt(text);
  if (isNaN(result)) {
    throw new Error('Invalid integer literal when parsing ' + text);
  }
  return result;
}

class SplitInterpolation {
  strings;
  expressions;
  offsets;
  constructor(strings, expressions, offsets) {
    this.strings = strings;
    this.expressions = expressions;
    this.offsets = offsets;
  }
}
class TemplateBindingParseResult {
  templateBindings;
  warnings;
  errors;
  constructor(templateBindings, warnings, errors) {
    this.templateBindings = templateBindings;
    this.warnings = warnings;
    this.errors = errors;
  }
}
function getLocation(span) {
  return span.start.toString() || '(unknown)';
}
class Parser {
  _lexer;
  _supportsDirectPipeReferences;
  constructor(_lexer, _supportsDirectPipeReferences = false) {
    this._lexer = _lexer;
    this._supportsDirectPipeReferences = _supportsDirectPipeReferences;
  }
  parseAction(input, parseSourceSpan, absoluteOffset) {
    const errors = [];
    this._checkNoInterpolation(errors, input, parseSourceSpan);
    const {
      stripped: sourceToLex
    } = this._stripComments(input);
    const tokens = this._lexer.tokenize(sourceToLex);
    const ast = new _ParseAST(input, parseSourceSpan, absoluteOffset, tokens, 1, errors, 0, this._supportsDirectPipeReferences).parseChain();
    return new ASTWithSource(ast, input, getLocation(parseSourceSpan), absoluteOffset, errors);
  }
  parseBinding(input, parseSourceSpan, absoluteOffset) {
    const errors = [];
    const ast = this._parseBindingAst(input, parseSourceSpan, absoluteOffset, errors);
    return new ASTWithSource(ast, input, getLocation(parseSourceSpan), absoluteOffset, errors);
  }
  checkSimpleExpression(ast) {
    const checker = new SimpleExpressionChecker();
    ast.visit(checker);
    return checker.errors;
  }
  parseSimpleBinding(input, parseSourceSpan, absoluteOffset) {
    const errors = [];
    const ast = this._parseBindingAst(input, parseSourceSpan, absoluteOffset, errors);
    const simplExpressionErrors = this.checkSimpleExpression(ast);
    if (simplExpressionErrors.length > 0) {
      errors.push(getParseError(`Host binding expression cannot contain ${simplExpressionErrors.join(' ')}`, input, '', parseSourceSpan));
    }
    return new ASTWithSource(ast, input, getLocation(parseSourceSpan), absoluteOffset, errors);
  }
  _parseBindingAst(input, parseSourceSpan, absoluteOffset, errors) {
    this._checkNoInterpolation(errors, input, parseSourceSpan);
    const {
      stripped: sourceToLex
    } = this._stripComments(input);
    const tokens = this._lexer.tokenize(sourceToLex);
    return new _ParseAST(input, parseSourceSpan, absoluteOffset, tokens, 0, errors, 0, this._supportsDirectPipeReferences).parseChain();
  }
  parseTemplateBindings(templateKey, templateValue, parseSourceSpan, absoluteKeyOffset, absoluteValueOffset) {
    const tokens = this._lexer.tokenize(templateValue);
    const errors = [];
    const parser = new _ParseAST(templateValue, parseSourceSpan, absoluteValueOffset, tokens, 0, errors, 0, this._supportsDirectPipeReferences);
    return parser.parseTemplateBindings({
      source: templateKey,
      span: new AbsoluteSourceSpan(absoluteKeyOffset, absoluteKeyOffset + templateKey.length)
    });
  }
  parseInterpolation(input, parseSourceSpan, absoluteOffset, interpolatedTokens) {
    const errors = [];
    const {
      strings,
      expressions,
      offsets
    } = this.splitInterpolation(input, parseSourceSpan, errors, interpolatedTokens);
    if (expressions.length === 0) return null;
    const expressionNodes = [];
    for (let i = 0; i < expressions.length; ++i) {
      const expressionSpan = interpolatedTokens?.[i * 2 + 1]?.sourceSpan;
      const expressionText = expressions[i].text;
      const {
        stripped: sourceToLex,
        hasComments
      } = this._stripComments(expressionText);
      const tokens = this._lexer.tokenize(sourceToLex);
      if (hasComments && sourceToLex.trim().length === 0 && tokens.length === 0) {
        errors.push(getParseError('Interpolation expression cannot only contain a comment', input, `at column ${expressions[i].start} in`, parseSourceSpan));
        continue;
      }
      const ast = new _ParseAST(expressionSpan ? expressionText : input, expressionSpan || parseSourceSpan, absoluteOffset, tokens, 0, errors, offsets[i], this._supportsDirectPipeReferences).parseChain();
      expressionNodes.push(ast);
    }
    return this.createInterpolationAst(strings.map(s => s.text), expressionNodes, input, getLocation(parseSourceSpan), absoluteOffset, errors);
  }
  parseInterpolationExpression(expression, parseSourceSpan, absoluteOffset) {
    const {
      stripped: sourceToLex
    } = this._stripComments(expression);
    const tokens = this._lexer.tokenize(sourceToLex);
    const errors = [];
    const ast = new _ParseAST(expression, parseSourceSpan, absoluteOffset, tokens, 0, errors, 0, this._supportsDirectPipeReferences).parseChain();
    const strings = ['', ''];
    return this.createInterpolationAst(strings, [ast], expression, getLocation(parseSourceSpan), absoluteOffset, errors);
  }
  createInterpolationAst(strings, expressions, input, location, absoluteOffset, errors) {
    const span = new ParseSpan(0, input.length);
    const interpolation = new Interpolation$1(span, span.toAbsolute(absoluteOffset), strings, expressions);
    return new ASTWithSource(interpolation, input, location, absoluteOffset, errors);
  }
  splitInterpolation(input, parseSourceSpan, errors, interpolatedTokens) {
    const strings = [];
    const expressions = [];
    const offsets = [];
    const inputToTemplateIndexMap = interpolatedTokens ? getIndexMapForOriginalTemplate(interpolatedTokens) : null;
    let i = 0;
    let atInterpolation = false;
    let extendLastString = false;
    const interpStart = '{{';
    const interpEnd = '}}';
    while (i < input.length) {
      if (!atInterpolation) {
        const start = i;
        i = input.indexOf(interpStart, i);
        if (i === -1) {
          i = input.length;
        }
        const text = input.substring(start, i);
        strings.push({
          text,
          start,
          end: i
        });
        atInterpolation = true;
      } else {
        const fullStart = i;
        const exprStart = fullStart + interpStart.length;
        const exprEnd = this._getInterpolationEndIndex(input, interpEnd, exprStart);
        if (exprEnd === -1) {
          atInterpolation = false;
          extendLastString = true;
          break;
        }
        const fullEnd = exprEnd + interpEnd.length;
        const text = input.substring(exprStart, exprEnd);
        if (text.trim().length === 0) {
          errors.push(getParseError('Blank expressions are not allowed in interpolated strings', input, `at column ${i} in`, parseSourceSpan));
        }
        expressions.push({
          text,
          start: fullStart,
          end: fullEnd
        });
        const startInOriginalTemplate = inputToTemplateIndexMap?.get(fullStart) ?? fullStart;
        const offset = startInOriginalTemplate + interpStart.length;
        offsets.push(offset);
        i = fullEnd;
        atInterpolation = false;
      }
    }
    if (!atInterpolation) {
      if (extendLastString) {
        const piece = strings[strings.length - 1];
        piece.text += input.substring(i);
        piece.end = input.length;
      } else {
        strings.push({
          text: input.substring(i),
          start: i,
          end: input.length
        });
      }
    }
    return new SplitInterpolation(strings, expressions, offsets);
  }
  wrapLiteralPrimitive(input, sourceSpanOrLocation, absoluteOffset) {
    const span = new ParseSpan(0, input == null ? 0 : input.length);
    return new ASTWithSource(new LiteralPrimitive(span, span.toAbsolute(absoluteOffset), input), input, typeof sourceSpanOrLocation === 'string' ? sourceSpanOrLocation : getLocation(sourceSpanOrLocation), absoluteOffset, []);
  }
  _stripComments(input) {
    const i = this._commentStart(input);
    return i != null ? {
      stripped: input.substring(0, i),
      hasComments: true
    } : {
      stripped: input,
      hasComments: false
    };
  }
  _commentStart(input) {
    let outerQuote = null;
    for (let i = 0; i < input.length - 1; i++) {
      const char = input.charCodeAt(i);
      const nextChar = input.charCodeAt(i + 1);
      if (char === $SLASH && nextChar == $SLASH && outerQuote == null) return i;
      if (outerQuote === char) {
        outerQuote = null;
      } else if (outerQuote == null && isQuote(char)) {
        outerQuote = char;
      }
    }
    return null;
  }
  _checkNoInterpolation(errors, input, parseSourceSpan) {
    let startIndex = -1;
    let endIndex = -1;
    for (const charIndex of this._forEachUnquotedChar(input, 0)) {
      if (startIndex === -1) {
        if (input.startsWith('{{')) {
          startIndex = charIndex;
        }
      } else {
        endIndex = this._getInterpolationEndIndex(input, '}}', charIndex);
        if (endIndex > -1) {
          break;
        }
      }
    }
    if (startIndex > -1 && endIndex > -1) {
      errors.push(getParseError(`Got interpolation ({{}}) where expression was expected`, input, `at column ${startIndex} in`, parseSourceSpan));
    }
  }
  _getInterpolationEndIndex(input, expressionEnd, start) {
    for (const charIndex of this._forEachUnquotedChar(input, start)) {
      if (input.startsWith(expressionEnd, charIndex)) {
        return charIndex;
      }
      if (input.startsWith('//', charIndex)) {
        return input.indexOf(expressionEnd, charIndex);
      }
    }
    return -1;
  }
  *_forEachUnquotedChar(input, start) {
    let currentQuote = null;
    let escapeCount = 0;
    for (let i = start; i < input.length; i++) {
      const char = input[i];
      if (isQuote(input.charCodeAt(i)) && (currentQuote === null || currentQuote === char) && escapeCount % 2 === 0) {
        currentQuote = currentQuote === null ? char : null;
      } else if (currentQuote === null) {
        yield i;
      }
      escapeCount = char === '\\' ? escapeCount + 1 : 0;
    }
  }
}
var ParseContextFlags;
(function (ParseContextFlags) {
  ParseContextFlags[ParseContextFlags["None"] = 0] = "None";
  ParseContextFlags[ParseContextFlags["Writable"] = 1] = "Writable";
})(ParseContextFlags || (ParseContextFlags = {}));
const SUPPORTED_REGEX_FLAGS = new Set(['d', 'g', 'i', 'm', 's', 'u', 'v', 'y']);
class _ParseAST {
  input;
  parseSourceSpan;
  absoluteOffset;
  tokens;
  parseFlags;
  errors;
  offset;
  supportsDirectPipeReferences;
  rparensExpected = 0;
  rbracketsExpected = 0;
  rbracesExpected = 0;
  context = ParseContextFlags.None;
  sourceSpanCache = new Map();
  index = 0;
  constructor(input, parseSourceSpan, absoluteOffset, tokens, parseFlags, errors, offset, supportsDirectPipeReferences) {
    this.input = input;
    this.parseSourceSpan = parseSourceSpan;
    this.absoluteOffset = absoluteOffset;
    this.tokens = tokens;
    this.parseFlags = parseFlags;
    this.errors = errors;
    this.offset = offset;
    this.supportsDirectPipeReferences = supportsDirectPipeReferences;
  }
  peek(offset) {
    const i = this.index + offset;
    return i < this.tokens.length ? this.tokens[i] : EOF;
  }
  get next() {
    return this.peek(0);
  }
  get atEOF() {
    return this.index >= this.tokens.length;
  }
  get inputIndex() {
    return this.atEOF ? this.currentEndIndex : this.next.index + this.offset;
  }
  get currentEndIndex() {
    if (this.index > 0) {
      const curToken = this.peek(-1);
      return curToken.end + this.offset;
    }
    if (this.tokens.length === 0) {
      return this.input.length + this.offset;
    }
    return this.next.index + this.offset;
  }
  get currentAbsoluteOffset() {
    return this.absoluteOffset + this.inputIndex;
  }
  span(start, artificialEndIndex) {
    let endIndex = this.currentEndIndex;
    if (artificialEndIndex !== undefined && artificialEndIndex > this.currentEndIndex) {
      endIndex = artificialEndIndex;
    }
    if (start > endIndex) {
      const tmp = endIndex;
      endIndex = start;
      start = tmp;
    }
    return new ParseSpan(start, endIndex);
  }
  sourceSpan(start, artificialEndIndex) {
    const serial = `${start}@${this.inputIndex}:${artificialEndIndex}`;
    if (!this.sourceSpanCache.has(serial)) {
      this.sourceSpanCache.set(serial, this.span(start, artificialEndIndex).toAbsolute(this.absoluteOffset));
    }
    return this.sourceSpanCache.get(serial);
  }
  advance() {
    this.index++;
  }
  withContext(context, cb) {
    this.context |= context;
    const ret = cb();
    this.context ^= context;
    return ret;
  }
  consumeOptionalCharacter(code) {
    if (this.next.isCharacter(code)) {
      this.advance();
      return true;
    } else {
      return false;
    }
  }
  peekKeywordLet() {
    return this.next.isKeywordLet();
  }
  peekKeywordAs() {
    return this.next.isKeywordAs();
  }
  expectCharacter(code) {
    if (this.consumeOptionalCharacter(code)) return;
    this.error(`Missing expected ${String.fromCharCode(code)}`);
  }
  consumeOptionalOperator(op) {
    if (this.next.isOperator(op)) {
      this.advance();
      return true;
    } else {
      return false;
    }
  }
  isAssignmentOperator(token) {
    return token.type === TokenType.Operator && Binary.isAssignmentOperation(token.strValue);
  }
  expectOperator(operator) {
    if (this.consumeOptionalOperator(operator)) return;
    this.error(`Missing expected operator ${operator}`);
  }
  prettyPrintToken(tok) {
    return tok === EOF ? 'end of input' : `token ${tok}`;
  }
  expectIdentifierOrKeyword() {
    const n = this.next;
    if (!n.isIdentifier() && !n.isKeyword()) {
      if (n.isPrivateIdentifier()) {
        this._reportErrorForPrivateIdentifier(n, 'expected identifier or keyword');
      } else {
        this.error(`Unexpected ${this.prettyPrintToken(n)}, expected identifier or keyword`);
      }
      return null;
    }
    this.advance();
    return n.toString();
  }
  expectIdentifierOrKeywordOrString() {
    const n = this.next;
    if (!n.isIdentifier() && !n.isKeyword() && !n.isString()) {
      if (n.isPrivateIdentifier()) {
        this._reportErrorForPrivateIdentifier(n, 'expected identifier, keyword or string');
      } else {
        this.error(`Unexpected ${this.prettyPrintToken(n)}, expected identifier, keyword, or string`);
      }
      return '';
    }
    this.advance();
    return n.toString();
  }
  parseChain() {
    const exprs = [];
    const start = this.inputIndex;
    while (this.index < this.tokens.length) {
      const expr = this.parsePipe();
      exprs.push(expr);
      if (this.consumeOptionalCharacter($SEMICOLON)) {
        if (!(this.parseFlags & 1)) {
          this.error('Binding expression cannot contain chained expression');
        }
        while (this.consumeOptionalCharacter($SEMICOLON)) {}
      } else if (this.index < this.tokens.length) {
        const errorIndex = this.index;
        this.error(`Unexpected token '${this.next}'`);
        if (this.index === errorIndex) {
          break;
        }
      }
    }
    if (exprs.length === 0) {
      const artificialStart = this.offset;
      const artificialEnd = this.offset + this.input.length;
      return new EmptyExpr$1(this.span(artificialStart, artificialEnd), this.sourceSpan(artificialStart, artificialEnd));
    }
    if (exprs.length == 1) return exprs[0];
    return new Chain(this.span(start), this.sourceSpan(start), exprs);
  }
  parsePipe() {
    const start = this.inputIndex;
    let result = this.parseExpression();
    if (this.consumeOptionalOperator('|')) {
      if (this.parseFlags & 1) {
        this.error(`Cannot have a pipe in an action expression`);
      }
      do {
        const nameStart = this.inputIndex;
        let nameId = this.expectIdentifierOrKeyword();
        let nameSpan;
        let fullSpanEnd = undefined;
        if (nameId !== null) {
          nameSpan = this.sourceSpan(nameStart);
        } else {
          nameId = '';
          fullSpanEnd = this.next.index !== -1 ? this.next.index : this.input.length + this.offset;
          nameSpan = new ParseSpan(fullSpanEnd, fullSpanEnd).toAbsolute(this.absoluteOffset);
        }
        const args = [];
        while (this.consumeOptionalCharacter($COLON)) {
          args.push(this.parseExpression());
        }
        let type;
        if (this.supportsDirectPipeReferences) {
          const charCode = nameId.charCodeAt(0);
          type = charCode === $_ || charCode >= $A && charCode <= $Z ? BindingPipeType.ReferencedDirectly : BindingPipeType.ReferencedByName;
        } else {
          type = BindingPipeType.ReferencedByName;
        }
        result = new BindingPipe(this.span(start), this.sourceSpan(start, fullSpanEnd), result, nameId, args, type, nameSpan);
      } while (this.consumeOptionalOperator('|'));
    }
    return result;
  }
  parseExpression() {
    return this.parseConditional();
  }
  parseConditional() {
    const start = this.inputIndex;
    const result = this.parseLogicalOr();
    if (this.consumeOptionalOperator('?')) {
      const yes = this.parsePipe();
      let no;
      if (!this.consumeOptionalCharacter($COLON)) {
        const end = this.inputIndex;
        const expression = this.input.substring(start, end);
        this.error(`Conditional expression ${expression} requires all 3 expressions`);
        no = new EmptyExpr$1(this.span(start), this.sourceSpan(start));
      } else {
        no = this.parsePipe();
      }
      return new Conditional(this.span(start), this.sourceSpan(start), result, yes, no);
    } else {
      return result;
    }
  }
  parseLogicalOr() {
    const start = this.inputIndex;
    let result = this.parseLogicalAnd();
    while (this.consumeOptionalOperator('||')) {
      const right = this.parseLogicalAnd();
      result = new Binary(this.span(start), this.sourceSpan(start), '||', result, right);
    }
    return result;
  }
  parseLogicalAnd() {
    const start = this.inputIndex;
    let result = this.parseNullishCoalescing();
    while (this.consumeOptionalOperator('&&')) {
      const right = this.parseNullishCoalescing();
      result = new Binary(this.span(start), this.sourceSpan(start), '&&', result, right);
    }
    return result;
  }
  parseNullishCoalescing() {
    const start = this.inputIndex;
    let result = this.parseEquality();
    while (this.consumeOptionalOperator('??')) {
      const right = this.parseEquality();
      result = new Binary(this.span(start), this.sourceSpan(start), '??', result, right);
    }
    return result;
  }
  parseEquality() {
    const start = this.inputIndex;
    let result = this.parseRelational();
    while (this.next.type == TokenType.Operator) {
      const operator = this.next.strValue;
      switch (operator) {
        case '==':
        case '===':
        case '!=':
        case '!==':
          this.advance();
          const right = this.parseRelational();
          result = new Binary(this.span(start), this.sourceSpan(start), operator, result, right);
          continue;
      }
      break;
    }
    return result;
  }
  parseRelational() {
    const start = this.inputIndex;
    let result = this.parseAdditive();
    while (this.next.type == TokenType.Operator || this.next.isKeywordIn() || this.next.isKeywordInstanceOf()) {
      const operator = this.next.strValue;
      switch (operator) {
        case '<':
        case '>':
        case '<=':
        case '>=':
        case 'in':
        case 'instanceof':
          this.advance();
          const right = this.parseAdditive();
          result = new Binary(this.span(start), this.sourceSpan(start), operator, result, right);
          continue;
      }
      break;
    }
    return result;
  }
  parseAdditive() {
    const start = this.inputIndex;
    let result = this.parseMultiplicative();
    while (this.next.type == TokenType.Operator) {
      const operator = this.next.strValue;
      switch (operator) {
        case '+':
        case '-':
          this.advance();
          let right = this.parseMultiplicative();
          result = new Binary(this.span(start), this.sourceSpan(start), operator, result, right);
          continue;
      }
      break;
    }
    return result;
  }
  parseMultiplicative() {
    const start = this.inputIndex;
    let result = this.parseExponentiation();
    while (this.next.type == TokenType.Operator) {
      const operator = this.next.strValue;
      switch (operator) {
        case '*':
        case '%':
        case '/':
          this.advance();
          const right = this.parseExponentiation();
          result = new Binary(this.span(start), this.sourceSpan(start), operator, result, right);
          continue;
      }
      break;
    }
    return result;
  }
  parseExponentiation() {
    const start = this.inputIndex;
    let result = this.parsePrefix();
    while (this.next.type == TokenType.Operator && this.next.strValue === '**') {
      if (result instanceof Unary || result instanceof PrefixNot || result instanceof TypeofExpression || result instanceof VoidExpression) {
        this.error('Unary operator used immediately before exponentiation expression. Parenthesis must be used to disambiguate operator precedence');
      }
      this.advance();
      const right = this.parseExponentiation();
      result = new Binary(this.span(start), this.sourceSpan(start), '**', result, right);
    }
    return result;
  }
  parsePrefix() {
    if (this.next.type == TokenType.Operator) {
      const start = this.inputIndex;
      const operator = this.next.strValue;
      let result;
      switch (operator) {
        case '+':
          this.advance();
          result = this.parsePrefix();
          return Unary.createPlus(this.span(start), this.sourceSpan(start), result);
        case '-':
          this.advance();
          result = this.parsePrefix();
          return Unary.createMinus(this.span(start), this.sourceSpan(start), result);
        case '!':
          this.advance();
          result = this.parsePrefix();
          return new PrefixNot(this.span(start), this.sourceSpan(start), result);
      }
    } else if (this.next.isKeywordTypeof()) {
      const start = this.inputIndex;
      this.advance();
      const result = this.parsePrefix();
      return new TypeofExpression(this.span(start), this.sourceSpan(start), result);
    } else if (this.next.isKeywordVoid()) {
      const start = this.inputIndex;
      this.advance();
      const result = this.parsePrefix();
      return new VoidExpression(this.span(start), this.sourceSpan(start), result);
    }
    return this.parseCallChain();
  }
  parseCallChain() {
    const start = this.inputIndex;
    let result = this.parsePrimary();
    while (true) {
      if (this.consumeOptionalCharacter($PERIOD)) {
        result = this.parseAccessMember(result, start, false);
      } else if (this.consumeOptionalOperator('?.')) {
        if (this.consumeOptionalCharacter($LPAREN)) {
          result = this.parseCall(result, start, true);
        } else {
          result = this.consumeOptionalCharacter($LBRACKET) ? this.parseKeyedReadOrWrite(result, start, true) : this.parseAccessMember(result, start, true);
        }
      } else if (this.consumeOptionalCharacter($LBRACKET)) {
        result = this.parseKeyedReadOrWrite(result, start, false);
      } else if (this.consumeOptionalCharacter($LPAREN)) {
        result = this.parseCall(result, start, false);
      } else if (this.consumeOptionalOperator('!')) {
        result = new NonNullAssert(this.span(start), this.sourceSpan(start), result);
      } else if (this.next.isTemplateLiteralEnd()) {
        result = this.parseNoInterpolationTaggedTemplateLiteral(result, start);
      } else if (this.next.isTemplateLiteralPart()) {
        result = this.parseTaggedTemplateLiteral(result, start);
      } else {
        return result;
      }
    }
  }
  parsePrimary() {
    const start = this.inputIndex;
    if (this.isArrowFunction()) {
      return this.parseArrowFunction(start);
    } else if (this.consumeOptionalCharacter($LPAREN)) {
      this.rparensExpected++;
      const result = this.parsePipe();
      if (!this.consumeOptionalCharacter($RPAREN)) {
        this.error('Missing closing parentheses');
        this.consumeOptionalCharacter($RPAREN);
      }
      this.rparensExpected--;
      return new ParenthesizedExpression(this.span(start), this.sourceSpan(start), result);
    } else if (this.next.isKeywordNull()) {
      this.advance();
      return new LiteralPrimitive(this.span(start), this.sourceSpan(start), null);
    } else if (this.next.isKeywordUndefined()) {
      this.advance();
      return new LiteralPrimitive(this.span(start), this.sourceSpan(start), undefined);
    } else if (this.next.isKeywordTrue()) {
      this.advance();
      return new LiteralPrimitive(this.span(start), this.sourceSpan(start), true);
    } else if (this.next.isKeywordFalse()) {
      this.advance();
      return new LiteralPrimitive(this.span(start), this.sourceSpan(start), false);
    } else if (this.next.isKeywordThis()) {
      this.advance();
      return new ThisReceiver(this.span(start), this.sourceSpan(start));
    } else if (this.consumeOptionalCharacter($LBRACKET)) {
      return this.parseLiteralArray(start);
    } else if (this.next.isCharacter($LBRACE)) {
      return this.parseLiteralMap();
    } else if (this.next.isIdentifier()) {
      return this.parseAccessMember(new ImplicitReceiver(this.span(start), this.sourceSpan(start)), start, false);
    } else if (this.next.isNumber()) {
      const value = this.next.toNumber();
      this.advance();
      return new LiteralPrimitive(this.span(start), this.sourceSpan(start), value);
    } else if (this.next.isTemplateLiteralEnd()) {
      return this.parseNoInterpolationTemplateLiteral();
    } else if (this.next.isTemplateLiteralPart()) {
      return this.parseTemplateLiteral();
    } else if (this.next.isString() && this.next.kind === StringTokenKind.Plain) {
      const literalValue = this.next.toString();
      this.advance();
      return new LiteralPrimitive(this.span(start), this.sourceSpan(start), literalValue);
    } else if (this.next.isPrivateIdentifier()) {
      this._reportErrorForPrivateIdentifier(this.next, null);
      return new EmptyExpr$1(this.span(start), this.sourceSpan(start));
    } else if (this.next.isRegExpBody()) {
      return this.parseRegularExpressionLiteral();
    } else if (this.index >= this.tokens.length) {
      this.error(`Unexpected end of expression: ${this.input}`);
      return new EmptyExpr$1(this.span(start), this.sourceSpan(start));
    } else {
      this.error(`Unexpected token ${this.next}`);
      return new EmptyExpr$1(this.span(start), this.sourceSpan(start));
    }
  }
  parseLiteralArray(arrayStart) {
    this.rbracketsExpected++;
    const elements = [];
    do {
      if (this.next.isOperator('...')) {
        elements.push(this.parseSpreadElement());
      } else if (!this.next.isCharacter($RBRACKET)) {
        elements.push(this.parsePipe());
      } else {
        break;
      }
    } while (this.consumeOptionalCharacter($COMMA));
    this.rbracketsExpected--;
    this.expectCharacter($RBRACKET);
    return new LiteralArray(this.span(arrayStart), this.sourceSpan(arrayStart), elements);
  }
  parseLiteralMap() {
    const keys = [];
    const values = [];
    const start = this.inputIndex;
    this.expectCharacter($LBRACE);
    if (!this.consumeOptionalCharacter($RBRACE)) {
      this.rbracesExpected++;
      do {
        const keyStart = this.inputIndex;
        if (this.next.isOperator('...')) {
          this.advance();
          keys.push({
            kind: 'spread',
            span: this.span(keyStart),
            sourceSpan: this.sourceSpan(keyStart)
          });
          values.push(this.parsePipe());
          continue;
        }
        const quoted = this.next.isString();
        const key = this.expectIdentifierOrKeywordOrString();
        const keySpan = this.span(keyStart);
        const keySourceSpan = this.sourceSpan(keyStart);
        const literalMapKey = {
          kind: 'property',
          key,
          quoted,
          span: keySpan,
          sourceSpan: keySourceSpan
        };
        keys.push(literalMapKey);
        if (quoted) {
          this.expectCharacter($COLON);
          values.push(this.parsePipe());
        } else if (this.consumeOptionalCharacter($COLON)) {
          values.push(this.parsePipe());
        } else {
          literalMapKey.isShorthandInitialized = true;
          values.push(new PropertyRead(keySpan, keySourceSpan, keySourceSpan, new ImplicitReceiver(keySpan, keySourceSpan), key));
        }
      } while (this.consumeOptionalCharacter($COMMA) && !this.next.isCharacter($RBRACE));
      this.rbracesExpected--;
      this.expectCharacter($RBRACE);
    }
    return new LiteralMap(this.span(start), this.sourceSpan(start), keys, values);
  }
  parseAccessMember(readReceiver, start, isSafe) {
    const nameStart = this.inputIndex;
    const id = this.withContext(ParseContextFlags.Writable, () => {
      const id = this.expectIdentifierOrKeyword() ?? '';
      if (id.length === 0) {
        this.error(`Expected identifier for property access`, readReceiver.span.end);
      }
      return id;
    });
    const nameSpan = this.sourceSpan(nameStart);
    if (isSafe) {
      if (this.isAssignmentOperator(this.next)) {
        this.advance();
        this.error("The '?.' operator cannot be used in the assignment");
        return new EmptyExpr$1(this.span(start), this.sourceSpan(start));
      } else {
        return new SafePropertyRead(this.span(start), this.sourceSpan(start), nameSpan, readReceiver, id);
      }
    } else {
      if (this.isAssignmentOperator(this.next)) {
        const operation = this.next.strValue;
        if (!(this.parseFlags & 1)) {
          this.advance();
          this.error('Bindings cannot contain assignments');
          return new EmptyExpr$1(this.span(start), this.sourceSpan(start));
        }
        const receiver = new PropertyRead(this.span(start), this.sourceSpan(start), nameSpan, readReceiver, id);
        this.advance();
        const value = this.parseConditional();
        return new Binary(this.span(start), this.sourceSpan(start), operation, receiver, value);
      } else {
        return new PropertyRead(this.span(start), this.sourceSpan(start), nameSpan, readReceiver, id);
      }
    }
  }
  parseCall(receiver, start, isSafe) {
    const argumentStart = this.inputIndex;
    this.rparensExpected++;
    const args = this.parseCallArguments();
    const argumentSpan = this.span(argumentStart, this.inputIndex).toAbsolute(this.absoluteOffset);
    this.expectCharacter($RPAREN);
    this.rparensExpected--;
    const span = this.span(start);
    const sourceSpan = this.sourceSpan(start);
    return isSafe ? new SafeCall(span, sourceSpan, receiver, args, argumentSpan) : new Call(span, sourceSpan, receiver, args, argumentSpan);
  }
  parseCallArguments() {
    if (this.next.isCharacter($RPAREN)) {
      return [];
    }
    const positionals = [];
    do {
      positionals.push(this.next.isOperator('...') ? this.parseSpreadElement() : this.parsePipe());
    } while (this.consumeOptionalCharacter($COMMA));
    return positionals;
  }
  parseSpreadElement() {
    if (!this.next.isOperator('...')) {
      this.error("Spread element must start with '...' operator");
    }
    const spreadStart = this.inputIndex;
    this.advance();
    const expression = this.parsePipe();
    const span = this.span(spreadStart);
    const sourceSpan = this.sourceSpan(spreadStart);
    return new SpreadElement(span, sourceSpan, expression);
  }
  expectTemplateBindingKey() {
    let result = '';
    let operatorFound = false;
    const start = this.currentAbsoluteOffset;
    do {
      result += this.expectIdentifierOrKeywordOrString();
      operatorFound = this.consumeOptionalOperator('-');
      if (operatorFound) {
        result += '-';
      }
    } while (operatorFound);
    return {
      source: result,
      span: new AbsoluteSourceSpan(start, start + result.length)
    };
  }
  parseTemplateBindings(templateKey) {
    const bindings = [];
    bindings.push(...this.parseDirectiveKeywordBindings(templateKey));
    while (this.index < this.tokens.length) {
      const letBinding = this.parseLetBinding();
      if (letBinding) {
        bindings.push(letBinding);
      } else {
        const key = this.expectTemplateBindingKey();
        const binding = this.parseAsBinding(key);
        if (binding) {
          bindings.push(binding);
        } else {
          key.source = templateKey.source + key.source.charAt(0).toUpperCase() + key.source.substring(1);
          bindings.push(...this.parseDirectiveKeywordBindings(key));
        }
      }
      this.consumeStatementTerminator();
    }
    return new TemplateBindingParseResult(bindings, [], this.errors);
  }
  parseKeyedReadOrWrite(receiver, start, isSafe) {
    return this.withContext(ParseContextFlags.Writable, () => {
      this.rbracketsExpected++;
      const key = this.parsePipe();
      if (key instanceof EmptyExpr$1) {
        this.error(`Key access cannot be empty`);
      }
      this.rbracketsExpected--;
      this.expectCharacter($RBRACKET);
      if (this.isAssignmentOperator(this.next)) {
        const operation = this.next.strValue;
        if (isSafe) {
          this.advance();
          this.error("The '?.' operator cannot be used in the assignment");
        } else {
          const binaryReceiver = new KeyedRead(this.span(start), this.sourceSpan(start), receiver, key);
          this.advance();
          const value = this.parseConditional();
          return new Binary(this.span(start), this.sourceSpan(start), operation, binaryReceiver, value);
        }
      } else {
        return isSafe ? new SafeKeyedRead(this.span(start), this.sourceSpan(start), receiver, key) : new KeyedRead(this.span(start), this.sourceSpan(start), receiver, key);
      }
      return new EmptyExpr$1(this.span(start), this.sourceSpan(start));
    });
  }
  parseDirectiveKeywordBindings(key) {
    const bindings = [];
    this.consumeOptionalCharacter($COLON);
    const value = this.getDirectiveBoundTarget();
    let spanEnd = this.currentAbsoluteOffset;
    const asBinding = this.parseAsBinding(key);
    if (!asBinding) {
      this.consumeStatementTerminator();
      spanEnd = this.currentAbsoluteOffset;
    }
    const sourceSpan = new AbsoluteSourceSpan(key.span.start, spanEnd);
    bindings.push(new ExpressionBinding(sourceSpan, key, value));
    if (asBinding) {
      bindings.push(asBinding);
    }
    return bindings;
  }
  getDirectiveBoundTarget() {
    if (this.next === EOF || this.peekKeywordAs() || this.peekKeywordLet()) {
      return null;
    }
    const ast = this.parsePipe();
    const {
      start,
      end
    } = ast.span;
    const value = this.input.substring(start, end);
    return new ASTWithSource(ast, value, getLocation(this.parseSourceSpan), this.absoluteOffset + start, this.errors);
  }
  parseAsBinding(value) {
    if (!this.peekKeywordAs()) {
      return null;
    }
    this.advance();
    const key = this.expectTemplateBindingKey();
    this.consumeStatementTerminator();
    const sourceSpan = new AbsoluteSourceSpan(value.span.start, this.currentAbsoluteOffset);
    return new VariableBinding(sourceSpan, key, value);
  }
  parseLetBinding() {
    if (!this.peekKeywordLet()) {
      return null;
    }
    const spanStart = this.currentAbsoluteOffset;
    this.advance();
    const key = this.expectTemplateBindingKey();
    let value = null;
    if (this.consumeOptionalOperator('=')) {
      value = this.expectTemplateBindingKey();
    }
    this.consumeStatementTerminator();
    const sourceSpan = new AbsoluteSourceSpan(spanStart, this.currentAbsoluteOffset);
    return new VariableBinding(sourceSpan, key, value);
  }
  parseNoInterpolationTaggedTemplateLiteral(tag, start) {
    const template = this.parseNoInterpolationTemplateLiteral();
    return new TaggedTemplateLiteral(this.span(start), this.sourceSpan(start), tag, template);
  }
  parseNoInterpolationTemplateLiteral() {
    const text = this.next.strValue;
    const start = this.inputIndex;
    this.advance();
    const span = this.span(start);
    const sourceSpan = this.sourceSpan(start);
    return new TemplateLiteral(span, sourceSpan, [new TemplateLiteralElement(span, sourceSpan, text)], []);
  }
  parseTaggedTemplateLiteral(tag, start) {
    const template = this.parseTemplateLiteral();
    return new TaggedTemplateLiteral(this.span(start), this.sourceSpan(start), tag, template);
  }
  parseTemplateLiteral() {
    const elements = [];
    const expressions = [];
    const start = this.inputIndex;
    while (this.next !== EOF) {
      const token = this.next;
      if (token.isTemplateLiteralPart() || token.isTemplateLiteralEnd()) {
        const partStart = this.inputIndex;
        this.advance();
        elements.push(new TemplateLiteralElement(this.span(partStart), this.sourceSpan(partStart), token.strValue));
        if (token.isTemplateLiteralEnd()) {
          break;
        }
      } else if (token.isTemplateLiteralInterpolationStart()) {
        this.advance();
        this.rbracesExpected++;
        const expression = this.parsePipe();
        if (expression instanceof EmptyExpr$1) {
          this.error('Template literal interpolation cannot be empty');
        }
        expressions.push(expression);
        this.rbracesExpected--;
      } else {
        this.advance();
      }
    }
    return new TemplateLiteral(this.span(start), this.sourceSpan(start), elements, expressions);
  }
  parseRegularExpressionLiteral() {
    const bodyToken = this.next;
    this.advance();
    if (!bodyToken.isRegExpBody()) {
      return new EmptyExpr$1(this.span(this.inputIndex), this.sourceSpan(this.inputIndex));
    }
    let flagsToken = null;
    if (this.next.isRegExpFlags()) {
      flagsToken = this.next;
      this.advance();
      const seenFlags = new Set();
      for (let i = 0; i < flagsToken.strValue.length; i++) {
        const char = flagsToken.strValue[i];
        if (!SUPPORTED_REGEX_FLAGS.has(char)) {
          this.error(`Unsupported regular expression flag "${char}". The supported flags are: ` + Array.from(SUPPORTED_REGEX_FLAGS, f => `"${f}"`).join(', '), flagsToken.index + i);
        } else if (seenFlags.has(char)) {
          this.error(`Duplicate regular expression flag "${char}"`, flagsToken.index + i);
        } else {
          seenFlags.add(char);
        }
      }
    }
    const start = bodyToken.index;
    const end = flagsToken ? flagsToken.end : bodyToken.end;
    return new RegularExpressionLiteral(this.span(start, end), this.sourceSpan(start, end), bodyToken.strValue, flagsToken ? flagsToken.strValue : null);
  }
  parseArrowFunction(start) {
    let params;
    if (this.next.isIdentifier()) {
      const token = this.next;
      this.advance();
      params = [this.getArrowFunctionIdentifierArg(token)];
    } else if (this.next.isCharacter($LPAREN)) {
      this.rparensExpected++;
      this.advance();
      params = this.parseArrowFunctionParameters();
      this.rparensExpected--;
    } else {
      params = [];
      this.error(`Unexpected token ${this.next}`);
    }
    this.expectOperator('=>');
    let body;
    if (this.next.isCharacter($LBRACE)) {
      this.error('Multi-line arrow functions are not supported. If you meant to return an object literal, wrap it with parentheses.');
      body = new EmptyExpr$1(this.span(start), this.sourceSpan(start));
    } else {
      const prevFlags = this.parseFlags;
      this.parseFlags = 1;
      body = this.parseExpression();
      this.parseFlags = prevFlags;
    }
    return new ArrowFunction(this.span(start), this.sourceSpan(start), params, body);
  }
  parseArrowFunctionParameters() {
    const params = [];
    if (!this.consumeOptionalCharacter($RPAREN)) {
      while (this.next !== EOF) {
        if (this.next.isIdentifier()) {
          const token = this.next;
          this.advance();
          params.push(this.getArrowFunctionIdentifierArg(token));
          if (this.consumeOptionalCharacter($RPAREN)) {
            break;
          } else {
            this.expectCharacter($COMMA);
          }
        } else {
          this.error(`Unexpected token ${this.next}`);
          break;
        }
      }
    }
    return params;
  }
  getArrowFunctionIdentifierArg(token) {
    return new ArrowFunctionIdentifierParameter(token.strValue, this.span(token.index), this.sourceSpan(token.index));
  }
  isArrowFunction() {
    const start = this.index;
    const tokens = this.tokens;
    if (start > tokens.length - 2) {
      return false;
    }
    if (tokens[start].isIdentifier() && tokens[start + 1].isOperator('=>')) {
      return true;
    }
    if (tokens[start].isCharacter($LPAREN)) {
      let i = start + 1;
      for (i; i < tokens.length; i++) {
        if (!tokens[i].isIdentifier() && !tokens[i].isCharacter($COMMA)) {
          break;
        }
      }
      return i < tokens.length - 1 && tokens[i].isCharacter($RPAREN) && tokens[i + 1].isOperator('=>');
    }
    return false;
  }
  consumeStatementTerminator() {
    this.consumeOptionalCharacter($SEMICOLON) || this.consumeOptionalCharacter($COMMA);
  }
  error(message, index = this.index) {
    this.errors.push(getParseError(message, this.input, this.getErrorLocationText(index), this.parseSourceSpan));
    this.skip();
  }
  getErrorLocationText(index) {
    return index < this.tokens.length ? `at column ${this.tokens[index].index + 1} in` : `at the end of the expression`;
  }
  _reportErrorForPrivateIdentifier(token, extraMessage) {
    let errorMessage = `Private identifiers are not supported. Unexpected private identifier: ${token}`;
    if (extraMessage !== null) {
      errorMessage += `, ${extraMessage}`;
    }
    this.error(errorMessage);
  }
  skip() {
    let n = this.next;
    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) || !this.isAssignmentOperator(n))) {
      if (this.next.isError()) {
        this.errors.push(getParseError(this.next.toString(), this.input, this.getErrorLocationText(this.next.index), this.parseSourceSpan));
      }
      this.advance();
      n = this.next;
    }
  }
}
function getParseError(message, input, locationText, parseSourceSpan) {
  if (locationText.length > 0) {
    locationText = ` ${locationText} `;
  }
  const location = getLocation(parseSourceSpan);
  const error = `Parser Error: ${message}${locationText}[${input}] in ${location}`;
  return new ParseError(parseSourceSpan, error);
}
class SimpleExpressionChecker extends RecursiveAstVisitor {
  errors = [];
  visitPipe() {
    this.errors.push('pipes');
  }
}
function getIndexMapForOriginalTemplate(interpolatedTokens) {
  let offsetMap = new Map();
  let consumedInOriginalTemplate = 0;
  let consumedInInput = 0;
  let tokenIndex = 0;
  while (tokenIndex < interpolatedTokens.length) {
    const currentToken = interpolatedTokens[tokenIndex];
    if (currentToken.type === 9) {
      const [decoded, encoded] = currentToken.parts;
      consumedInOriginalTemplate += encoded.length;
      consumedInInput += decoded.length;
    } else {
      const lengthOfParts = currentToken.parts.reduce((sum, current) => sum + current.length, 0);
      consumedInInput += lengthOfParts;
      consumedInOriginalTemplate += lengthOfParts;
    }
    offsetMap.set(consumedInInput, consumedInOriginalTemplate);
    tokenIndex++;
  }
  return offsetMap;
}

function serialize(expression) {
  return expression.visit(new SerializeExpressionVisitor());
}
class SerializeExpressionVisitor {
  visitUnary(ast, context) {
    return `${ast.operator}${ast.expr.visit(this, context)}`;
  }
  visitBinary(ast, context) {
    return `${ast.left.visit(this, context)} ${ast.operation} ${ast.right.visit(this, context)}`;
  }
  visitChain(ast, context) {
    return ast.expressions.map(e => e.visit(this, context)).join('; ');
  }
  visitConditional(ast, context) {
    return `${ast.condition.visit(this, context)} ? ${ast.trueExp.visit(this, context)} : ${ast.falseExp.visit(this, context)}`;
  }
  visitThisReceiver() {
    return 'this';
  }
  visitImplicitReceiver() {
    return '';
  }
  visitInterpolation(ast, context) {
    return interleave(ast.strings, ast.expressions.map(e => e.visit(this, context))).join('');
  }
  visitKeyedRead(ast, context) {
    return `${ast.receiver.visit(this, context)}[${ast.key.visit(this, context)}]`;
  }
  visitLiteralArray(ast, context) {
    return `[${ast.expressions.map(e => e.visit(this, context)).join(', ')}]`;
  }
  visitLiteralMap(ast, context) {
    return `{${zip(ast.keys.map(literal => {
      if (literal.kind === 'spread') {
        return '...';
      }
      return literal.quoted ? `'${literal.key}'` : literal.key;
    }), ast.values.map(value => value.visit(this, context))).map(([key, value]) => `${key}: ${value}`).join(', ')}}`;
  }
  visitLiteralPrimitive(ast) {
    if (ast.value === null) return 'null';
    switch (typeof ast.value) {
      case 'number':
      case 'boolean':
        return ast.value.toString();
      case 'undefined':
        return 'undefined';
      case 'string':
        return `'${ast.value.replace(/'/g, `\\'`)}'`;
      default:
        throw new Error(`Unsupported primitive type: ${ast.value}`);
    }
  }
  visitPipe(ast, context) {
    return `${ast.exp.visit(this, context)} | ${ast.name}`;
  }
  visitPrefixNot(ast, context) {
    return `!${ast.expression.visit(this, context)}`;
  }
  visitNonNullAssert(ast, context) {
    return `${ast.expression.visit(this, context)}!`;
  }
  visitPropertyRead(ast, context) {
    if (ast.receiver instanceof ImplicitReceiver || ast.receiver instanceof ThisReceiver) {
      return ast.name;
    } else {
      return `${ast.receiver.visit(this, context)}.${ast.name}`;
    }
  }
  visitSafePropertyRead(ast, context) {
    return `${ast.receiver.visit(this, context)}?.${ast.name}`;
  }
  visitSafeKeyedRead(ast, context) {
    return `${ast.receiver.visit(this, context)}?.[${ast.key.visit(this, context)}]`;
  }
  visitCall(ast, context) {
    return `${ast.receiver.visit(this, context)}(${ast.args.map(e => e.visit(this, context)).join(', ')})`;
  }
  visitSafeCall(ast, context) {
    return `${ast.receiver.visit(this, context)}?.(${ast.args.map(e => e.visit(this, context)).join(', ')})`;
  }
  visitTypeofExpression(ast, context) {
    return `typeof ${ast.expression.visit(this, context)}`;
  }
  visitVoidExpression(ast, context) {
    return `void ${ast.expression.visit(this, context)}`;
  }
  visitRegularExpressionLiteral(ast, context) {
    return `/${ast.body}/${ast.flags || ''}`;
  }
  visitArrowFunction(ast, context) {
    let params;
    if (ast.parameters.length === 1) {
      params = ast.parameters[0].name;
    } else {
      params = `(${ast.parameters.map(e => e.name).join(', ')})`;
    }
    return `${params} => ${ast.body.visit(this, context)}`;
  }
  visitASTWithSource(ast, context) {
    return ast.ast.visit(this, context);
  }
  visitTemplateLiteral(ast, context) {
    let result = '';
    for (let i = 0; i < ast.elements.length; i++) {
      result += ast.elements[i].visit(this, context);
      const expression = i < ast.expressions.length ? ast.expressions[i] : null;
      if (expression !== null) {
        result += '${' + expression.visit(this, context) + '}';
      }
    }
    return '`' + result + '`';
  }
  visitTemplateLiteralElement(ast, context) {
    return ast.text;
  }
  visitTaggedTemplateLiteral(ast, context) {
    return ast.tag.visit(this, context) + ast.template.visit(this, context);
  }
  visitSpreadElement(ast, context) {
    return `...${ast.expression.visit(this, context)}`;
  }
  visitParenthesizedExpression(ast, context) {
    return '(' + ast.expression.visit(this, context) + ')';
  }
}
function zip(left, right) {
  if (left.length !== right.length) throw new Error('Array lengths must match');
  return left.map((l, i) => [l, right[i]]);
}
function interleave(left, right) {
  const result = [];
  for (let index = 0; index < Math.max(left.length, right.length); index++) {
    if (index < left.length) result.push(left[index]);
    if (index < right.length) result.push(right[index]);
  }
  return result;
}

const SVG_NAMESPACE = 'svg';
const MATH_ML_NAMESPACE = 'math';

class ElementSchemaRegistry {}

const BOOLEAN = 'boolean';
const NUMBER = 'number';
const STRING = 'string';
const OBJECT = 'object';
function normalizeTagName(tagName) {
  const tagNameLower = tagName.toLowerCase();
  const [ns, name] = splitNsName(tagNameLower, false);
  return ns === SVG_NAMESPACE || ns === MATH_ML_NAMESPACE ? `:${ns}:${name}` : name;
}
const SCHEMA = ['[Element]|textContent,%ariaActiveDescendantElement,%ariaAtomic,%ariaAutoComplete,%ariaBusy,%ariaChecked,%ariaColCount,%ariaColIndex,%ariaColIndexText,%ariaColSpan,%ariaControlsElements,%ariaCurrent,%ariaDescribedByElements,%ariaDescription,%ariaDetailsElements,%ariaDisabled,%ariaErrorMessageElements,%ariaExpanded,%ariaFlowToElements,%ariaHasPopup,%ariaHidden,%ariaInvalid,%ariaKeyShortcuts,%ariaLabel,%ariaLabelledByElements,%ariaLevel,%ariaLive,%ariaModal,%ariaMultiLine,%ariaMultiSelectable,%ariaOrientation,%ariaOwnsElements,%ariaPlaceholder,%ariaPosInSet,%ariaPressed,%ariaReadOnly,%ariaRelevant,%ariaRequired,%ariaRoleDescription,%ariaRowCount,%ariaRowIndex,%ariaRowIndexText,%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' + ',*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,search,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,*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,%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', 'geolocation^[HTMLElement]|accuracymode,!autolocate,*location,*promptaction,*promptdismiss,*validationstatuschange,!watch', '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,!credentialless,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', 'selectedcontent^[HTMLElement]|', 'slot^[HTMLElement]|name', 'source^[HTMLElement]|#height,media,sizes,src,srcset,type,#width', 'span^[HTMLElement]|', 'style^[HTMLElement]|!disabled,media,type', 'search^[HTMLELement]|', '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,*auxclick,*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^: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:|'];
const _ATTR_TO_PROP = new Map(Object.entries({
  'class': 'className',
  'for': 'htmlFor',
  'formaction': 'formAction',
  'innerHtml': 'innerHTML',
  'readonly': 'readOnly',
  'tabindex': 'tabIndex',
  'aria-activedescendant': 'ariaActiveDescendantElement',
  'aria-atomic': 'ariaAtomic',
  'aria-autocomplete': 'ariaAutoComplete',
  'aria-busy': 'ariaBusy',
  'aria-checked': 'ariaChecked',
  'aria-colcount': 'ariaColCount',
  'aria-colindex': 'ariaColIndex',
  'aria-colindextext': 'ariaColIndexText',
  'aria-colspan': 'ariaColSpan',
  'aria-controls': 'ariaControlsElements',
  'aria-current': 'ariaCurrent',
  'aria-describedby': 'ariaDescribedByElements',
  'aria-description': 'ariaDescription',
  'aria-details': 'ariaDetailsElements',
  'aria-disabled': 'ariaDisabled',
  'aria-errormessage': 'ariaErrorMessageElements',
  'aria-expanded': 'ariaExpanded',
  'aria-flowto': 'ariaFlowToElements',
  'aria-haspopup': 'ariaHasPopup',
  'aria-hidden': 'ariaHidden',
  'aria-invalid': 'ariaInvalid',
  'aria-keyshortcuts': 'ariaKeyShortcuts',
  'aria-label': 'ariaLabel',
  'aria-labelledby': 'ariaLabelledByElements',
  'aria-level': 'ariaLevel',
  'aria-live': 'ariaLive',
  'aria-modal': 'ariaModal',
  'aria-multiline': 'ariaMultiLine',
  'aria-multiselectable': 'ariaMultiSelectable',
  'aria-orientation': 'ariaOrientation',
  'aria-owns': 'ariaOwnsElements',
  'aria-placeholder': 'ariaPlaceholder',
  'aria-posinset': 'ariaPosInSet',
  'aria-pressed': 'ariaPressed',
  'aria-readonly': 'ariaReadOnly',
  'aria-required': 'ariaRequired',
  'aria-roledescription': 'ariaRoleDescription',
  'aria-rowcount': 'ariaRowCount',
  'aria-rowindex': 'ariaRowIndex',
  'aria-rowindextext': 'ariaRowIndexText',
  'aria-rowspan': 'ariaRowSpan',
  'aria-selected': 'ariaSelected',
  'aria-setsize': 'ariaSetSize',
  'aria-sort': 'ariaSort',
  'aria-valuemax': 'ariaValueMax',
  'aria-valuemin': 'ariaValueMin',
  'aria-valuenow': 'ariaValueNow',
  'aria-valuetext': 'ariaValueText'
}));
const _PROP_TO_ATTR = Array.from(_ATTR_TO_PROP).reduce((inverted, [propertyName, attributeName]) => {
  inverted.set(propertyName, attributeName);
  return inverted;
}, new Map());
class DomElementSchemaRegistry extends ElementSchemaRegistry {
  _schema = new Map();
  _eventSchema = new Map();
  constructor() {
    super();
    SCHEMA.forEach(encodedType => {
      const type = new Map();
      const events = new Set();
      const [strType, strProperties] = encodedType.split('|');
      const properties = strProperties.split(',');
      const [typeNames, superName] = strType.split('^');
      typeNames.split(',').forEach(tag => {
        this._schema.set(tag.toLowerCase(), type);
        this._eventSchema.set(tag.toLowerCase(), events);
      });
      const superType = superName && this._schema.get(superName.toLowerCase());
      if (superType) {
        for (const [prop, value] of superType) {
          type.set(prop, value);
        }
        for (const superEvent of this._eventSchema.get(superName.toLowerCase())) {
          events.add(superEvent);
        }
      }
      properties.forEach(property => {
        if (property.length > 0) {
          switch (property[0]) {
            case '*':
              events.add(property.substring(1));
              break;
            case '!':
              type.set(property.substring(1), BOOLEAN);
              break;
            case '#':
              type.set(property.substring(1), NUMBER);
              break;
            case '%':
              type.set(property.substring(1), OBJECT);
              break;
            default:
              type.set(property, STRING);
          }
        }
      });
    });
  }
  hasProperty(tagName, propName, schemaMetas) {
    if (schemaMetas.some(schema => schema.name === NO_ERRORS_SCHEMA.name)) {
      return true;
    }
    const normalizedTag = normalizeTagName(tagName);
    if (normalizedTag.includes('-')) {
      if (isNgContainer(normalizedTag) || isNgContent(normalizedTag)) {
        return false;
      }
      if (schemaMetas.some(schema => schema.name === CUSTOM_ELEMENTS_SCHEMA.name)) {
        return true;
      }
    }
    const elementProperties = this._schema.get(normalizedTag) || this._schema.get('unknown');
    return elementProperties.has(propName);
  }
  hasElement(tagName, schemaMetas) {
    if (schemaMetas.some(schema => schema.name === NO_ERRORS_SCHEMA.name)) {
      return true;
    }
    const normalizedTag = normalizeTagName(tagName);
    if (normalizedTag.includes('-')) {
      if (isNgContainer(normalizedTag) || isNgContent(normalizedTag)) {
        return true;
      }
      if (schemaMetas.some(schema => schema.name === CUSTOM_ELEMENTS_SCHEMA.name)) {
        return true;
      }
    }
    return this._schema.has(normalizedTag);
  }
  securityContext(tagName, propName, isAttribute) {
    if (isAttribute) {
      propName = this.getMappedPropName(propName);
    }
    const [ns, name] = splitNsName(tagName, false);
    return checkSecurityContext(name, propName, ns);
  }
  getMappedPropName(propName) {
    return _ATTR_TO_PROP.get(propName) ?? propName;
  }
  getDefaultComponentElementName() {
    return 'ng-component';
  }
  validateProperty(name) {
    if (name.toLowerCase().startsWith('on')) {
      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.`;
      return {
        error: true,
        msg: msg
      };
    } else {
      return {
        error: false
      };
    }
  }
  validateAttribute(name) {
    if (name.toLowerCase().startsWith('on')) {
      const msg = `Binding to event attribute '${name}' is disallowed for security reasons, ` + `please use (${name.slice(2)})=...`;
      return {
        error: true,
        msg: msg
      };
    } else {
      return {
        error: false
      };
    }
  }
  allKnownElementNames() {
    return Array.from(this._schema.keys());
  }
  allKnownAttributesOfElement(tagName) {
    const normalizedTag = normalizeTagName(tagName);
    const elementProperties = this._schema.get(normalizedTag) || this._schema.get('unknown');
    return Array.from(elementProperties.keys()).map(prop => _PROP_TO_ATTR.get(prop) ?? prop);
  }
  allKnownEventsOfElement(tagName) {
    const normalizedTag = normalizeTagName(tagName);
    return Array.from(this._eventSchema.get(normalizedTag) ?? []);
  }
  normalizeAnimationStyleProperty(propName) {
    return dashCaseToCamelCase(propName);
  }
  normalizeAnimationStyleValue(camelCaseProp, userProvidedProp, val) {
    let unit = '';
    const strVal = val.toString().trim();
    let errorMsg = null;
    if (_isPixelDimensionStyle(camelCaseProp) && val !== 0 && val !== '0') {
      if (typeof val === 'number') {
        unit = 'px';
      } else {
        const valAndSuffixMatch = val.match(/^[+-]?[\d\.]+([a-z]*)$/);
        if (valAndSuffixMatch && valAndSuffixMatch[1].length == 0) {
          errorMsg = `Please provide a CSS unit value for ${userProvidedProp}:${val}`;
        }
      }
    }
    return {
      error: errorMsg,
      value: strVal + unit
    };
  }
}
function _isPixelDimensionStyle(prop) {
  switch (prop) {
    case 'width':
    case 'height':
    case 'minWidth':
    case 'minHeight':
    case 'maxWidth':
    case 'maxHeight':
    case 'left':
    case 'top':
    case 'bottom':
    case 'right':
    case 'fontSize':
    case 'outlineWidth':
    case 'outlineOffset':
    case 'paddingTop':
    case 'paddingLeft':
    case 'paddingBottom':
    case 'paddingRight':
    case 'marginTop':
    case 'marginLeft':
    case 'marginBottom':
    case 'marginRight':
    case 'borderRadius':
    case 'borderWidth':
    case 'borderTopWidth':
    case 'borderLeftWidth':
    case 'borderRightWidth':
    case 'borderBottomWidth':
    case 'textIndent':
      return true;
    default:
      return false;
  }
}

class HtmlTagDefinition {
  closedByChildren = {};
  contentType;
  closedByParent = false;
  implicitNamespacePrefix;
  isVoid;
  ignoreFirstLf;
  canSelfClose;
  preventNamespaceInheritance;
  constructor({
    closedByChildren,
    implicitNamespacePrefix,
    contentType = TagContentType.PARSABLE_DATA,
    closedByParent = false,
    isVoid = false,
    ignoreFirstLf = false,
    preventNamespaceInheritance = false,
    canSelfClose = false
  } = {}) {
    if (closedByChildren && closedByChildren.length > 0) {
      closedByChildren.forEach(tagName => this.closedByChildren[tagName] = true);
    }
    this.isVoid = isVoid;
    this.closedByParent = closedByParent || isVoid;
    this.implicitNamespacePrefix = implicitNamespacePrefix || null;
    this.contentType = contentType;
    this.ignoreFirstLf = ignoreFirstLf;
    this.preventNamespaceInheritance = preventNamespaceInheritance;
    this.canSelfClose = canSelfClose ?? isVoid;
  }
  isClosedByChild(name) {
    return this.isVoid || name.toLowerCase() in this.closedByChildren;
  }
  getContentType(prefix) {
    if (typeof this.contentType === 'object') {
      const overrideType = prefix === undefined ? undefined : this.contentType[prefix];
      return overrideType ?? this.contentType.default;
    }
    return this.contentType;
  }
}
let DEFAULT_TAG_DEFINITION;
let TAG_DEFINITIONS;
function getHtmlTagDefinition(tagName) {
  if (!TAG_DEFINITIONS) {
    DEFAULT_TAG_DEFINITION = new HtmlTagDefinition({
      canSelfClose: true
    });
    TAG_DEFINITIONS = Object.assign(Object.create(null), {
      'base': new HtmlTagDefinition({
        isVoid: true
      }),
      'meta': new HtmlTagDefinition({
        isVoid: true
      }),
      'area': new HtmlTagDefinition({
        isVoid: true
      }),
      'embed': new HtmlTagDefinition({
        isVoid: true
      }),
      'link': new HtmlTagDefinition({
        isVoid: true
      }),
      'img': new HtmlTagDefinition({
        isVoid: true
      }),
      'input': new HtmlTagDefinition({
        isVoid: true
      }),
      'param': new HtmlTagDefinition({
        isVoid: true
      }),
      'hr': new HtmlTagDefinition({
        isVoid: true
      }),
      'br': new HtmlTagDefinition({
        isVoid: true
      }),
      'source': new HtmlTagDefinition({
        isVoid: true
      }),
      'track': new HtmlTagDefinition({
        isVoid: true
      }),
      'wbr': new HtmlTagDefinition({
        isVoid: true
      }),
      'p': new HtmlTagDefinition({
        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'],
        closedByParent: true
      }),
      'thead': new HtmlTagDefinition({
        closedByChildren: ['tbody', 'tfoot']
      }),
      'tbody': new HtmlTagDefinition({
        closedByChildren: ['tbody', 'tfoot'],
        closedByParent: true
      }),
      'tfoot': new HtmlTagDefinition({
        closedByChildren: ['tbody'],
        closedByParent: true
      }),
      'tr': new HtmlTagDefinition({
        closedByChildren: ['tr'],
        closedByParent: true
      }),
      'td': new HtmlTagDefinition({
        closedByChildren: ['td', 'th'],
        closedByParent: true
      }),
      'th': new HtmlTagDefinition({
        closedByChildren: ['td', 'th'],
        closedByParent: true
      }),
      'col': new HtmlTagDefinition({
        isVoid: true
      }),
      'svg': new HtmlTagDefinition({
        implicitNamespacePrefix: 'svg'
      }),
      'foreignObject': new HtmlTagDefinition({
        implicitNamespacePrefix: 'svg',
        preventNamespaceInheritance: true
      }),
      'math': new HtmlTagDefinition({
        implicitNamespacePrefix: 'math'
      }),
      'li': new HtmlTagDefinition({
        closedByChildren: ['li'],
        closedByParent: true
      }),
      'dt': new HtmlTagDefinition({
        closedByChildren: ['dt', 'dd']
      }),
      'dd': new HtmlTagDefinition({
        closedByChildren: ['dt', 'dd'],
        closedByParent: true
      }),
      'rb': new HtmlTagDefinition({
        closedByChildren: ['rb', 'rt', 'rtc', 'rp'],
        closedByParent: true
      }),
      'rt': new HtmlTagDefinition({
        closedByChildren: ['rb', 'rt', 'rtc', 'rp'],
        closedByParent: true
      }),
      'rtc': new HtmlTagDefinition({
        closedByChildren: ['rb', 'rtc', 'rp'],
        closedByParent: true
      }),
      'rp': new HtmlTagDefinition({
        closedByChildren: ['rb', 'rt', 'rtc', 'rp'],
        closedByParent: true
      }),
      'optgroup': new HtmlTagDefinition({
        closedByChildren: ['optgroup'],
        closedByParent: true
      }),
      'option': new HtmlTagDefinition({
        closedByChildren: ['option', 'optgroup'],
        closedByParent: true
      }),
      'pre': new HtmlTagDefinition({
        ignoreFirstLf: true
      }),
      'listing': new HtmlTagDefinition({
        ignoreFirstLf: true
      }),
      'style': new HtmlTagDefinition({
        contentType: TagContentType.RAW_TEXT
      }),
      'script': new HtmlTagDefinition({
        contentType: TagContentType.RAW_TEXT
      }),
      'title': new HtmlTagDefinition({
        contentType: {
          default: TagContentType.ESCAPABLE_RAW_TEXT,
          svg: TagContentType.PARSABLE_DATA
        }
      }),
      'textarea': new HtmlTagDefinition({
        contentType: TagContentType.ESCAPABLE_RAW_TEXT,
        ignoreFirstLf: true
      })
    });
    new DomElementSchemaRegistry().allKnownElementNames().forEach(knownTagName => {
      if (!TAG_DEFINITIONS[knownTagName] && getNsPrefix(knownTagName) === null) {
        TAG_DEFINITIONS[knownTagName] = new HtmlTagDefinition({
          canSelfClose: false
        });
      }
    });
  }
  return TAG_DEFINITIONS[tagName] ?? TAG_DEFINITIONS[tagName.toLowerCase()] ?? DEFAULT_TAG_DEFINITION;
}

const TAG_TO_PLACEHOLDER_NAMES = {
  'A': 'LINK',
  'B': 'BOLD_TEXT',
  'BR': 'LINE_BREAK',
  'EM': 'EMPHASISED_TEXT',
  'H1': 'HEADING_LEVEL1',
  'H2': 'HEADING_LEVEL2',
  'H3': 'HEADING_LEVEL3',
  'H4': 'HEADING_LEVEL4',
  'H5': 'HEADING_LEVEL5',
  'H6': 'HEADING_LEVEL6',
  'HR': 'HORIZONTAL_RULE',
  'I': 'ITALIC_TEXT',
  'LI': 'LIST_ITEM',
  'LINK': 'MEDIA_LINK',
  'OL': 'ORDERED_LIST',
  'P': 'PARAGRAPH',
  'Q': 'QUOTATION',
  'S': 'STRIKETHROUGH_TEXT',
  'SMALL': 'SMALL_TEXT',
  'SUB': 'SUBSTRIPT',
  'SUP': 'SUPERSCRIPT',
  'TBODY': 'TABLE_BODY',
  'TD': 'TABLE_CELL',
  'TFOOT': 'TABLE_FOOTER',
  'TH': 'TABLE_HEADER_CELL',
  'THEAD': 'TABLE_HEADER',
  'TR': 'TABLE_ROW',
  'TT': 'MONOSPACED_TEXT',
  'U': 'UNDERLINED_TEXT',
  'UL': 'UNORDERED_LIST'
};
class PlaceholderRegistry {
  _placeHolderNameCounts = {};
  _signatureToName = {};
  getStartTagPlaceholderName(tag, attrs, isVoid) {
    const signature = this._hashTag(tag, attrs, isVoid);
    if (this._signatureToName[signature]) {
      return this._signatureToName[signature];
    }
    const upperTag = tag.toUpperCase();
    const baseName = TAG_TO_PLACEHOLDER_NAMES[upperTag] || `TAG_${upperTag}`;
    const name = this._generateUniqueName(isVoid ? baseName : `START_${baseName}`);
    this._signatureToName[signature] = name;
    return name;
  }
  getCloseTagPlaceholderName(tag) {
    const signature = this._hashClosingTag(tag);
    if (this._signatureToName[signature]) {
      return this._signatureToName[signature];
    }
    const upperTag = tag.toUpperCase();
    const baseName = TAG_TO_PLACEHOLDER_NAMES[upperTag] || `TAG_${upperTag}`;
    const name = this._generateUniqueName(`CLOSE_${baseName}`);
    this._signatureToName[signature] = name;
    return name;
  }
  getPlaceholderName(name, content) {
    const upperName = name.toUpperCase();
    const signature = `PH: ${upperName}=${content}`;
    if (this._signatureToName[signature]) {
      return this._signatureToName[signature];
    }
    const uniqueName = this._generateUniqueName(upperName);
    this._signatureToName[signature] = uniqueName;
    return uniqueName;
  }
  getUniquePlaceholder(name) {
    return this._generateUniqueName(name.toUpperCase());
  }
  getStartBlockPlaceholderName(name, parameters) {
    const signature = this._hashBlock(name, parameters);
    if (this._signatureToName[signature]) {
      return this._signatureToName[signature];
    }
    const placeholder = this._generateUniqueName(`START_BLOCK_${this._toSnakeCase(name)}`);
    this._signatureToName[signature] = placeholder;
    return placeholder;
  }
  getCloseBlockPlaceholderName(name) {
    const signature = this._hashClosingBlock(name);
    if (this._signatureToName[signature]) {
      return this._signatureToName[signature];
    }
    const placeholder = this._generateUniqueName(`CLOSE_BLOCK_${this._toSnakeCase(name)}`);
    this._signatureToName[signature] = placeholder;
    return placeholder;
  }
  _hashTag(tag, attrs, isVoid) {
    const start = `<${tag}`;
    const strAttrs = Object.keys(attrs).sort().map(name => ` ${name}=${attrs[name]}`).join('');
    const end = isVoid ? '/>' : `></${tag}>`;
    return start + strAttrs + end;
  }
  _hashClosingTag(tag) {
    return this._hashTag(`/${tag}`, {}, false);
  }
  _hashBlock(name, parameters) {
    const params = parameters.length === 0 ? '' : ` (${parameters.sort().join('; ')})`;
    return `@${name}${params} {}`;
  }
  _hashClosingBlock(name) {
    return this._hashBlock(`close_${name}`, []);
  }
  _toSnakeCase(name) {
    return name.toUpperCase().replace(/[^A-Z0-9]/g, '_');
  }
  _generateUniqueName(base) {
    const seen = Object.hasOwn(this._placeHolderNameCounts, base);
    if (!seen) {
      this._placeHolderNameCounts[base] = 1;
      return base;
    }
    const id = this._placeHolderNameCounts[base];
    this._placeHolderNameCounts[base] = id + 1;
    return `${base}_${id}`;
  }
}

const _expParser = new Parser(new Lexer());
function createI18nMessageFactory(retainEmptyTokens, preserveExpressionWhitespace) {
  const visitor = new _I18nVisitor(_expParser, retainEmptyTokens, preserveExpressionWhitespace);
  return (nodes, meaning, description, customId, visitNodeFn) => visitor.toI18nMessage(nodes, meaning, description, customId, visitNodeFn);
}
function noopVisitNodeFn(_html, i18n) {
  return i18n;
}
class _I18nVisitor {
  _expressionParser;
  _retainEmptyTokens;
  _preserveExpressionWhitespace;
  constructor(_expressionParser, _retainEmptyTokens, _preserveExpressionWhitespace) {
    this._expressionParser = _expressionParser;
    this._retainEmptyTokens = _retainEmptyTokens;
    this._preserveExpressionWhitespace = _preserveExpressionWhitespace;
  }
  toI18nMessage(nodes, meaning = '', description = '', customId = '', visitNodeFn) {
    const context = {
      isIcu: nodes.length == 1 && nodes[0] instanceof Expansion,
      icuDepth: 0,
      placeholderRegistry: new PlaceholderRegistry(),
      placeholderToContent: {},
      placeholderToMessage: {},
      visitNodeFn: visitNodeFn || noopVisitNodeFn
    };
    const i18nodes = visitAll(this, nodes, context);
    return new Message(i18nodes, context.placeholderToContent, context.placeholderToMessage, meaning, description, customId);
  }
  visitElement(el, context) {
    return this._visitElementLike(el, context);
  }
  visitComponent(component, context) {
    return this._visitElementLike(component, context);
  }
  visitDirective(directive, context) {
    throw new Error('Unreachable code');
  }
  visitAttribute(attribute, context) {
    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);
    return context.visitNodeFn(attribute, node);
  }
  visitText(text, context) {
    const node = text.tokens.length === 1 ? new Text$2(text.value, text.sourceSpan) : this._visitTextWithInterpolation(text.tokens, text.sourceSpan, context, text.i18n);
    return context.visitNodeFn(text, node);
  }
  visitComment(comment, context) {
    return null;
  }
  visitExpansion(icu, context) {
    context.icuDepth++;
    const i18nIcuCases = {};
    const i18nIcu = new Icu(icu.switchValue, icu.type, i18nIcuCases, icu.sourceSpan);
    icu.cases.forEach(caze => {
      i18nIcuCases[caze.value] = new Container(caze.expression.map(node => node.visit(this, context)), caze.expSourceSpan);
    });
    context.icuDepth--;
    if (context.isIcu || context.icuDepth > 0) {
      const expPh = context.placeholderRegistry.getUniquePlaceholder(`VAR_${icu.type}`);
      i18nIcu.expressionPlaceholder = expPh;
      context.placeholderToContent[expPh] = {
        text: icu.switchValue,
        sourceSpan: icu.switchValueSourceSpan
      };
      return context.visitNodeFn(icu, i18nIcu);
    }
    const phName = context.placeholderRegistry.getPlaceholderName('ICU', icu.sourceSpan.toString());
    context.placeholderToMessage[phName] = this.toI18nMessage([icu], '', '', '', undefined);
    const node = new IcuPlaceholder(i18nIcu, phName, icu.sourceSpan);
    return context.visitNodeFn(icu, node);
  }
  visitExpansionCase(_icuCase, _context) {
    throw new Error('Unreachable code');
  }
  visitBlock(block, context) {
    const children = visitAll(this, block.children, context);
    if (block.name === 'switch') {
      return new Container(children, block.sourceSpan);
    }
    const parameters = block.parameters.map(param => param.expression);
    const startPhName = context.placeholderRegistry.getStartBlockPlaceholderName(block.name, parameters);
    const closePhName = context.placeholderRegistry.getCloseBlockPlaceholderName(block.name);
    context.placeholderToContent[startPhName] = {
      text: block.startSourceSpan.toString(),
      sourceSpan: block.startSourceSpan
    };
    context.placeholderToContent[closePhName] = {
      text: block.endSourceSpan ? block.endSourceSpan.toString() : '}',
      sourceSpan: block.endSourceSpan ?? block.sourceSpan
    };
    const node = new BlockPlaceholder(block.name, parameters, startPhName, closePhName, children, block.sourceSpan, block.startSourceSpan, block.endSourceSpan);
    return context.visitNodeFn(block, node);
  }
  visitBlockParameter(_parameter, _context) {
    throw new Error('Unreachable code');
  }
  visitLetDeclaration(decl, context) {
    return null;
  }
  _visitElementLike(node, context) {
    const children = visitAll(this, node.children, context);
    const attrs = {};
    const visitAttribute = attr => {
      attrs[attr.name] = attr.value;
    };
    let nodeName;
    let isVoid;
    if (node instanceof Element) {
      nodeName = node.name;
      isVoid = getHtmlTagDefinition(node.name).isVoid;
    } else {
      nodeName = node.fullName;
      isVoid = node.tagName ? getHtmlTagDefinition(node.tagName).isVoid : false;
    }
    node.attrs.forEach(visitAttribute);
    node.directives.forEach(dir => dir.attrs.forEach(visitAttribute));
    const startPhName = context.placeholderRegistry.getStartTagPlaceholderName(nodeName, attrs, isVoid);
    context.placeholderToContent[startPhName] = {
      text: node.startSourceSpan.toString(),
      sourceSpan: node.startSourceSpan
    };
    let closePhName = '';
    if (!isVoid) {
      closePhName = context.placeholderRegistry.getCloseTagPlaceholderName(nodeName);
      context.placeholderToContent[closePhName] = {
        text: `</${nodeName}>`,
        sourceSpan: node.endSourceSpan ?? node.sourceSpan
      };
    }
    const i18nNode = new TagPlaceholder(nodeName, attrs, startPhName, closePhName, children, isVoid, node.sourceSpan, node.startSourceSpan, node.endSourceSpan);
    return context.visitNodeFn(node, i18nNode);
  }
  _visitTextWithInterpolation(tokens, sourceSpan, context, previousI18n) {
    const nodes = [];
    let hasInterpolation = false;
    for (const token of tokens) {
      switch (token.type) {
        case 8:
        case 18:
          hasInterpolation = true;
          const [startMarker, expression, endMarker] = token.parts;
          const baseName = extractPlaceholderName(expression) || 'INTERPOLATION';
          const phName = context.placeholderRegistry.getPlaceholderName(baseName, expression);
          if (this._preserveExpressionWhitespace) {
            context.placeholderToContent[phName] = {
              text: token.parts.join(''),
              sourceSpan: token.sourceSpan
            };
            nodes.push(new Placeholder(expression, phName, token.sourceSpan));
          } else {
            const normalized = this.normalizeExpression(token);
            context.placeholderToContent[phName] = {
              text: `${startMarker}${normalized}${endMarker}`,
              sourceSpan: token.sourceSpan
            };
            nodes.push(new Placeholder(normalized, phName, token.sourceSpan));
          }
          break;
        default:
          if (token.parts[0].length > 0 || this._retainEmptyTokens) {
            const previous = nodes[nodes.length - 1];
            if (previous instanceof Text$2) {
              previous.value += token.parts[0];
              previous.sourceSpan = new ParseSourceSpan(previous.sourceSpan.start, token.sourceSpan.end, previous.sourceSpan.fullStart, previous.sourceSpan.details);
            } else {
              nodes.push(new Text$2(token.parts[0], token.sourceSpan));
            }
          } else {
            if (this._retainEmptyTokens) {
              nodes.push(new Text$2(token.parts[0], token.sourceSpan));
            }
          }
          break;
      }
    }
    if (hasInterpolation) {
      reusePreviousSourceSpans(nodes, previousI18n);
      return new Container(nodes, sourceSpan);
    } else {
      return nodes[0];
    }
  }
  normalizeExpression(token) {
    const expression = token.parts[1];
    const expr = this._expressionParser.parseBinding(expression, token.sourceSpan, token.sourceSpan.start.offset);
    return serialize(expr);
  }
}
function reusePreviousSourceSpans(nodes, previousI18n) {
  if (previousI18n instanceof Message) {
    assertSingleContainerMessage(previousI18n);
    previousI18n = previousI18n.nodes[0];
  }
  if (previousI18n instanceof Container) {
    assertEquivalentNodes(previousI18n.children, nodes);
    for (let i = 0; i < nodes.length; i++) {
      nodes[i].sourceSpan = previousI18n.children[i].sourceSpan;
    }
  }
}
function assertSingleContainerMessage(message) {
  const nodes = message.nodes;
  if (nodes.length !== 1 || !(nodes[0] instanceof Container)) {
    throw new Error('Unexpected previous i18n message - expected it to consist of only a single `Container` node.');
  }
}
function assertEquivalentNodes(previousNodes, nodes) {
  if (previousNodes.length !== nodes.length) {
    throw new Error(`
The number of i18n message children changed between first and second pass.

First pass (${previousNodes.length} tokens):
${previousNodes.map(node => `"${node.sourceSpan.toString()}"`).join('\n')}

Second pass (${nodes.length} tokens):
${nodes.map(node => `"${node.sourceSpan.toString()}"`).join('\n')}
    `.trim());
  }
  if (previousNodes.some((node, i) => nodes[i].constructor !== node.constructor)) {
    throw new Error('The types of the i18n message children changed between first and second pass.');
  }
}
const _CUSTOM_PH_EXP = /\/\/[\s\S]*i18n[\s\S]*\([\s\S]*ph[\s\S]*=[\s\S]*("|')([\s\S]*?)\1[\s\S]*\)/g;
function extractPlaceholderName(input) {
  return input.split(_CUSTOM_PH_EXP)[2];
}

const TRUSTED_TYPES_SINKS = new Set(['iframe|srcdoc', '*|innerhtml', '*|outerhtml', 'embed|src', 'iframe|src', 'object|codebase', 'object|data']);
function isTrustedTypesSink(tagName, propName) {
  tagName = tagName.toLowerCase();
  propName = propName.toLowerCase();
  return TRUSTED_TYPES_SINKS.has(tagName + '|' + propName) || TRUSTED_TYPES_SINKS.has('*|' + propName);
}

const setI18nRefs = originalNodeMap => {
  return (trimmedNode, i18nNode) => {
    const originalNode = originalNodeMap.get(trimmedNode) ?? trimmedNode;
    if (originalNode instanceof NodeWithI18n) {
      if (i18nNode instanceof IcuPlaceholder && originalNode.i18n instanceof Message) {
        i18nNode.previousMessage = originalNode.i18n;
      }
      originalNode.i18n = i18nNode;
    }
    return i18nNode;
  };
};
class I18nMetaVisitor {
  keepI18nAttrs;
  enableI18nLegacyMessageIdFormat;
  preserveSignificantWhitespace;
  retainEmptyTokens;
  hasI18nMeta = false;
  _errors = [];
  constructor(keepI18nAttrs = false, enableI18nLegacyMessageIdFormat = false, preserveSignificantWhitespace = true, retainEmptyTokens = !preserveSignificantWhitespace) {
    this.keepI18nAttrs = keepI18nAttrs;
    this.enableI18nLegacyMessageIdFormat = enableI18nLegacyMessageIdFormat;
    this.preserveSignificantWhitespace = preserveSignificantWhitespace;
    this.retainEmptyTokens = retainEmptyTokens;
  }
  _generateI18nMessage(nodes, meta = '', visitNodeFn) {
    const {
      meaning,
      description,
      customId
    } = this._parseMetadata(meta);
    const createI18nMessage = createI18nMessageFactory(this.retainEmptyTokens, this.preserveSignificantWhitespace);
    const message = createI18nMessage(nodes, meaning, description, customId, visitNodeFn);
    this._setMessageId(message, meta);
    this._setLegacyIds(message, meta);
    return message;
  }
  visitAllWithErrors(nodes) {
    const result = nodes.map(node => node.visit(this, null));
    return new ParseTreeResult(result, this._errors);
  }
  visitElement(element) {
    this._visitElementLike(element);
    return element;
  }
  visitComponent(component, context) {
    this._visitElementLike(component);
    return component;
  }
  visitExpansion(expansion, currentMessage) {
    let message;
    const meta = expansion.i18n;
    this.hasI18nMeta = true;
    if (meta instanceof IcuPlaceholder) {
      const name = meta.name;
      message = this._generateI18nMessage([expansion], meta);
      const icu = icuFromI18nMessage(message);
      icu.name = name;
      if (currentMessage !== null) {
        currentMessage.placeholderToMessage[name] = message;
      }
    } else {
      message = this._generateI18nMessage([expansion], currentMessage || meta);
    }
    expansion.i18n = message;
    return expansion;
  }
  visitText(text) {
    return text;
  }
  visitAttribute(attribute) {
    return attribute;
  }
  visitComment(comment) {
    return comment;
  }
  visitExpansionCase(expansionCase) {
    return expansionCase;
  }
  visitBlock(block, context) {
    visitAll(this, block.children, context);
    return block;
  }
  visitBlockParameter(parameter, context) {
    return parameter;
  }
  visitLetDeclaration(decl, context) {
    return decl;
  }
  visitDirective(directive, context) {
    return directive;
  }
  _visitElementLike(node) {
    let message = undefined;
    if (hasI18nAttrs(node)) {
      this.hasI18nMeta = true;
      const attrs = [];
      const attrsMeta = {};
      for (const attr of node.attrs) {
        if (attr.name === I18N_ATTR) {
          const i18n = node.i18n || attr.value;
          const originalNodeMap = new Map();
          const trimmedNodes = this.preserveSignificantWhitespace ? node.children : visitAllWithSiblings(new WhitespaceVisitor(false, originalNodeMap), node.children);
          message = this._generateI18nMessage(trimmedNodes, i18n, setI18nRefs(originalNodeMap));
          if (message.nodes.length === 0) {
            message = undefined;
          }
          node.i18n = message;
        } else if (attr.name.startsWith(I18N_ATTR_PREFIX)) {
          const name = attr.name.slice(I18N_ATTR_PREFIX.length);
          let isTrustedType;
          if (node instanceof Component) {
            isTrustedType = node.tagName === null ? false : isTrustedTypesSink(node.tagName, name);
          } else {
            isTrustedType = isTrustedTypesSink(node.name, name);
          }
          if (isTrustedType || isPossibleEventHandler(name)) {
            this._reportError(attr, `Translating attribute '${name}' is disallowed for security reasons.`);
          } else {
            attrsMeta[name] = attr.value;
          }
        } else {
          attrs.push(attr);
        }
      }
      if (Object.keys(attrsMeta).length) {
        for (const attr of attrs) {
          const meta = attrsMeta[attr.name];
          if (meta !== undefined && attr.value) {
            attr.i18n = this._generateI18nMessage([attr], attr.i18n || meta);
          }
        }
      }
      if (!this.keepI18nAttrs) {
        node.attrs = attrs;
      }
    }
    visitAll(this, node.children, message);
  }
  _parseMetadata(meta) {
    return typeof meta === 'string' ? parseI18nMeta(meta) : meta instanceof Message ? meta : {};
  }
  _setMessageId(message, meta) {
    if (!message.id) {
      message.id = meta instanceof Message && meta.id || decimalDigest(message);
    }
  }
  _setLegacyIds(message, meta) {
    if (this.enableI18nLegacyMessageIdFormat) {
      message.legacyIds = [computeDigest(message), computeDecimalDigest(message)];
    } else if (typeof meta !== 'string') {
      const previousMessage = meta instanceof Message ? meta : meta instanceof IcuPlaceholder ? meta.previousMessage : undefined;
      message.legacyIds = previousMessage ? previousMessage.legacyIds : [];
    }
  }
  _reportError(node, msg) {
    this._errors.push(new ParseError(node.sourceSpan, msg));
  }
}
const I18N_MEANING_SEPARATOR = '|';
const I18N_ID_SEPARATOR = '@@';
function parseI18nMeta(meta = '') {
  let customId;
  let meaning;
  let description;
  meta = meta.trim();
  if (meta) {
    const idIndex = meta.indexOf(I18N_ID_SEPARATOR);
    const descIndex = meta.indexOf(I18N_MEANING_SEPARATOR);
    let meaningAndDesc;
    [meaningAndDesc, customId] = idIndex > -1 ? [meta.slice(0, idIndex), meta.slice(idIndex + 2)] : [meta, ''];
    [meaning, description] = descIndex > -1 ? [meaningAndDesc.slice(0, descIndex), meaningAndDesc.slice(descIndex + 1)] : ['', meaningAndDesc];
  }
  return {
    customId,
    meaning,
    description
  };
}
function i18nMetaToJSDoc(meta) {
  const tags = [];
  if (meta.description) {
    tags.push({
      tagName: "desc",
      text: meta.description
    });
  } else {
    tags.push({
      tagName: "suppress",
      text: '{msgDescriptions}'
    });
  }
  if (meta.meaning) {
    tags.push({
      tagName: "meaning",
      text: meta.meaning
    });
  }
  return jsDocComment(tags);
}
function isPossibleEventHandler(propertyName) {
  const name = propertyName.toLowerCase();
  return name.length > 2 && name !== 'only' && name.startsWith('on');
}

function createGoogleGetMsgStatements(variable$1, message, closureVar, placeholderValues) {
  const messageString = serializeI18nMessageForGetMsg(message);
  const args = [literal(messageString)];
  if (Object.keys(placeholderValues).length) {
    args.push(mapLiteral(formatI18nPlaceholderNamesInMap(placeholderValues, true), true));
    args.push(mapLiteral({
      original_code: literalMap(Object.keys(placeholderValues).map(param => ({
        key: formatI18nPlaceholderName(param),
        quoted: true,
        value: message.placeholders[param] ? literal(message.placeholders[param].sourceSpan.toString()) : literal(message.placeholderToMessage[param].nodes.map(node => node.sourceSpan.toString()).join(''))
      })))
    }));
  }
  const googGetMsgStmt = new DeclareVarStmt(closureVar.name, variable('goog').prop('getMsg').callFn(args, null, undefined, [tsIgnoreComment()]), INFERRED_TYPE, StmtModifier.Final);
  googGetMsgStmt.addLeadingComment(i18nMetaToJSDoc(message));
  const i18nAssignmentStmt = new ExpressionStatement(variable$1.set(closureVar));
  return [googGetMsgStmt, i18nAssignmentStmt];
}
class GetMsgSerializerVisitor {
  formatPh(value) {
    return `{$${formatI18nPlaceholderName(value)}}`;
  }
  visitText(text) {
    return text.value;
  }
  visitContainer(container) {
    return container.children.map(child => child.visit(this)).join('');
  }
  visitIcu(icu) {
    return serializeIcuNode(icu);
  }
  visitTagPlaceholder(ph) {
    return ph.isVoid ? this.formatPh(ph.startName) : `${this.formatPh(ph.startName)}${ph.children.map(child => child.visit(this)).join('')}${this.formatPh(ph.closeName)}`;
  }
  visitPlaceholder(ph) {
    return this.formatPh(ph.name);
  }
  visitBlockPlaceholder(ph) {
    return `${this.formatPh(ph.startName)}${ph.children.map(child => child.visit(this)).join('')}${this.formatPh(ph.closeName)}`;
  }
  visitIcuPlaceholder(ph, context) {
    return this.formatPh(ph.name);
  }
}
const serializerVisitor = new GetMsgSerializerVisitor();
function serializeI18nMessageForGetMsg(message) {
  return message.nodes.map(node => node.visit(serializerVisitor, null)).join('');
}

function createLocalizeStatements(variable, message, params) {
  const {
    messageParts,
    placeHolders
  } = serializeI18nMessageForLocalize(message);
  const sourceSpan = getSourceSpan(message);
  const expressions = placeHolders.map(ph => params[ph.text]);
  const localizedString$1 = localizedString(message, messageParts, placeHolders, expressions, sourceSpan);
  const variableInitialization = variable.set(localizedString$1);
  return [new ExpressionStatement(variableInitialization, null, [tsIgnoreComment()])];
}
class LocalizeSerializerVisitor {
  placeholderToMessage;
  pieces;
  constructor(placeholderToMessage, pieces) {
    this.placeholderToMessage = placeholderToMessage;
    this.pieces = pieces;
  }
  visitText(text) {
    if (this.pieces[this.pieces.length - 1] instanceof LiteralPiece) {
      this.pieces[this.pieces.length - 1].text += text.value;
    } else {
      const sourceSpan = new ParseSourceSpan(text.sourceSpan.fullStart, text.sourceSpan.end, text.sourceSpan.fullStart, text.sourceSpan.details);
      this.pieces.push(new LiteralPiece(text.value, sourceSpan));
    }
  }
  visitContainer(container) {
    container.children.forEach(child => child.visit(this));
  }
  visitIcu(icu) {
    this.pieces.push(new LiteralPiece(serializeIcuNode(icu), icu.sourceSpan));
  }
  visitTagPlaceholder(ph) {
    this.pieces.push(this.createPlaceholderPiece(ph.startName, ph.startSourceSpan ?? ph.sourceSpan));
    if (!ph.isVoid) {
      ph.children.forEach(child => child.visit(this));
      this.pieces.push(this.createPlaceholderPiece(ph.closeName, ph.endSourceSpan ?? ph.sourceSpan));
    }
  }
  visitPlaceholder(ph) {
    this.pieces.push(this.createPlaceholderPiece(ph.name, ph.sourceSpan));
  }
  visitBlockPlaceholder(ph) {
    this.pieces.push(this.createPlaceholderPiece(ph.startName, ph.startSourceSpan ?? ph.sourceSpan));
    ph.children.forEach(child => child.visit(this));
    this.pieces.push(this.createPlaceholderPiece(ph.closeName, ph.endSourceSpan ?? ph.sourceSpan));
  }
  visitIcuPlaceholder(ph) {
    this.pieces.push(this.createPlaceholderPiece(ph.name, ph.sourceSpan, this.placeholderToMessage[ph.name]));
  }
  createPlaceholderPiece(name, sourceSpan, associatedMessage) {
    return new PlaceholderPiece(formatI18nPlaceholderName(name, false), sourceSpan, associatedMessage);
  }
}
function serializeI18nMessageForLocalize(message) {
  const pieces = [];
  const serializerVisitor = new LocalizeSerializerVisitor(message.placeholderToMessage, pieces);
  message.nodes.forEach(node => node.visit(serializerVisitor));
  return processMessagePieces(pieces);
}
function getSourceSpan(message) {
  const startNode = message.nodes[0];
  const endNode = message.nodes[message.nodes.length - 1];
  return new ParseSourceSpan(startNode.sourceSpan.fullStart, endNode.sourceSpan.end, startNode.sourceSpan.fullStart, startNode.sourceSpan.details);
}
function processMessagePieces(pieces) {
  const messageParts = [];
  const placeHolders = [];
  if (pieces[0] instanceof PlaceholderPiece) {
    messageParts.push(createEmptyMessagePart(pieces[0].sourceSpan.start));
  }
  for (let i = 0; i < pieces.length; i++) {
    const part = pieces[i];
    if (part instanceof LiteralPiece) {
      messageParts.push(part);
    } else {
      placeHolders.push(part);
      if (pieces[i - 1] instanceof PlaceholderPiece) {
        messageParts.push(createEmptyMessagePart(pieces[i - 1].sourceSpan.end));
      }
    }
  }
  if (pieces[pieces.length - 1] instanceof PlaceholderPiece) {
    messageParts.push(createEmptyMessagePart(pieces[pieces.length - 1].sourceSpan.end));
  }
  return {
    messageParts,
    placeHolders
  };
}
function createEmptyMessagePart(location) {
  return new LiteralPiece('', new ParseSourceSpan(location, location));
}

const NG_I18N_CLOSURE_MODE = 'ngI18nClosureMode';
const TRANSLATION_VAR_PREFIX = 'i18n_';
const I18N_ICU_MAPPING_PREFIX = 'I18N_EXP_';
const ESCAPE = '\uFFFD';
const CLOSURE_TRANSLATION_VAR_PREFIX = 'MSG_';
function getTranslationConstPrefix(extra) {
  return `${CLOSURE_TRANSLATION_VAR_PREFIX}${extra}`.toUpperCase();
}
function declareI18nVariable(variable) {
  return new DeclareVarStmt(variable.name, undefined, INFERRED_TYPE, undefined, variable.sourceSpan);
}
function collectI18nConsts(job) {
  const fileBasedI18nSuffix = job.relativeContextFilePath.replace(/[^A-Za-z0-9]/g, '_').toUpperCase() + '_';
  const extractedAttributesByI18nContext = new Map();
  const i18nAttributesByElement = new Map();
  const i18nExpressionsByElement = new Map();
  const messages = new Map();
  for (const unit of job.units) {
    for (const op of unit.ops()) {
      if (op.kind === OpKind.ExtractedAttribute && op.i18nContext !== null) {
        const attributes = extractedAttributesByI18nContext.get(op.i18nContext) ?? [];
        attributes.push(op);
        extractedAttributesByI18nContext.set(op.i18nContext, attributes);
      } else if (op.kind === OpKind.I18nAttributes) {
        i18nAttributesByElement.set(op.target, op);
      } else if (op.kind === OpKind.I18nExpression && op.usage === I18nExpressionFor.I18nAttribute) {
        const expressions = i18nExpressionsByElement.get(op.target) ?? [];
        expressions.push(op);
        i18nExpressionsByElement.set(op.target, expressions);
      } else if (op.kind === OpKind.I18nMessage) {
        messages.set(op.xref, op);
      }
    }
  }
  const i18nValuesByContext = new Map();
  const messageConstIndices = new Map();
  for (const unit of job.units) {
    for (const op of unit.create) {
      if (op.kind === OpKind.I18nMessage) {
        if (op.messagePlaceholder === null) {
          const {
            mainVar,
            statements
          } = collectMessage(job, fileBasedI18nSuffix, messages, op);
          if (op.i18nBlock !== null) {
            const i18nConst = job.addConst(mainVar, statements);
            messageConstIndices.set(op.i18nBlock, i18nConst);
          } else {
            job.constsInitializers.push(...statements);
            i18nValuesByContext.set(op.i18nContext, mainVar);
            const attributesForMessage = extractedAttributesByI18nContext.get(op.i18nContext);
            if (attributesForMessage !== undefined) {
              for (const attr of attributesForMessage) {
                attr.expression = mainVar.clone();
              }
            }
          }
        }
        OpList.remove(op);
      }
    }
  }
  for (const unit of job.units) {
    for (const elem of unit.create) {
      if (isElementOrContainerOp(elem)) {
        const i18nAttributes = i18nAttributesByElement.get(elem.xref);
        if (i18nAttributes === undefined) {
          continue;
        }
        let i18nExpressions = i18nExpressionsByElement.get(elem.xref);
        if (i18nExpressions === undefined) {
          throw new Error('AssertionError: Could not find any i18n expressions associated with an I18nAttributes instruction');
        }
        const seenPropertyNames = new Set();
        i18nExpressions = i18nExpressions.filter(i18nExpr => {
          const seen = seenPropertyNames.has(i18nExpr.name);
          seenPropertyNames.add(i18nExpr.name);
          return !seen;
        });
        const i18nAttributeConfig = i18nExpressions.flatMap(i18nExpr => {
          const i18nExprValue = i18nValuesByContext.get(i18nExpr.context);
          if (i18nExprValue === undefined) {
            throw new Error("AssertionError: Could not find i18n expression's value");
          }
          return [literal(i18nExpr.name), i18nExprValue];
        });
        i18nAttributes.i18nAttributesConfig = job.addConst(new LiteralArrayExpr(i18nAttributeConfig));
      }
    }
  }
  for (const unit of job.units) {
    for (const op of unit.create) {
      if (op.kind === OpKind.I18nStart) {
        const msgIndex = messageConstIndices.get(op.root);
        if (msgIndex === undefined) {
          throw new Error('AssertionError: Could not find corresponding i18n block index for an i18n message op; was an i18n message incorrectly assumed to correspond to an attribute?');
        }
        op.messageIndex = msgIndex;
      }
    }
  }
}
function collectMessage(job, fileBasedI18nSuffix, messages, messageOp) {
  const statements = [];
  const subMessagePlaceholders = new Map();
  for (const subMessageId of messageOp.subMessages) {
    const subMessage = messages.get(subMessageId);
    const {
      mainVar: subMessageVar,
      statements: subMessageStatements
    } = collectMessage(job, fileBasedI18nSuffix, messages, subMessage);
    statements.push(...subMessageStatements);
    const subMessages = subMessagePlaceholders.get(subMessage.messagePlaceholder) ?? [];
    subMessages.push(subMessageVar);
    subMessagePlaceholders.set(subMessage.messagePlaceholder, subMessages);
  }
  addSubMessageParams(messageOp, subMessagePlaceholders);
  messageOp.params = new Map([...messageOp.params.entries()].sort());
  const mainVar = variable(job.pool.uniqueName(TRANSLATION_VAR_PREFIX), DYNAMIC_TYPE);
  const closureVar = i18nGenerateClosureVar(job.pool, messageOp.message.id, fileBasedI18nSuffix, job.i18nUseExternalIds);
  let transformFn = undefined;
  if (messageOp.needsPostprocessing || messageOp.postprocessingParams.size > 0) {
    const postprocessingParams = Object.fromEntries([...messageOp.postprocessingParams.entries()].sort());
    const formattedPostprocessingParams = formatI18nPlaceholderNamesInMap(postprocessingParams, false);
    const extraTransformFnParams = [];
    if (messageOp.postprocessingParams.size > 0) {
      extraTransformFnParams.push(mapLiteral(formattedPostprocessingParams, true));
    }
    transformFn = expr => importExpr(Identifiers.i18nPostprocess).callFn([expr, ...extraTransformFnParams]);
  }
  statements.push(...getTranslationDeclStmts(messageOp.message, mainVar, closureVar, messageOp.params, transformFn));
  return {
    mainVar,
    statements
  };
}
function addSubMessageParams(messageOp, subMessagePlaceholders) {
  for (const [placeholder, subMessages] of subMessagePlaceholders) {
    if (subMessages.length === 1) {
      messageOp.params.set(placeholder, subMessages[0]);
    } else {
      messageOp.params.set(placeholder, literal(`${ESCAPE}${I18N_ICU_MAPPING_PREFIX}${placeholder}${ESCAPE}`));
      messageOp.postprocessingParams.set(placeholder, literalArr(subMessages));
    }
  }
}
function getTranslationDeclStmts(message, variable, closureVar, params, transformFn) {
  const paramsObject = Object.fromEntries(params);
  const statements = [declareI18nVariable(variable), ifStmt(createClosureModeGuard(), createGoogleGetMsgStatements(variable, message, closureVar, paramsObject), createLocalizeStatements(variable, message, formatI18nPlaceholderNamesInMap(paramsObject, false)))];
  if (transformFn) {
    statements.push(new ExpressionStatement(variable.set(transformFn(variable))));
  }
  return statements;
}
function createClosureModeGuard() {
  return typeofExpr(variable(NG_I18N_CLOSURE_MODE)).notIdentical(literal('undefined', STRING_TYPE)).and(variable(NG_I18N_CLOSURE_MODE));
}
function i18nGenerateClosureVar(pool, messageId, fileBasedI18nSuffix, useExternalIds) {
  let name;
  const suffix = fileBasedI18nSuffix;
  if (useExternalIds) {
    const prefix = getTranslationConstPrefix(`EXTERNAL_`);
    const uniqueSuffix = pool.uniqueName(suffix);
    name = `${prefix}${sanitizeIdentifier(messageId)}$$${uniqueSuffix}`;
  } else {
    const prefix = getTranslationConstPrefix(suffix);
    name = pool.uniqueName(prefix);
  }
  return variable(name);
}

function convertI18nText(job) {
  for (const unit of job.units) {
    let currentI18n = null;
    let currentIcu = null;
    const textNodeI18nBlocks = new Map();
    const textNodeIcus = new Map();
    const icuPlaceholderByText = new Map();
    for (const op of unit.create) {
      switch (op.kind) {
        case OpKind.I18nStart:
          if (op.context === null) {
            throw Error('I18n op should have its context set.');
          }
          currentI18n = op;
          break;
        case OpKind.I18nEnd:
          currentI18n = null;
          break;
        case OpKind.IcuStart:
          if (op.context === null) {
            throw Error('Icu op should have its context set.');
          }
          currentIcu = op;
          break;
        case OpKind.IcuEnd:
          currentIcu = null;
          break;
        case OpKind.Text:
          if (currentI18n !== null) {
            textNodeI18nBlocks.set(op.xref, currentI18n);
            textNodeIcus.set(op.xref, currentIcu);
            if (op.icuPlaceholder !== null) {
              const icuPlaceholderOp = createIcuPlaceholderOp(job.allocateXrefId(), op.icuPlaceholder, [op.initialValue]);
              OpList.replace(op, icuPlaceholderOp);
              icuPlaceholderByText.set(op.xref, icuPlaceholderOp);
            } else {
              OpList.remove(op);
            }
          }
          break;
      }
    }
    for (const op of unit.update) {
      switch (op.kind) {
        case OpKind.InterpolateText:
          if (!textNodeI18nBlocks.has(op.target)) {
            continue;
          }
          const i18nOp = textNodeI18nBlocks.get(op.target);
          const icuOp = textNodeIcus.get(op.target);
          const icuPlaceholder = icuPlaceholderByText.get(op.target);
          const contextId = icuOp ? icuOp.context : i18nOp.context;
          const resolutionTime = icuOp ? I18nParamResolutionTime.Postproccessing : I18nParamResolutionTime.Creation;
          const ops = [];
          for (let i = 0; i < op.interpolation.expressions.length; i++) {
            const expr = op.interpolation.expressions[i];
            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));
          }
          OpList.replaceWithMany(op, ops);
          if (icuPlaceholder !== undefined) {
            icuPlaceholder.strings = op.interpolation.strings;
          }
          break;
      }
    }
  }
}

function liftLocalRefs(job) {
  for (const unit of job.units) {
    for (const op of unit.create) {
      switch (op.kind) {
        case OpKind.ElementStart:
        case OpKind.ConditionalCreate:
        case OpKind.ConditionalBranchCreate:
        case OpKind.Template:
          if (!Array.isArray(op.localRefs)) {
            throw new Error(`AssertionError: expected localRefs to be an array still`);
          }
          op.numSlotsUsed += op.localRefs.length;
          if (op.localRefs.length > 0) {
            const localRefs = serializeLocalRefs(op.localRefs);
            op.localRefs = job.addConst(localRefs);
          } else {
            op.localRefs = null;
          }
          break;
      }
    }
  }
}
function serializeLocalRefs(refs) {
  const constRefs = [];
  for (const ref of refs) {
    constRefs.push(literal(ref.name), literal(ref.target));
  }
  return literalArr(constRefs);
}

function emitNamespaceChanges(job) {
  for (const unit of job.units) {
    let activeNamespace = Namespace.HTML;
    for (const op of unit.create) {
      if (op.kind !== OpKind.ElementStart) {
        continue;
      }
      if (op.namespace !== activeNamespace) {
        OpList.insertBefore(createNamespaceOp(op.namespace), op);
        activeNamespace = op.namespace;
      }
    }
  }
}

function parse(value) {
  const styles = [];
  let i = 0;
  let parenDepth = 0;
  let quote = 0;
  let valueStart = 0;
  let propStart = 0;
  let currentProp = null;
  while (i < value.length) {
    const token = value.charCodeAt(i++);
    switch (token) {
      case 40:
        parenDepth++;
        break;
      case 41:
        parenDepth--;
        break;
      case 39:
        if (quote === 0) {
          quote = 39;
        } else if (quote === 39 && value.charCodeAt(i - 1) !== 92) {
          quote = 0;
        }
        break;
      case 34:
        if (quote === 0) {
          quote = 34;
        } else if (quote === 34 && value.charCodeAt(i - 1) !== 92) {
          quote = 0;
        }
        break;
      case 58:
        if (!currentProp && parenDepth === 0 && quote === 0) {
          currentProp = hyphenate(value.substring(propStart, i - 1).trim());
          valueStart = i;
        }
        break;
      case 59:
        if (currentProp && valueStart > 0 && parenDepth === 0 && quote === 0) {
          const styleVal = value.substring(valueStart, i - 1).trim();
          styles.push(currentProp, styleVal);
          propStart = i;
          valueStart = 0;
          currentProp = null;
        }
        break;
    }
  }
  if (currentProp && valueStart) {
    const styleVal = value.slice(valueStart).trim();
    styles.push(currentProp, styleVal);
  }
  return styles;
}
function hyphenate(value) {
  return value.replace(/[a-z][A-Z]/g, v => {
    return v.charAt(0) + '-' + v.charAt(1);
  }).toLowerCase();
}
function parseExtractedStyles(job) {
  const elements = new Map();
  for (const unit of job.units) {
    for (const op of unit.create) {
      if (isElementOrContainerOp(op)) {
        elements.set(op.xref, op);
      }
    }
  }
  for (const unit of job.units) {
    for (const op of unit.create) {
      if (op.kind === OpKind.ExtractedAttribute && op.bindingKind === BindingKind.Attribute && isStringLiteral(op.expression)) {
        const target = elements.get(op.target);
        if (target !== undefined && (target.kind === OpKind.Template || target.kind === OpKind.ConditionalCreate || target.kind === OpKind.ConditionalBranchCreate) && target.templateKind === TemplateKind.Structural) {
          continue;
        }
        if (op.name === 'style') {
          const parsedStyles = parse(op.expression.value);
          for (let i = 0; i < parsedStyles.length - 1; i += 2) {
            OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.StyleProperty, null, parsedStyles[i], literal(parsedStyles[i + 1]), null, null, SecurityContext.STYLE), op);
          }
          OpList.remove(op);
        } else if (op.name === 'class') {
          const parsedClasses = op.expression.value.trim().split(/\s+/g);
          for (const parsedClass of parsedClasses) {
            OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.ClassName, null, parsedClass, null, null, null, SecurityContext.NONE), op);
          }
          OpList.remove(op);
        }
      }
    }
  }
}

function nameFunctionsAndVariables(job) {
  addNamesToView(job.root, job.componentName, {
    index: 0
  });
}
function addNamesToView(unit, baseName, state) {
  if (unit.fnName === null) {
    unit.fnName = unit.job.pool.uniqueName(sanitizeIdentifier(`${baseName}_${unit.job.fnSuffix}`), false);
  }
  const varNames = new Map();
  for (const op of unit.ops()) {
    switch (op.kind) {
      case OpKind.Property:
      case OpKind.DomProperty:
        if (op.bindingKind === BindingKind.LegacyAnimation) {
          op.name = '@' + op.name;
        }
        break;
      case OpKind.Animation:
        if (op.handlerFnName === null) {
          const animationKind = op.name.replace('.', '');
          op.handlerFnName = `${unit.fnName}_${animationKind}_cb`;
          op.handlerFnName = sanitizeIdentifier(op.handlerFnName);
        }
        break;
      case OpKind.AnimationListener:
        if (op.handlerFnName !== null) {
          break;
        }
        if (!op.hostListener && op.targetSlot.slot === null) {
          throw new Error(`Expected a slot to be assigned`);
        }
        const animationKind = op.name.replace('.', '');
        if (op.hostListener) {
          op.handlerFnName = `${baseName}_${animationKind}_HostBindingHandler`;
        } else {
          op.handlerFnName = `${unit.fnName}_${op.tag.replace('-', '_')}_${animationKind}_${op.targetSlot.slot}_listener`;
        }
        op.handlerFnName = sanitizeIdentifier(op.handlerFnName);
        break;
      case OpKind.Listener:
        if (op.handlerFnName !== null) {
          break;
        }
        if (!op.hostListener && op.targetSlot.slot === null) {
          throw new Error(`Expected a slot to be assigned`);
        }
        let animation = '';
        if (op.isLegacyAnimationListener) {
          op.name = `@${op.name}.${op.legacyAnimationPhase}`;
          animation = 'animation';
        }
        if (op.hostListener) {
          op.handlerFnName = `${baseName}_${animation}${op.name}_HostBindingHandler`;
        } else {
          op.handlerFnName = `${unit.fnName}_${op.tag.replace('-', '_')}_${animation}${op.name}_${op.targetSlot.slot}_listener`;
        }
        op.handlerFnName = sanitizeIdentifier(op.handlerFnName);
        break;
      case OpKind.TwoWayListener:
        if (op.handlerFnName !== null) {
          break;
        }
        if (op.targetSlot.slot === null) {
          throw new Error(`Expected a slot to be assigned`);
        }
        op.handlerFnName = sanitizeIdentifier(`${unit.fnName}_${op.tag.replace('-', '_')}_${op.name}_${op.targetSlot.slot}_listener`);
        break;
      case OpKind.Variable:
        varNames.set(op.xref, getVariableName(op.variable, state));
        break;
      case OpKind.RepeaterCreate:
        if (!(unit instanceof ViewCompilationUnit)) {
          throw new Error(`AssertionError: must be compiling a component`);
        }
        if (op.handle.slot === null) {
          throw new Error(`Expected slot to be assigned`);
        }
        if (op.emptyView !== null) {
          const emptyView = unit.job.views.get(op.emptyView);
          addNamesToView(emptyView, `${baseName}_${op.functionNameSuffix}Empty_${op.handle.slot + 2}`, state);
        }
        addNamesToView(unit.job.views.get(op.xref), `${baseName}_${op.functionNameSuffix}_${op.handle.slot + 1}`, state);
        break;
      case OpKind.Projection:
        if (!(unit instanceof ViewCompilationUnit)) {
          throw new Error(`AssertionError: must be compiling a component`);
        }
        if (op.handle.slot === null) {
          throw new Error(`Expected slot to be assigned`);
        }
        if (op.fallbackView !== null) {
          const fallbackView = unit.job.views.get(op.fallbackView);
          addNamesToView(fallbackView, `${baseName}_ProjectionFallback_${op.handle.slot}`, state);
        }
        break;
      case OpKind.ConditionalCreate:
      case OpKind.ConditionalBranchCreate:
      case OpKind.Template:
        if (!(unit instanceof ViewCompilationUnit)) {
          throw new Error(`AssertionError: must be compiling a component`);
        }
        const childView = unit.job.views.get(op.xref);
        if (op.handle.slot === null) {
          throw new Error(`Expected slot to be assigned`);
        }
        const suffix = op.functionNameSuffix.length === 0 ? '' : `_${op.functionNameSuffix}`;
        addNamesToView(childView, `${baseName}${suffix}_${op.handle.slot}`, state);
        break;
      case OpKind.StyleProp:
        op.name = stripImportant(normalizeStylePropName(op.name));
        break;
      case OpKind.ClassProp:
        op.name = stripImportant(op.name);
        break;
    }
  }
  for (const op of unit.ops()) {
    visitExpressionsInOp(op, expr => {
      if (!(expr instanceof ReadVariableExpr) || expr.name !== null) {
        return;
      }
      if (!varNames.has(expr.xref)) {
        throw new Error(`Variable ${expr.xref} not yet named`);
      }
      expr.name = varNames.get(expr.xref);
    });
  }
}
function getVariableName(variable, state) {
  if (variable.name === null) {
    switch (variable.kind) {
      case SemanticVariableKind.Context:
        variable.name = `ctx_r${state.index++}`;
        break;
      case SemanticVariableKind.Identifier:
        const compatPrefix = variable.identifier === CONTEXT_NAME ? 'i' : '';
        variable.name = `${variable.identifier}_${compatPrefix}r${++state.index}`;
        break;
      default:
        variable.name = `_r${++state.index}`;
        break;
    }
  }
  return variable.name;
}
function normalizeStylePropName(name) {
  return name.startsWith('--') ? name : hyphenate(name);
}
function stripImportant(name) {
  const importantIndex = name.indexOf('!important');
  if (importantIndex > -1) {
    return name.substring(0, importantIndex);
  }
  return name;
}

function mergeNextContextExpressions(job) {
  for (const unit of job.units) {
    for (const expr of unit.functions) {
      mergeNextContextsInOps(expr.ops);
    }
    for (const op of unit.create) {
      if (op.kind === OpKind.Listener || op.kind === OpKind.Animation || op.kind === OpKind.AnimationListener || op.kind === OpKind.TwoWayListener) {
        mergeNextContextsInOps(op.handlerOps);
      }
    }
    mergeNextContextsInOps(unit.create);
    mergeNextContextsInOps(unit.update);
  }
}
function mergeNextContextsInOps(ops) {
  for (const op of ops) {
    if (op.kind !== OpKind.Statement || !(op.statement instanceof ExpressionStatement) || !(op.statement.expr instanceof NextContextExpr)) {
      continue;
    }
    const mergeSteps = op.statement.expr.steps;
    let tryToMerge = true;
    for (let candidate = op.next; candidate.kind !== OpKind.ListEnd && tryToMerge; candidate = candidate.next) {
      visitExpressionsInOp(candidate, (expr, flags) => {
        if (!isIrExpression(expr)) {
          return expr;
        }
        if (!tryToMerge) {
          return;
        }
        if (flags & VisitorContextFlag.InChildOperation) {
          return;
        }
        switch (expr.kind) {
          case ExpressionKind.NextContext:
            expr.steps += mergeSteps;
            OpList.remove(op);
            tryToMerge = false;
            break;
          case ExpressionKind.GetCurrentView:
          case ExpressionKind.Reference:
          case ExpressionKind.ContextLetReference:
            tryToMerge = false;
            break;
        }
        return;
      });
    }
  }
}

const CONTAINER_TAG = 'ng-container';
function generateNgContainerOps(job) {
  for (const unit of job.units) {
    const updatedElementXrefs = new Set();
    for (const op of unit.create) {
      if (op.kind === OpKind.ElementStart && op.tag === CONTAINER_TAG) {
        op.kind = OpKind.ContainerStart;
        updatedElementXrefs.add(op.xref);
      }
      if (op.kind === OpKind.ElementEnd && updatedElementXrefs.has(op.xref)) {
        op.kind = OpKind.ContainerEnd;
      }
    }
  }
}

function lookupElement(elements, xref) {
  const el = elements.get(xref);
  if (el === undefined) {
    throw new Error('All attributes should have an element-like target.');
  }
  return el;
}
function disableBindings$1(job) {
  const elements = new Map();
  for (const view of job.units) {
    for (const op of view.create) {
      if (!isElementOrContainerOp(op)) {
        continue;
      }
      elements.set(op.xref, op);
    }
  }
  for (const unit of job.units) {
    for (const op of unit.create) {
      if ((op.kind === OpKind.ElementStart || op.kind === OpKind.ContainerStart) && op.nonBindable) {
        OpList.insertAfter(createDisableBindingsOp(op.xref), op);
      }
      if ((op.kind === OpKind.ElementEnd || op.kind === OpKind.ContainerEnd) && lookupElement(elements, op.xref).nonBindable) {
        OpList.insertBefore(createEnableBindingsOp(op.xref), op);
      }
    }
  }
}

function kindTest(kind) {
  return op => op.kind === kind;
}
function kindWithInterpolationTest(kind, interpolation) {
  return op => {
    return op.kind === kind && interpolation === op.expression instanceof Interpolation;
  };
}
function basicListenerKindTest(op) {
  return op.kind === OpKind.Listener && !(op.hostListener && op.isLegacyAnimationListener) || op.kind === OpKind.TwoWayListener || op.kind === OpKind.Animation || op.kind === OpKind.AnimationListener;
}
function nonInterpolationPropertyKindTest(op) {
  return (op.kind === OpKind.Property || op.kind === OpKind.TwoWayProperty) && !(op.expression instanceof Interpolation);
}
const CREATE_ORDERING = [{
  test: op => op.kind === OpKind.Listener && op.hostListener && op.isLegacyAnimationListener
}, {
  test: basicListenerKindTest
}];
const UPDATE_ORDERING = [{
  test: kindTest(OpKind.StyleMap),
  transform: keepLast
}, {
  test: kindTest(OpKind.ClassMap),
  transform: keepLast
}, {
  test: kindTest(OpKind.StyleProp)
}, {
  test: kindTest(OpKind.ClassProp)
}, {
  test: kindWithInterpolationTest(OpKind.Attribute, true)
}, {
  test: kindWithInterpolationTest(OpKind.Property, true)
}, {
  test: nonInterpolationPropertyKindTest
}, {
  test: kindWithInterpolationTest(OpKind.Attribute, false)
}, {
  test: kindTest(OpKind.Control)
}];
const UPDATE_HOST_ORDERING = [{
  test: kindWithInterpolationTest(OpKind.DomProperty, true)
}, {
  test: kindWithInterpolationTest(OpKind.DomProperty, false)
}, {
  test: kindTest(OpKind.Attribute)
}, {
  test: kindTest(OpKind.StyleMap),
  transform: keepLast
}, {
  test: kindTest(OpKind.ClassMap),
  transform: keepLast
}, {
  test: kindTest(OpKind.StyleProp)
}, {
  test: kindTest(OpKind.ClassProp)
}];
const handledOpKinds = new Set([OpKind.Listener, OpKind.TwoWayListener, OpKind.AnimationListener, OpKind.StyleMap, OpKind.ClassMap, OpKind.StyleProp, OpKind.ClassProp, OpKind.Property, OpKind.TwoWayProperty, OpKind.DomProperty, OpKind.Attribute, OpKind.Animation, OpKind.Control]);
function orderOps(job) {
  for (const unit of job.units) {
    orderWithin(unit.create, CREATE_ORDERING);
    const ordering = unit.job.kind === CompilationJobKind.Host ? UPDATE_HOST_ORDERING : UPDATE_ORDERING;
    orderWithin(unit.update, ordering);
  }
}
function orderWithin(opList, ordering) {
  let opsToOrder = [];
  let firstTargetInGroup = null;
  for (const op of opList) {
    const currentTarget = hasDependsOnSlotContextTrait(op) ? op.target : null;
    if (!handledOpKinds.has(op.kind) || currentTarget !== firstTargetInGroup && firstTargetInGroup !== null && currentTarget !== null) {
      OpList.insertBefore(reorder(opsToOrder, ordering), op);
      opsToOrder = [];
      firstTargetInGroup = null;
    }
    if (handledOpKinds.has(op.kind)) {
      opsToOrder.push(op);
      OpList.remove(op);
      firstTargetInGroup = currentTarget ?? firstTargetInGroup;
    }
  }
  opList.push(reorder(opsToOrder, ordering));
}
function reorder(ops, ordering) {
  const groups = Array.from(ordering, () => new Array());
  for (const op of ops) {
    const groupIndex = ordering.findIndex(o => o.test(op));
    groups[groupIndex].push(op);
  }
  return groups.flatMap((group, i) => {
    const transform = ordering[i].transform;
    return transform ? transform(group) : group;
  });
}
function keepLast(ops) {
  return ops.slice(ops.length - 1);
}

function removeContentSelectors(job) {
  for (const unit of job.units) {
    const elements = createOpXrefMap(unit);
    for (const op of unit.ops()) {
      switch (op.kind) {
        case OpKind.Binding:
          const target = lookupInXrefMap(elements, op.target);
          if (isSelectAttribute(op.name) && target.kind === OpKind.Projection) {
            OpList.remove(op);
          }
          break;
      }
    }
  }
}
function isSelectAttribute(name) {
  return name.toLowerCase() === 'select';
}
function lookupInXrefMap(map, xref) {
  const el = map.get(xref);
  if (el === undefined) {
    throw new Error('All attributes should have an slottable target.');
  }
  return el;
}

function createPipes(job) {
  for (const unit of job.units) {
    processPipeBindingsInView(unit);
  }
}
function processPipeBindingsInView(unit) {
  for (const updateOp of unit.update) {
    visitExpressionsInOp(updateOp, (expr, flags) => {
      if (!isIrExpression(expr)) {
        return;
      }
      if (expr.kind !== ExpressionKind.PipeBinding) {
        return;
      }
      if (flags & VisitorContextFlag.InChildOperation) {
        throw new Error(`AssertionError: pipe bindings should not appear in child expressions`);
      }
      const slotHandle = updateOp.target;
      if (slotHandle == undefined) {
        throw new Error(`AssertionError: expected slot handle to be assigned for pipe creation`);
      }
      addPipeToCreationBlock(unit, slotHandle, expr);
    });
  }
}
function addPipeToCreationBlock(unit, afterTargetXref, binding) {
  for (let op = unit.create.head.next; op.kind !== OpKind.ListEnd; op = op.next) {
    if (!hasConsumesSlotTrait(op)) {
      continue;
    }
    if (op.xref !== afterTargetXref) {
      continue;
    }
    while (op.next.kind === OpKind.Pipe) {
      op = op.next;
    }
    const pipe = createPipeOp(binding.target, binding.targetSlot, binding.name);
    OpList.insertBefore(pipe, op.next);
    return;
  }
  throw new Error(`AssertionError: unable to find insertion point for pipe ${binding.name}`);
}

function createVariadicPipes(job) {
  for (const unit of job.units) {
    for (const op of unit.update) {
      transformExpressionsInOp(op, expr => {
        if (!(expr instanceof PipeBindingExpr)) {
          return expr;
        }
        if (expr.args.length <= 4) {
          return expr;
        }
        return new PipeBindingVariadicExpr(expr.target, expr.targetSlot, expr.name, literalArr(expr.args), expr.args.length);
      }, VisitorContextFlag.None);
    }
  }
}

function propagateI18nBlocks(job) {
  propagateI18nBlocksToTemplates(job.root, 0);
}
function propagateI18nBlocksToTemplates(unit, subTemplateIndex) {
  let i18nBlock = null;
  for (const op of unit.create) {
    switch (op.kind) {
      case OpKind.I18nStart:
        op.subTemplateIndex = subTemplateIndex === 0 ? null : subTemplateIndex;
        i18nBlock = op;
        break;
      case OpKind.I18nEnd:
        if (i18nBlock.subTemplateIndex === null) {
          subTemplateIndex = 0;
        }
        i18nBlock = null;
        break;
      case OpKind.ConditionalCreate:
      case OpKind.ConditionalBranchCreate:
      case OpKind.Template:
        subTemplateIndex = propagateI18nBlocksForView(unit.job.views.get(op.xref), i18nBlock, op.i18nPlaceholder, subTemplateIndex);
        break;
      case OpKind.RepeaterCreate:
        const forView = unit.job.views.get(op.xref);
        subTemplateIndex = propagateI18nBlocksForView(forView, i18nBlock, op.i18nPlaceholder, subTemplateIndex);
        if (op.emptyView !== null) {
          subTemplateIndex = propagateI18nBlocksForView(unit.job.views.get(op.emptyView), i18nBlock, op.emptyI18nPlaceholder, subTemplateIndex);
        }
        break;
      case OpKind.Projection:
        if (op.fallbackView !== null) {
          subTemplateIndex = propagateI18nBlocksForView(unit.job.views.get(op.fallbackView), i18nBlock, op.fallbackViewI18nPlaceholder, subTemplateIndex);
        }
        break;
    }
  }
  return subTemplateIndex;
}
function propagateI18nBlocksForView(view, i18nBlock, i18nPlaceholder, subTemplateIndex) {
  if (i18nPlaceholder !== undefined) {
    if (i18nBlock === null) {
      throw Error('Expected template with i18n placeholder to be in an i18n block.');
    }
    subTemplateIndex++;
    wrapTemplateWithI18n(view, i18nBlock);
  }
  return propagateI18nBlocksToTemplates(view, subTemplateIndex);
}
function wrapTemplateWithI18n(unit, parentI18n) {
  if (unit.create.head.next?.kind !== OpKind.I18nStart) {
    const id = unit.job.allocateXrefId();
    OpList.insertAfter(createI18nStartOp(id, parentI18n.message, parentI18n.root, null), unit.create.head);
    OpList.insertBefore(createI18nEndOp(id, null), unit.create.tail);
  }
}

function extractPureFunctions(job) {
  for (const view of job.units) {
    for (const op of view.ops()) {
      visitExpressionsInOp(op, expr => {
        if (!(expr instanceof PureFunctionExpr) || expr.body === null) {
          return;
        }
        const constantDef = new PureFunctionConstant(expr.args.length);
        expr.fn = job.pool.getSharedConstant(constantDef, expr.body);
        expr.body = null;
      });
    }
  }
}
class PureFunctionConstant extends GenericKeyFn {
  numArgs;
  constructor(numArgs) {
    super();
    this.numArgs = numArgs;
  }
  keyOf(expr) {
    if (expr instanceof PureFunctionParameterExpr) {
      return `param(${expr.index})`;
    } else {
      return super.keyOf(expr);
    }
  }
  toSharedConstantDeclaration(declName, keyExpr) {
    const fnParams = [];
    for (let idx = 0; idx < this.numArgs; idx++) {
      fnParams.push(new FnParam('a' + idx, DYNAMIC_TYPE));
    }
    const returnExpr = transformExpressionsInExpression(keyExpr, expr => {
      if (!(expr instanceof PureFunctionParameterExpr)) {
        return expr;
      }
      return variable('a' + expr.index);
    }, VisitorContextFlag.None);
    return new DeclareVarStmt(declName, new ArrowFunctionExpr$1(fnParams, returnExpr), undefined, StmtModifier.Final);
  }
}

function generatePureLiteralStructures(job) {
  for (const unit of job.units) {
    for (const op of unit.update) {
      transformExpressionsInOp(op, (expr, flags) => {
        if (flags & VisitorContextFlag.InChildOperation) {
          return expr;
        }
        if (expr instanceof LiteralArrayExpr) {
          return transformLiteralArray(expr);
        } else if (expr instanceof LiteralMapExpr) {
          return transformLiteralMap(expr);
        }
        return expr;
      }, VisitorContextFlag.None);
    }
  }
}
function transformLiteralArray(expr) {
  const derivedEntries = [];
  const nonConstantArgs = [];
  for (const entry of expr.entries) {
    if (entry instanceof SpreadElementExpr) {
      if (entry.expression.isConstant()) {
        derivedEntries.push(entry);
      } else {
        const idx = nonConstantArgs.length;
        nonConstantArgs.push(entry.expression);
        derivedEntries.push(new SpreadElementExpr(new PureFunctionParameterExpr(idx)));
      }
      continue;
    }
    if (entry.isConstant()) {
      derivedEntries.push(entry);
    } else {
      const idx = nonConstantArgs.length;
      nonConstantArgs.push(entry);
      derivedEntries.push(new PureFunctionParameterExpr(idx));
    }
  }
  return new PureFunctionExpr(literalArr(derivedEntries), nonConstantArgs);
}
function transformLiteralMap(expr) {
  let derivedEntries = [];
  const nonConstantArgs = [];
  for (const entry of expr.entries) {
    if (entry instanceof LiteralMapSpreadAssignment) {
      if (entry.expression.isConstant()) {
        derivedEntries.push(entry);
      } else {
        const idx = nonConstantArgs.length;
        nonConstantArgs.push(entry.expression);
        derivedEntries.push(new LiteralMapSpreadAssignment(new PureFunctionParameterExpr(idx)));
      }
      continue;
    }
    if (entry.value.isConstant()) {
      derivedEntries.push(entry);
    } else {
      const idx = nonConstantArgs.length;
      nonConstantArgs.push(entry.value);
      derivedEntries.push(new LiteralMapPropertyAssignment(entry.key, new PureFunctionParameterExpr(idx), entry.quoted));
    }
  }
  return new PureFunctionExpr(new LiteralMapExpr(derivedEntries), nonConstantArgs);
}

const SAFE_REGEX_FLAGS = new Set(['d', 'i', 'm', 's', 'u', 'v']);
function optimizeRegularExpressions(job) {
  for (const view of job.units) {
    for (const op of view.ops()) {
      transformExpressionsInOp(op, expr => {
        if (expr instanceof RegularExpressionLiteralExpr && canOptimizeRegex(expr)) {
          return job.pool.getSharedConstant(new RegularExpressionConstant(), expr);
        }
        return expr;
      }, VisitorContextFlag.None);
    }
  }
}
function canOptimizeRegex(expr) {
  if (!expr.flags) {
    return true;
  }
  for (let i = 0; i < expr.flags.length; i++) {
    if (!SAFE_REGEX_FLAGS.has(expr.flags[i])) {
      return false;
    }
  }
  return true;
}
class RegularExpressionConstant extends GenericKeyFn {
  toSharedConstantDeclaration(declName, keyExpr) {
    return new DeclareVarStmt(declName, keyExpr, undefined, StmtModifier.Final);
  }
}

function element(slot, tag, constIndex, localRefIndex, sourceSpan) {
  return elementOrContainerBase(Identifiers.element, slot, tag, constIndex, localRefIndex, sourceSpan);
}
function elementStart(slot, tag, constIndex, localRefIndex, sourceSpan) {
  return elementOrContainerBase(Identifiers.elementStart, slot, tag, constIndex, localRefIndex, sourceSpan);
}
function foreignComponent(slot, foreignComponentRef, props, sourceSpan) {
  const args = [literal(slot), foreignComponentRef];
  if (props !== null) {
    args.push(props);
  }
  return call(Identifiers.foreignComponent, args, sourceSpan);
}
function foreignContent(slot, foreignComponentIndex, parameterized) {
  return importExpr(parameterized ? Identifiers.foreignContentFn : Identifiers.foreignContent).callFn([literal(slot), literal(foreignComponentIndex)]);
}
function elementOrContainerBase(instruction, slot, tag, constIndex, localRefIndex, sourceSpan) {
  const args = [literal(slot)];
  if (tag !== null) {
    args.push(literal(tag));
  }
  if (localRefIndex !== null) {
    args.push(literal(constIndex), literal(localRefIndex));
  } else if (constIndex !== null) {
    args.push(literal(constIndex));
  }
  return call(instruction, args, sourceSpan);
}
function templateBase(instruction, slot, templateFnRef, decls, vars, tag, constIndex, localRefs, sourceSpan) {
  const args = [literal(slot), templateFnRef, literal(decls), literal(vars), literal(tag), literal(constIndex)];
  if (localRefs !== null) {
    args.push(literal(localRefs));
    args.push(importExpr(Identifiers.templateRefExtractor));
  }
  while (args[args.length - 1].isEquivalent(NULL_EXPR)) {
    args.pop();
  }
  return call(instruction, args, sourceSpan);
}
function propertyBase(instruction, name, expression, sanitizer, sourceSpan) {
  const args = [literal(name)];
  if (expression instanceof Interpolation) {
    args.push(interpolationToExpression(expression, sourceSpan));
  } else {
    args.push(expression);
  }
  if (sanitizer !== null) {
    args.push(sanitizer);
  }
  return call(instruction, args, sourceSpan);
}
function elementEnd(sourceSpan) {
  return call(Identifiers.elementEnd, [], sourceSpan);
}
function elementContainerStart(slot, constIndex, localRefIndex, sourceSpan) {
  return elementOrContainerBase(Identifiers.elementContainerStart, slot, null, constIndex, localRefIndex, sourceSpan);
}
function elementContainer(slot, constIndex, localRefIndex, sourceSpan) {
  return elementOrContainerBase(Identifiers.elementContainer, slot, null, constIndex, localRefIndex, sourceSpan);
}
function elementContainerEnd() {
  return call(Identifiers.elementContainerEnd, [], null);
}
function template(slot, templateFnRef, decls, vars, tag, constIndex, localRefs, sourceSpan) {
  return templateBase(Identifiers.templateCreate, slot, templateFnRef, decls, vars, tag, constIndex, localRefs, sourceSpan);
}
function disableBindings() {
  return call(Identifiers.disableBindings, [], null);
}
function enableBindings() {
  return call(Identifiers.enableBindings, [], null);
}
function listener(name, handlerFn, eventTargetResolver, syntheticHost, sourceSpan) {
  const args = [literal(name), handlerFn];
  if (eventTargetResolver !== null) {
    args.push(importExpr(eventTargetResolver));
  }
  return call(syntheticHost ? Identifiers.syntheticHostListener : Identifiers.listener, args, sourceSpan);
}
function twoWayBindingSet(target, value) {
  return importExpr(Identifiers.twoWayBindingSet).callFn([target, value]);
}
function twoWayListener(name, handlerFn, sourceSpan) {
  return call(Identifiers.twoWayListener, [literal(name), handlerFn], sourceSpan);
}
function pipe(slot, name) {
  return call(Identifiers.pipe, [literal(slot), literal(name)], null);
}
function namespaceHTML() {
  return call(Identifiers.namespaceHTML, [], null);
}
function namespaceSVG() {
  return call(Identifiers.namespaceSVG, [], null);
}
function namespaceMath() {
  return call(Identifiers.namespaceMathML, [], null);
}
function advance(delta, sourceSpan) {
  return call(Identifiers.advance, delta > 1 ? [literal(delta)] : [], sourceSpan);
}
function reference(slot) {
  return importExpr(Identifiers.reference).callFn([literal(slot)]);
}
function nextContext(steps) {
  return importExpr(Identifiers.nextContext).callFn(steps === 1 ? [] : [literal(steps)]);
}
function getCurrentView() {
  return importExpr(Identifiers.getCurrentView).callFn([]);
}
function restoreView(savedView) {
  return importExpr(Identifiers.restoreView).callFn([savedView]);
}
function resetView(returnValue) {
  return importExpr(Identifiers.resetView).callFn([returnValue]);
}
function text(slot, initialValue, sourceSpan) {
  const args = [literal(slot, null)];
  if (initialValue !== '') {
    args.push(literal(initialValue));
  }
  return call(Identifiers.text, args, sourceSpan);
}
function defer(selfSlot, primarySlot, dependencyResolverFn, loadingSlot, placeholderSlot, errorSlot, loadingConfig, placeholderConfig, enableTimerScheduling, sourceSpan, flags) {
  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), literal(flags)];
  let expr;
  while ((expr = args[args.length - 1]) !== null && expr instanceof LiteralExpr && expr.value === null) {
    args.pop();
  }
  return call(Identifiers.defer, args, sourceSpan);
}
function enableIncrementalHydrationRuntime(sourceSpan) {
  return call(Identifiers.enableIncrementalHydrationRuntime, [], sourceSpan);
}
const deferTriggerToR3TriggerInstructionsMap = new Map([[DeferTriggerKind.Idle, {
  ["none"]: Identifiers.deferOnIdle,
  ["prefetch"]: Identifiers.deferPrefetchOnIdle,
  ["hydrate"]: Identifiers.deferHydrateOnIdle
}], [DeferTriggerKind.Immediate, {
  ["none"]: Identifiers.deferOnImmediate,
  ["prefetch"]: Identifiers.deferPrefetchOnImmediate,
  ["hydrate"]: Identifiers.deferHydrateOnImmediate
}], [DeferTriggerKind.Timer, {
  ["none"]: Identifiers.deferOnTimer,
  ["prefetch"]: Identifiers.deferPrefetchOnTimer,
  ["hydrate"]: Identifiers.deferHydrateOnTimer
}], [DeferTriggerKind.Hover, {
  ["none"]: Identifiers.deferOnHover,
  ["prefetch"]: Identifiers.deferPrefetchOnHover,
  ["hydrate"]: Identifiers.deferHydrateOnHover
}], [DeferTriggerKind.Interaction, {
  ["none"]: Identifiers.deferOnInteraction,
  ["prefetch"]: Identifiers.deferPrefetchOnInteraction,
  ["hydrate"]: Identifiers.deferHydrateOnInteraction
}], [DeferTriggerKind.Viewport, {
  ["none"]: Identifiers.deferOnViewport,
  ["prefetch"]: Identifiers.deferPrefetchOnViewport,
  ["hydrate"]: Identifiers.deferHydrateOnViewport
}], [DeferTriggerKind.Never, {
  ["none"]: Identifiers.deferHydrateNever,
  ["prefetch"]: Identifiers.deferHydrateNever,
  ["hydrate"]: Identifiers.deferHydrateNever
}]]);
function deferOn(trigger, args, modifier, sourceSpan) {
  const instructionToCall = deferTriggerToR3TriggerInstructionsMap.get(trigger)?.[modifier];
  if (instructionToCall === undefined) {
    throw new Error(`Unable to determine instruction for trigger ${trigger}`);
  }
  return call(instructionToCall, args, sourceSpan);
}
function projectionDef(def) {
  return call(Identifiers.projectionDef, def ? [def] : [], null);
}
function projection(slot, projectionSlotIndex, attributes, fallbackFnName, fallbackDecls, fallbackVars, sourceSpan) {
  const args = [literal(slot)];
  if (projectionSlotIndex !== 0 || attributes !== null || fallbackFnName !== null) {
    args.push(literal(projectionSlotIndex));
    if (attributes !== null) {
      args.push(attributes);
    }
    if (fallbackFnName !== null) {
      if (attributes === null) {
        args.push(literal(null));
      }
      args.push(variable(fallbackFnName), literal(fallbackDecls), literal(fallbackVars));
    }
  }
  return call(Identifiers.projection, args, sourceSpan);
}
function i18nStart(slot, constIndex, subTemplateIndex, sourceSpan) {
  const args = [literal(slot), literal(constIndex)];
  if (subTemplateIndex !== null) {
    args.push(literal(subTemplateIndex));
  }
  return call(Identifiers.i18nStart, args, sourceSpan);
}
function conditionalCreate(slot, templateFnRef, decls, vars, tag, constIndex, localRefs, sourceSpan) {
  const args = [literal(slot), templateFnRef, literal(decls), literal(vars), literal(tag), literal(constIndex)];
  if (localRefs !== null) {
    args.push(literal(localRefs));
    args.push(importExpr(Identifiers.templateRefExtractor));
  }
  while (args[args.length - 1].isEquivalent(NULL_EXPR)) {
    args.pop();
  }
  return call(Identifiers.conditionalCreate, args, sourceSpan);
}
function conditionalBranchCreate(slot, templateFnRef, decls, vars, tag, constIndex, localRefs, sourceSpan) {
  const args = [literal(slot), templateFnRef, literal(decls), literal(vars), literal(tag), literal(constIndex)];
  if (localRefs !== null) {
    args.push(literal(localRefs));
    args.push(importExpr(Identifiers.templateRefExtractor));
  }
  while (args[args.length - 1].isEquivalent(NULL_EXPR)) {
    args.pop();
  }
  return call(Identifiers.conditionalBranchCreate, args, sourceSpan);
}
function repeaterCreate(slot, viewFnName, decls, vars, tag, constIndex, trackByFn, trackByUsesComponentInstance, emptyViewFnName, emptyDecls, emptyVars, emptyTag, emptyConstIndex, sourceSpan) {
  const args = [literal(slot), variable(viewFnName), literal(decls), literal(vars), literal(tag), literal(constIndex), trackByFn];
  if (trackByUsesComponentInstance || emptyViewFnName !== null) {
    args.push(literal(trackByUsesComponentInstance));
    if (emptyViewFnName !== null) {
      args.push(variable(emptyViewFnName), literal(emptyDecls), literal(emptyVars));
      if (emptyTag !== null || emptyConstIndex !== null) {
        args.push(literal(emptyTag));
      }
      if (emptyConstIndex !== null) {
        args.push(literal(emptyConstIndex));
      }
    }
  }
  return call(Identifiers.repeaterCreate, args, sourceSpan);
}
function repeater(collection, sourceSpan) {
  return call(Identifiers.repeater, [collection], sourceSpan);
}
function deferWhen(modifier, expr, sourceSpan) {
  if (modifier === "prefetch") {
    return call(Identifiers.deferPrefetchWhen, [expr], sourceSpan);
  } else if (modifier === "hydrate") {
    return call(Identifiers.deferHydrateWhen, [expr], sourceSpan);
  }
  return call(Identifiers.deferWhen, [expr], sourceSpan);
}
function declareLet(slot, sourceSpan) {
  return call(Identifiers.declareLet, [literal(slot)], sourceSpan);
}
function storeLet(value, sourceSpan) {
  return importExpr(Identifiers.storeLet).callFn([value], sourceSpan);
}
function readContextLet(slot) {
  return importExpr(Identifiers.readContextLet).callFn([literal(slot)]);
}
function i18n(slot, constIndex, subTemplateIndex, sourceSpan) {
  const args = [literal(slot), literal(constIndex)];
  if (subTemplateIndex) {
    args.push(literal(subTemplateIndex));
  }
  return call(Identifiers.i18n, args, sourceSpan);
}
function i18nEnd(endSourceSpan) {
  return call(Identifiers.i18nEnd, [], endSourceSpan);
}
function i18nAttributes(slot, i18nAttributesConfig) {
  const args = [literal(slot), literal(i18nAttributesConfig)];
  return call(Identifiers.i18nAttributes, args, null);
}
function ariaProperty(name, expression, sourceSpan) {
  return propertyBase(Identifiers.ariaProperty, name, expression, null, sourceSpan);
}
function property(name, expression, sanitizer, sourceSpan) {
  return propertyBase(Identifiers.property, name, expression, sanitizer, sourceSpan);
}
function control(sourceSpan) {
  return call(Identifiers.control, [], sourceSpan);
}
function controlCreate(sourceSpan) {
  return call(Identifiers.controlCreate, [], sourceSpan);
}
function twoWayProperty(name, expression, sanitizer, sourceSpan) {
  const args = [literal(name), expression];
  if (sanitizer !== null) {
    args.push(sanitizer);
  }
  return call(Identifiers.twoWayProperty, args, sourceSpan);
}
function attribute(name, expression, sanitizer, namespace, sourceSpan) {
  const args = [literal(name)];
  if (expression instanceof Interpolation) {
    args.push(interpolationToExpression(expression, sourceSpan));
  } else {
    args.push(expression);
  }
  if (sanitizer !== null || namespace !== null) {
    args.push(sanitizer ?? literal(null));
  }
  if (namespace !== null) {
    args.push(literal(namespace));
  }
  return call(Identifiers.attribute, args, null);
}
function styleProp(name, expression, unit, sourceSpan) {
  const args = [literal(name)];
  if (expression instanceof Interpolation) {
    args.push(interpolationToExpression(expression, sourceSpan));
  } else {
    args.push(expression);
  }
  if (unit !== null) {
    args.push(literal(unit));
  }
  return call(Identifiers.styleProp, args, sourceSpan);
}
function classProp(name, expression, sourceSpan) {
  return call(Identifiers.classProp, [literal(name), expression], sourceSpan);
}
function styleMap(expression, sourceSpan) {
  const value = expression instanceof Interpolation ? interpolationToExpression(expression, sourceSpan) : expression;
  return call(Identifiers.styleMap, [value], sourceSpan);
}
function classMap(expression, sourceSpan) {
  const value = expression instanceof Interpolation ? interpolationToExpression(expression, sourceSpan) : expression;
  return call(Identifiers.classMap, [value], sourceSpan);
}
function domElement(slot, tag, constIndex, localRefIndex, sourceSpan) {
  return elementOrContainerBase(Identifiers.domElement, slot, tag, constIndex, localRefIndex, sourceSpan);
}
function domElementStart(slot, tag, constIndex, localRefIndex, sourceSpan) {
  return elementOrContainerBase(Identifiers.domElementStart, slot, tag, constIndex, localRefIndex, sourceSpan);
}
function domElementEnd(sourceSpan) {
  return call(Identifiers.domElementEnd, [], sourceSpan);
}
function domElementContainerStart(slot, constIndex, localRefIndex, sourceSpan) {
  return elementOrContainerBase(Identifiers.domElementContainerStart, slot, null, constIndex, localRefIndex, sourceSpan);
}
function domElementContainer(slot, constIndex, localRefIndex, sourceSpan) {
  return elementOrContainerBase(Identifiers.domElementContainer, slot, null, constIndex, localRefIndex, sourceSpan);
}
function domElementContainerEnd() {
  return call(Identifiers.domElementContainerEnd, [], null);
}
function domListener(name, handlerFn, eventTargetResolver, sourceSpan) {
  const args = [literal(name), handlerFn];
  if (eventTargetResolver !== null) {
    args.push(importExpr(eventTargetResolver));
  }
  return call(Identifiers.domListener, args, sourceSpan);
}
function domTemplate(slot, templateFnRef, decls, vars, tag, constIndex, localRefs, sourceSpan) {
  return templateBase(Identifiers.domTemplate, slot, templateFnRef, decls, vars, tag, constIndex, localRefs, sourceSpan);
}
const PIPE_BINDINGS = [Identifiers.pipeBind1, Identifiers.pipeBind2, Identifiers.pipeBind3, Identifiers.pipeBind4];
function pipeBind(slot, varOffset, args) {
  if (args.length < 1 || args.length > PIPE_BINDINGS.length) {
    throw new Error(`pipeBind() argument count out of bounds`);
  }
  const instruction = PIPE_BINDINGS[args.length - 1];
  return importExpr(instruction).callFn([literal(slot), literal(varOffset), ...args]);
}
function pipeBindV(slot, varOffset, args) {
  return importExpr(Identifiers.pipeBindV).callFn([literal(slot), literal(varOffset), args]);
}
function textInterpolate(strings, expressions, sourceSpan) {
  const interpolationArgs = collateInterpolationArgs(strings, expressions);
  return callVariadicInstruction(TEXT_INTERPOLATE_CONFIG, [], interpolationArgs, sourceSpan);
}
function i18nExp(expr, sourceSpan) {
  return call(Identifiers.i18nExp, [expr], sourceSpan);
}
function i18nApply(slot, sourceSpan) {
  return call(Identifiers.i18nApply, [literal(slot)], sourceSpan);
}
function domProperty(name, expression, sanitizer, sourceSpan) {
  return propertyBase(Identifiers.domProperty, name, expression, sanitizer, sourceSpan);
}
function animation(animationKind, handlerFn, sanitizer, sourceSpan) {
  const args = [handlerFn];
  if (sanitizer !== null) {
    args.push(sanitizer);
  }
  const identifier = animationKind === "enter" ? Identifiers.animationEnter : Identifiers.animationLeave;
  return call(identifier, args, sourceSpan);
}
function animationString(animationKind, expression, sanitizer, sourceSpan) {
  const value = expression instanceof Interpolation ? interpolationToExpression(expression, sourceSpan) : expression;
  const args = [value];
  if (sanitizer !== null) {
    args.push(sanitizer);
  }
  const identifier = animationKind === "enter" ? Identifiers.animationEnter : Identifiers.animationLeave;
  return call(identifier, args, sourceSpan);
}
function animationListener(animationKind, handlerFn, eventTargetResolver, sourceSpan) {
  const args = [handlerFn];
  const identifier = animationKind === "enter" ? Identifiers.animationEnterListener : Identifiers.animationLeaveListener;
  return call(identifier, args, sourceSpan);
}
function syntheticHostProperty(name, expression, sourceSpan) {
  return call(Identifiers.syntheticHostProperty, [literal(name), expression], sourceSpan);
}
function pureFunction(varOffset, fn, args) {
  return callVariadicInstructionExpr(PURE_FUNCTION_CONFIG, [literal(varOffset), fn], args, null);
}
function attachSourceLocation(templatePath, locations) {
  return call(Identifiers.attachSourceLocations, [literal(templatePath), locations], null);
}
function arrowFunction(slotOffset, factory, contextRef) {
  return importExpr(Identifiers.arrowFunction).callFn([literal(slotOffset), factory, contextRef]);
}
function collateInterpolationArgs(strings, expressions) {
  if (strings.length < 1 || expressions.length !== strings.length - 1) {
    throw new Error(`AssertionError: expected specific shape of args for strings/expressions in interpolation`);
  }
  const interpolationArgs = [];
  if (expressions.length === 1 && strings[0] === '' && strings[1] === '') {
    interpolationArgs.push(expressions[0]);
  } else {
    let idx;
    for (idx = 0; idx < expressions.length; idx++) {
      interpolationArgs.push(literal(strings[idx]), expressions[idx]);
    }
    interpolationArgs.push(literal(strings[idx]));
  }
  return interpolationArgs;
}
function interpolationToExpression(interpolation, sourceSpan) {
  const interpolationArgs = collateInterpolationArgs(interpolation.strings, interpolation.expressions);
  return callVariadicInstructionExpr(VALUE_INTERPOLATE_CONFIG, [], interpolationArgs, sourceSpan);
}
function call(instruction, args, sourceSpan) {
  const expr = importExpr(instruction).callFn(args, sourceSpan);
  return createStatementOp(new ExpressionStatement(expr, sourceSpan));
}
function conditional(condition, contextValue, sourceSpan) {
  const args = [condition];
  if (contextValue !== null) {
    args.push(contextValue);
  }
  return call(Identifiers.conditional, args, sourceSpan);
}
const TEXT_INTERPOLATE_CONFIG = {
  constant: [Identifiers.textInterpolate, Identifiers.textInterpolate1, Identifiers.textInterpolate2, Identifiers.textInterpolate3, Identifiers.textInterpolate4, Identifiers.textInterpolate5, Identifiers.textInterpolate6, Identifiers.textInterpolate7, Identifiers.textInterpolate8],
  variable: Identifiers.textInterpolateV,
  mapping: n => {
    if (n % 2 === 0) {
      throw new Error(`Expected odd number of arguments`);
    }
    return (n - 1) / 2;
  }
};
const VALUE_INTERPOLATE_CONFIG = {
  constant: [Identifiers.interpolate, Identifiers.interpolate1, Identifiers.interpolate2, Identifiers.interpolate3, Identifiers.interpolate4, Identifiers.interpolate5, Identifiers.interpolate6, Identifiers.interpolate7, Identifiers.interpolate8],
  variable: Identifiers.interpolateV,
  mapping: n => {
    if (n % 2 === 0) {
      throw new Error(`Expected odd number of arguments`);
    }
    return (n - 1) / 2;
  }
};
const PURE_FUNCTION_CONFIG = {
  constant: [Identifiers.pureFunction0, Identifiers.pureFunction1, Identifiers.pureFunction2, Identifiers.pureFunction3, Identifiers.pureFunction4, Identifiers.pureFunction5, Identifiers.pureFunction6, Identifiers.pureFunction7, Identifiers.pureFunction8],
  variable: Identifiers.pureFunctionV,
  mapping: n => n
};
function callVariadicInstructionExpr(config, baseArgs, interpolationArgs, sourceSpan) {
  const n = config.mapping(interpolationArgs.length);
  const lastInterpolationArg = interpolationArgs.at(-1);
  if (interpolationArgs.length > 1 && lastInterpolationArg instanceof LiteralExpr && lastInterpolationArg.value === '') {
    interpolationArgs.pop();
  }
  if (n < config.constant.length) {
    return importExpr(config.constant[n]).callFn([...baseArgs, ...interpolationArgs], sourceSpan);
  } else if (config.variable !== null) {
    return importExpr(config.variable).callFn([...baseArgs, literalArr(interpolationArgs)], sourceSpan);
  } else {
    throw new Error(`AssertionError: unable to call variadic function`);
  }
}
function callVariadicInstruction(config, baseArgs, interpolationArgs, sourceSpan) {
  return createStatementOp(callVariadicInstructionExpr(config, baseArgs, interpolationArgs, sourceSpan).toStmt());
}

const GLOBAL_TARGET_RESOLVERS = new Map([['window', Identifiers.resolveWindow], ['document', Identifiers.resolveDocument], ['body', Identifiers.resolveBody]]);
const DOM_PROPERTY_REMAPPING = new Map([['class', 'className'], ['for', 'htmlFor'], ['formaction', 'formAction'], ['innerHtml', 'innerHTML'], ['readonly', 'readOnly'], ['tabindex', 'tabIndex']]);
function reify(job) {
  for (const unit of job.units) {
    reifyCreateOperations(unit, unit.create);
    reifyUpdateOperations(unit, unit.update);
  }
}
function reifyCreateOperations(unit, ops) {
  for (const op of ops) {
    transformExpressionsInOp(op, expr => reifyIrExpression(unit, expr), VisitorContextFlag.None);
    switch (op.kind) {
      case OpKind.Text:
        OpList.replace(op, text(op.handle.slot, op.initialValue, op.sourceSpan));
        break;
      case OpKind.ElementStart:
        OpList.replace(op, unit.job.mode === TemplateCompilationMode.DomOnly ? domElementStart(op.handle.slot, op.tag, op.attributes, op.localRefs, op.startSourceSpan) : elementStart(op.handle.slot, op.tag, op.attributes, op.localRefs, op.startSourceSpan));
        break;
      case OpKind.Element:
        OpList.replace(op, unit.job.mode === TemplateCompilationMode.DomOnly ? domElement(op.handle.slot, op.tag, op.attributes, op.localRefs, op.wholeSourceSpan) : element(op.handle.slot, op.tag, op.attributes, op.localRefs, op.wholeSourceSpan));
        break;
      case OpKind.ForeignComponent:
        const propsMap = op.props.size > 0 ? literalMap(Array.from(op.props.entries()).map(([key, value]) => ({
          key,
          value,
          quoted: isUnsafeObjectKey(key)
        }))) : null;
        const propsExpr = propsMap !== null ? arrowFn([], propsMap) : null;
        OpList.replace(op, foreignComponent(op.handle.slot, literal(op.constIndex), propsExpr, op.sourceSpan));
        break;
      case OpKind.ElementEnd:
        OpList.replace(op, unit.job.mode === TemplateCompilationMode.DomOnly ? domElementEnd(op.sourceSpan) : elementEnd(op.sourceSpan));
        break;
      case OpKind.ContainerStart:
        OpList.replace(op, unit.job.mode === TemplateCompilationMode.DomOnly ? domElementContainerStart(op.handle.slot, op.attributes, op.localRefs, op.startSourceSpan) : elementContainerStart(op.handle.slot, op.attributes, op.localRefs, op.startSourceSpan));
        break;
      case OpKind.Container:
        OpList.replace(op, unit.job.mode === TemplateCompilationMode.DomOnly ? domElementContainer(op.handle.slot, op.attributes, op.localRefs, op.wholeSourceSpan) : elementContainer(op.handle.slot, op.attributes, op.localRefs, op.wholeSourceSpan));
        break;
      case OpKind.ContainerEnd:
        OpList.replace(op, unit.job.mode === TemplateCompilationMode.DomOnly ? domElementContainerEnd() : elementContainerEnd());
        break;
      case OpKind.I18nStart:
        OpList.replace(op, i18nStart(op.handle.slot, op.messageIndex, op.subTemplateIndex, op.sourceSpan));
        break;
      case OpKind.I18nEnd:
        OpList.replace(op, i18nEnd(op.sourceSpan));
        break;
      case OpKind.I18n:
        OpList.replace(op, i18n(op.handle.slot, op.messageIndex, op.subTemplateIndex, op.sourceSpan));
        break;
      case OpKind.I18nAttributes:
        if (op.i18nAttributesConfig === null) {
          throw new Error(`AssertionError: i18nAttributesConfig was not set`);
        }
        OpList.replace(op, i18nAttributes(op.handle.slot, op.i18nAttributesConfig));
        break;
      case OpKind.Template:
        if (!(unit instanceof ViewCompilationUnit)) {
          throw new Error(`AssertionError: must be compiling a component`);
        }
        if (Array.isArray(op.localRefs)) {
          throw new Error(`AssertionError: local refs array should have been extracted into a constant`);
        }
        const childView = unit.job.views.get(op.xref);
        OpList.replace(op, op.templateKind === TemplateKind.Block || unit.job.mode === TemplateCompilationMode.DomOnly ? domTemplate(op.handle.slot, variable(childView.fnName), childView.decls, childView.vars, op.tag, op.attributes, op.localRefs, op.startSourceSpan) : template(op.handle.slot, variable(childView.fnName), childView.decls, childView.vars, op.tag, op.attributes, op.localRefs, op.startSourceSpan));
        break;
      case OpKind.DisableBindings:
        OpList.replace(op, disableBindings());
        break;
      case OpKind.EnableBindings:
        OpList.replace(op, enableBindings());
        break;
      case OpKind.Pipe:
        OpList.replace(op, pipe(op.handle.slot, op.name));
        break;
      case OpKind.DeclareLet:
        OpList.replace(op, declareLet(op.handle.slot, op.sourceSpan));
        break;
      case OpKind.AnimationString:
        OpList.replace(op, animationString(op.animationKind, op.expression, op.sanitizer, op.sourceSpan));
        break;
      case OpKind.Animation:
        const animationCallbackFn = reifyListenerHandler(unit, op.handlerFnName, op.handlerOps, false);
        OpList.replace(op, animation(op.animationKind, animationCallbackFn, op.sanitizer, op.sourceSpan));
        break;
      case OpKind.AnimationListener:
        const animationListenerFn = reifyListenerHandler(unit, op.handlerFnName, op.handlerOps, op.consumesDollarEvent);
        OpList.replace(op, animationListener(op.animationKind, animationListenerFn, null, op.sourceSpan));
        break;
      case OpKind.Listener:
        const listenerFn = reifyListenerHandler(unit, op.handlerFnName, op.handlerOps, op.consumesDollarEvent);
        const eventTargetResolver = op.eventTarget ? GLOBAL_TARGET_RESOLVERS.get(op.eventTarget) : null;
        if (eventTargetResolver === undefined) {
          throw new Error(`Unexpected global target '${op.eventTarget}' defined for '${op.name}' event. Supported list of global targets: window,document,body.`);
        }
        OpList.replace(op, unit.job.mode === TemplateCompilationMode.DomOnly && !op.hostListener && !op.isLegacyAnimationListener ? domListener(op.name, listenerFn, eventTargetResolver, op.sourceSpan) : listener(op.name, listenerFn, eventTargetResolver, op.hostListener && op.isLegacyAnimationListener, op.sourceSpan));
        break;
      case OpKind.TwoWayListener:
        OpList.replace(op, twoWayListener(op.name, reifyListenerHandler(unit, op.handlerFnName, op.handlerOps, true), op.sourceSpan));
        break;
      case OpKind.Variable:
        if (op.variable.name === null) {
          throw new Error(`AssertionError: unnamed variable ${op.xref}`);
        }
        OpList.replace(op, createStatementOp(new DeclareVarStmt(op.variable.name, op.initializer, DYNAMIC_TYPE, StmtModifier.Final)));
        break;
      case OpKind.Namespace:
        switch (op.active) {
          case Namespace.HTML:
            OpList.replace(op, namespaceHTML());
            break;
          case Namespace.SVG:
            OpList.replace(op, namespaceSVG());
            break;
          case Namespace.Math:
            OpList.replace(op, namespaceMath());
            break;
        }
        break;
      case OpKind.Defer:
        const timerScheduling = !!op.loadingMinimumTime || !!op.loadingAfterTime || !!op.placeholderMinimumTime;
        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, op.flags));
        break;
      case OpKind.DeferOn:
        let args = [];
        const triggerKind = op.trigger.kind;
        switch (triggerKind) {
          case DeferTriggerKind.Never:
          case DeferTriggerKind.Immediate:
            break;
          case DeferTriggerKind.Idle:
            if (op.trigger.timeout != null) {
              args = [literal(op.trigger.timeout)];
            }
            break;
          case DeferTriggerKind.Timer:
            args = [literal(op.trigger.delay)];
            break;
          case DeferTriggerKind.Viewport:
            if (op.modifier === "hydrate") {
              args = op.trigger.options ? [op.trigger.options] : [];
            } else {
              args = [literal(op.trigger.targetSlot?.slot ?? null)];
              if (op.trigger.targetSlotViewSteps !== 0) {
                args.push(literal(op.trigger.targetSlotViewSteps));
              } else if (op.trigger.options) {
                args.push(literal(null));
              }
              if (op.trigger.options) {
                args.push(op.trigger.options);
              }
            }
            break;
          case DeferTriggerKind.Interaction:
          case DeferTriggerKind.Hover:
            if (op.modifier === "hydrate") {
              args = [];
            } else {
              args = [literal(op.trigger.targetSlot?.slot ?? null)];
              if (op.trigger.targetSlotViewSteps !== 0) {
                args.push(literal(op.trigger.targetSlotViewSteps));
              }
            }
            break;
          default:
            {
              const unhandledTriggerKind = triggerKind;
              throw new Error(`AssertionError: Unsupported reification of defer trigger kind ${unhandledTriggerKind}`);
            }
        }
        OpList.replace(op, deferOn(op.trigger.kind, args, op.modifier, op.sourceSpan));
        break;
      case OpKind.ProjectionDef:
        OpList.replace(op, projectionDef(op.def));
        break;
      case OpKind.EnableIncrementalHydrationRuntime:
        OpList.replace(op, enableIncrementalHydrationRuntime(op.sourceSpan));
        break;
      case OpKind.Projection:
        if (op.handle.slot === null) {
          throw new Error('No slot was assigned for project instruction');
        }
        let fallbackViewFnName = null;
        let fallbackDecls = null;
        let fallbackVars = null;
        if (op.fallbackView !== null) {
          if (!(unit instanceof ViewCompilationUnit)) {
            throw new Error(`AssertionError: must be compiling a component`);
          }
          const fallbackView = unit.job.views.get(op.fallbackView);
          if (fallbackView === undefined) {
            throw new Error('AssertionError: projection had fallback view xref, but fallback view was not found');
          }
          if (fallbackView.fnName === null || fallbackView.decls === null || fallbackView.vars === null) {
            throw new Error(`AssertionError: expected projection fallback view to have been named and counted`);
          }
          fallbackViewFnName = fallbackView.fnName;
          fallbackDecls = fallbackView.decls;
          fallbackVars = fallbackView.vars;
        }
        OpList.replace(op, projection(op.handle.slot, op.projectionSlotIndex, op.attributes, fallbackViewFnName, fallbackDecls, fallbackVars, op.sourceSpan));
        break;
      case OpKind.ConditionalCreate:
        if (!(unit instanceof ViewCompilationUnit)) {
          throw new Error(`AssertionError: must be compiling a component`);
        }
        if (Array.isArray(op.localRefs)) {
          throw new Error(`AssertionError: local refs array should have been extracted into a constant`);
        }
        const conditionalCreateChildView = unit.job.views.get(op.xref);
        OpList.replace(op, conditionalCreate(op.handle.slot, variable(conditionalCreateChildView.fnName), conditionalCreateChildView.decls, conditionalCreateChildView.vars, op.tag, op.attributes, op.localRefs, op.startSourceSpan));
        break;
      case OpKind.ConditionalBranchCreate:
        if (!(unit instanceof ViewCompilationUnit)) {
          throw new Error(`AssertionError: must be compiling a component`);
        }
        if (Array.isArray(op.localRefs)) {
          throw new Error(`AssertionError: local refs array should have been extracted into a constant`);
        }
        const conditionalBranchCreateChildView = unit.job.views.get(op.xref);
        OpList.replace(op, conditionalBranchCreate(op.handle.slot, variable(conditionalBranchCreateChildView.fnName), conditionalBranchCreateChildView.decls, conditionalBranchCreateChildView.vars, op.tag, op.attributes, op.localRefs, op.startSourceSpan));
        break;
      case OpKind.RepeaterCreate:
        if (op.handle.slot === null) {
          throw new Error('No slot was assigned for repeater instruction');
        }
        if (!(unit instanceof ViewCompilationUnit)) {
          throw new Error(`AssertionError: must be compiling a component`);
        }
        const repeaterView = unit.job.views.get(op.xref);
        if (repeaterView.fnName === null) {
          throw new Error(`AssertionError: expected repeater primary view to have been named`);
        }
        let emptyViewFnName = null;
        let emptyDecls = null;
        let emptyVars = null;
        if (op.emptyView !== null) {
          const emptyView = unit.job.views.get(op.emptyView);
          if (emptyView === undefined) {
            throw new Error('AssertionError: repeater had empty view xref, but empty view was not found');
          }
          if (emptyView.fnName === null || emptyView.decls === null || emptyView.vars === null) {
            throw new Error(`AssertionError: expected repeater empty view to have been named and counted`);
          }
          emptyViewFnName = emptyView.fnName;
          emptyDecls = emptyView.decls;
          emptyVars = emptyView.vars;
        }
        OpList.replace(op, repeaterCreate(op.handle.slot, repeaterView.fnName, op.decls, op.vars, op.tag, op.attributes, reifyTrackBy(unit, op), op.usesComponentInstance, emptyViewFnName, emptyDecls, emptyVars, op.emptyTag, op.emptyAttributes, op.wholeSourceSpan));
        break;
      case OpKind.SourceLocation:
        const locationsLiteral = literalArr(op.locations.map(({
          targetSlot,
          offset,
          line,
          column
        }) => {
          if (targetSlot.slot === null) {
            throw new Error('No slot was assigned for source location');
          }
          return literalArr([literal(targetSlot.slot), literal(offset), literal(line), literal(column)]);
        }));
        OpList.replace(op, attachSourceLocation(op.templatePath, locationsLiteral));
        break;
      case OpKind.ControlCreate:
        OpList.replace(op, controlCreate(op.sourceSpan));
        break;
      case OpKind.Statement:
        break;
      default:
        throw new Error(`AssertionError: Unsupported reification of create op ${OpKind[op.kind]}`);
    }
  }
}
function reifyUpdateOperations(unit, ops) {
  for (const op of ops) {
    transformExpressionsInOp(op, expr => reifyIrExpression(unit, expr), VisitorContextFlag.None);
    switch (op.kind) {
      case OpKind.Advance:
        OpList.replace(op, advance(op.delta, op.sourceSpan));
        break;
      case OpKind.Property:
        OpList.replace(op, unit.job.mode === TemplateCompilationMode.DomOnly && op.bindingKind !== BindingKind.LegacyAnimation && op.bindingKind !== BindingKind.Animation ? reifyDomProperty(op) : reifyProperty(op));
        break;
      case OpKind.Control:
        OpList.replace(op, reifyControl(op));
        break;
      case OpKind.TwoWayProperty:
        OpList.replace(op, twoWayProperty(op.name, op.expression, op.sanitizer, op.sourceSpan));
        break;
      case OpKind.StyleProp:
        OpList.replace(op, styleProp(op.name, op.expression, op.unit, op.sourceSpan));
        break;
      case OpKind.ClassProp:
        OpList.replace(op, classProp(op.name, op.expression, op.sourceSpan));
        break;
      case OpKind.StyleMap:
        OpList.replace(op, styleMap(op.expression, op.sourceSpan));
        break;
      case OpKind.ClassMap:
        OpList.replace(op, classMap(op.expression, op.sourceSpan));
        break;
      case OpKind.I18nExpression:
        OpList.replace(op, i18nExp(op.expression, op.sourceSpan));
        break;
      case OpKind.I18nApply:
        OpList.replace(op, i18nApply(op.handle.slot, op.sourceSpan));
        break;
      case OpKind.InterpolateText:
        OpList.replace(op, textInterpolate(op.interpolation.strings, op.interpolation.expressions, op.sourceSpan));
        break;
      case OpKind.Attribute:
        OpList.replace(op, attribute(op.name, op.expression, op.sanitizer, op.namespace, op.sourceSpan));
        break;
      case OpKind.DomProperty:
        if (op.expression instanceof Interpolation) {
          throw new Error('not yet handled');
        } else {
          if (op.bindingKind === BindingKind.LegacyAnimation || op.bindingKind === BindingKind.Animation) {
            OpList.replace(op, syntheticHostProperty(op.name, op.expression, op.sourceSpan));
          } else {
            OpList.replace(op, reifyDomProperty(op));
          }
        }
        break;
      case OpKind.Variable:
        if (op.variable.name === null) {
          throw new Error(`AssertionError: unnamed variable ${op.xref}`);
        }
        OpList.replace(op, createStatementOp(new DeclareVarStmt(op.variable.name, op.initializer, DYNAMIC_TYPE, StmtModifier.Final)));
        break;
      case OpKind.Conditional:
        if (op.processed === null) {
          throw new Error(`Conditional test was not set.`);
        }
        OpList.replace(op, conditional(op.processed, op.contextValue, op.sourceSpan));
        break;
      case OpKind.Repeater:
        OpList.replace(op, repeater(op.collection, op.sourceSpan));
        break;
      case OpKind.DeferWhen:
        OpList.replace(op, deferWhen(op.modifier, op.expr, op.sourceSpan));
        break;
      case OpKind.StoreLet:
        throw new Error(`AssertionError: unexpected storeLet ${op.declaredName}`);
      case OpKind.Statement:
        break;
      default:
        throw new Error(`AssertionError: Unsupported reification of update op ${OpKind[op.kind]}`);
    }
  }
}
function reifyDomProperty(op) {
  return domProperty(DOM_PROPERTY_REMAPPING.get(op.name) ?? op.name, op.expression, op.sanitizer, op.sourceSpan);
}
function reifyProperty(op) {
  return isAriaAttribute(op.name) ? ariaProperty(op.name, op.expression, op.sourceSpan) : property(op.name, op.expression, op.sanitizer, op.sourceSpan);
}
function reifyControl(op) {
  return control(op.sourceSpan);
}
function reifyIrExpression(unit, expr) {
  if (!isIrExpression(expr)) {
    return expr;
  }
  switch (expr.kind) {
    case ExpressionKind.NextContext:
      return nextContext(expr.steps);
    case ExpressionKind.Reference:
      return reference(expr.targetSlot.slot + 1 + expr.offset);
    case ExpressionKind.ForeignContent:
      if (!(unit instanceof ViewCompilationUnit)) {
        throw new Error(`AssertionError: must be compiling a component`);
      }
      const parameterized = unit.job.views.get(expr.childrenViewXref).contextVariables.size > 0;
      return foreignContent(expr.childrenViewHandle.slot, expr.foreignComponentConstIndex, parameterized);
    case ExpressionKind.LexicalRead:
      throw new Error(`AssertionError: unresolved LexicalRead of ${expr.name}`);
    case ExpressionKind.TwoWayBindingSet:
      throw new Error(`AssertionError: unresolved TwoWayBindingSet`);
    case ExpressionKind.RestoreView:
      if (typeof expr.view === 'number') {
        throw new Error(`AssertionError: unresolved RestoreView`);
      }
      return restoreView(expr.view);
    case ExpressionKind.ResetView:
      return resetView(expr.expr);
    case ExpressionKind.GetCurrentView:
      return getCurrentView();
    case ExpressionKind.ReadVariable:
      if (expr.name === null) {
        throw new Error(`Read of unnamed variable ${expr.xref}`);
      }
      return variable(expr.name);
    case ExpressionKind.ReadTemporaryExpr:
      if (expr.name === null) {
        throw new Error(`Read of unnamed temporary ${expr.xref}`);
      }
      return variable(expr.name);
    case ExpressionKind.AssignTemporaryExpr:
      if (expr.name === null) {
        throw new Error(`Assign of unnamed temporary ${expr.xref}`);
      }
      return variable(expr.name).set(expr.expr);
    case ExpressionKind.PureFunctionExpr:
      if (expr.fn === null) {
        throw new Error(`AssertionError: expected PureFunctions to have been extracted`);
      }
      return pureFunction(expr.varOffset, expr.fn, expr.args);
    case ExpressionKind.PureFunctionParameterExpr:
      throw new Error(`AssertionError: expected PureFunctionParameterExpr to have been extracted`);
    case ExpressionKind.PipeBinding:
      return pipeBind(expr.targetSlot.slot, expr.varOffset, expr.args);
    case ExpressionKind.PipeBindingVariadic:
      return pipeBindV(expr.targetSlot.slot, expr.varOffset, expr.args);
    case ExpressionKind.SlotLiteralExpr:
      return literal(expr.slot.slot);
    case ExpressionKind.ContextLetReference:
      return readContextLet(expr.targetSlot.slot);
    case ExpressionKind.StoreLet:
      return storeLet(expr.value, expr.sourceSpan);
    case ExpressionKind.TrackContext:
      return variable('this');
    case ExpressionKind.ArrowFunction:
      if (expr.varOffset === null) {
        throw new Error(`AssertionError: variable offset was not assigned to arrow function`);
      }
      return arrowFunction(expr.varOffset, unit.job.pool.getSharedFunctionReference(getArrowFunctionFactory(unit, expr), 'arrowFn'), variable(CONTEXT_NAME));
    default:
      throw new Error(`AssertionError: Unsupported reification of ir.Expression kind: ${ExpressionKind[expr.kind]}`);
  }
}
function reifyListenerHandler(unit, name, handlerOps, consumesDollarEvent) {
  reifyUpdateOperations(unit, handlerOps);
  const handlerStmts = [];
  for (const op of handlerOps) {
    if (op.kind !== OpKind.Statement) {
      throw new Error(`AssertionError: expected reified statements, but found op ${OpKind[op.kind]}`);
    }
    handlerStmts.push(op.statement);
  }
  const params = [];
  if (consumesDollarEvent) {
    params.push(new FnParam('$event', DYNAMIC_TYPE));
  }
  return fn(params, handlerStmts, undefined, undefined, name);
}
function reifyTrackBy(unit, op) {
  if (op.trackByFn !== null) {
    return op.trackByFn;
  }
  const params = [new FnParam('$index', NUMBER_TYPE), new FnParam('$item', DYNAMIC_TYPE)];
  let fn$1;
  if (op.trackByOps === null) {
    fn$1 = op.usesComponentInstance ? fn(params, [new ReturnStatement(op.track)]) : arrowFn(params, op.track);
  } else {
    reifyUpdateOperations(unit, op.trackByOps);
    const statements = [];
    for (const trackOp of op.trackByOps) {
      if (trackOp.kind !== OpKind.Statement) {
        throw new Error(`AssertionError: expected reified statements, but found op ${OpKind[trackOp.kind]}`);
      }
      statements.push(trackOp.statement);
    }
    fn$1 = op.usesComponentInstance || statements.length !== 1 || !(statements[0] instanceof ReturnStatement) ? fn(params, statements) : arrowFn(params, statements[0].value);
  }
  op.trackByFn = unit.job.pool.getSharedFunctionReference(fn$1, '_forTrack');
  return op.trackByFn;
}
function getArrowFunctionFactory(unit, expr) {
  reifyUpdateOperations(unit, expr.ops);
  const statements = [];
  for (const op of expr.ops) {
    if (op.kind !== OpKind.Statement) {
      throw new Error(`AssertionError: expected reified statements, but found op ${OpKind[op.kind]}`);
    }
    statements.push(op.statement);
  }
  const body = statements.length === 1 && statements[0] instanceof ReturnStatement ? statements[0].value : statements;
  return arrowFn([new FnParam(expr.contextName, DYNAMIC_TYPE), new FnParam(expr.currentViewName, DYNAMIC_TYPE)], arrowFn(expr.parameters, body));
}

function removeEmptyBindings(job) {
  for (const unit of job.units) {
    for (const op of unit.update) {
      switch (op.kind) {
        case OpKind.Attribute:
        case OpKind.Binding:
        case OpKind.ClassProp:
        case OpKind.ClassMap:
        case OpKind.Property:
        case OpKind.StyleProp:
        case OpKind.StyleMap:
          if (op.expression instanceof EmptyExpr) {
            OpList.remove(op);
          }
          break;
      }
    }
  }
}

function removeI18nContexts(job) {
  for (const unit of job.units) {
    for (const op of unit.create) {
      switch (op.kind) {
        case OpKind.I18nContext:
          OpList.remove(op);
          break;
        case OpKind.I18nStart:
          op.context = null;
          break;
      }
    }
  }
}

function removeIllegalLetReferences(job) {
  for (const unit of job.units) {
    for (const op of unit.update) {
      if (op.kind !== OpKind.Variable || op.variable.kind !== SemanticVariableKind.Identifier || !(op.initializer instanceof StoreLetExpr)) {
        continue;
      }
      const name = op.variable.identifier;
      let current = op;
      while (current && current.kind !== OpKind.ListEnd) {
        transformExpressionsInOp(current, expr => expr instanceof LexicalReadExpr && expr.name === name ? literal(undefined) : expr, VisitorContextFlag.None);
        current = current.prev;
      }
    }
  }
}

function removeUnusedI18nAttributesOps(job) {
  for (const unit of job.units) {
    const ownersWithI18nExpressions = new Set();
    for (const op of unit.update) {
      switch (op.kind) {
        case OpKind.I18nExpression:
          ownersWithI18nExpressions.add(op.i18nOwner);
      }
    }
    for (const op of unit.create) {
      switch (op.kind) {
        case OpKind.I18nAttributes:
          if (ownersWithI18nExpressions.has(op.xref)) {
            continue;
          }
          OpList.remove(op);
      }
    }
  }
}

function resolveContexts(job) {
  for (const unit of job.units) {
    for (const expr of unit.functions) {
      processLexicalScope$1(unit, expr.ops);
    }
    processLexicalScope$1(unit, unit.create);
    processLexicalScope$1(unit, unit.update);
  }
}
function processLexicalScope$1(view, ops) {
  const scope = new Map();
  scope.set(view.xref, variable(CONTEXT_NAME));
  for (const op of ops) {
    switch (op.kind) {
      case OpKind.Variable:
        switch (op.variable.kind) {
          case SemanticVariableKind.Context:
            scope.set(op.variable.view, new ReadVariableExpr(op.xref));
            break;
        }
        break;
      case OpKind.Animation:
      case OpKind.AnimationListener:
      case OpKind.Listener:
      case OpKind.TwoWayListener:
        processLexicalScope$1(view, op.handlerOps);
        break;
      case OpKind.RepeaterCreate:
        if (op.trackByOps !== null) {
          processLexicalScope$1(view, op.trackByOps);
        }
        break;
    }
  }
  if (view === view.job.root) {
    scope.set(view.xref, variable(CONTEXT_NAME));
  }
  for (const op of ops) {
    transformExpressionsInOp(op, expr => {
      if (expr instanceof ContextExpr) {
        if (!scope.has(expr.view)) {
          throw new Error(`No context found for reference to view ${expr.view} from view ${view.xref}`);
        }
        return scope.get(expr.view);
      } else {
        return expr;
      }
    }, VisitorContextFlag.None);
  }
}

function resolveDeferDepsFns(job) {
  for (const unit of job.units) {
    for (const op of unit.create) {
      if (op.kind === OpKind.Defer) {
        if (op.resolverFn !== null) {
          continue;
        }
        if (op.ownResolverFn !== null) {
          if (op.handle.slot === null) {
            throw new Error('AssertionError: slot must be assigned before extracting defer deps functions');
          }
          const fullPathName = unit.fnName?.replace('_Template', '');
          op.resolverFn = job.pool.getSharedFunctionReference(op.ownResolverFn, `${fullPathName}_Defer_${op.handle.slot}_DepsFn`, false);
        }
      }
    }
  }
}

function resolveDollarEvent(job) {
  for (const unit of job.units) {
    transformDollarEvent(unit.create);
    transformDollarEvent(unit.update);
  }
}
function transformDollarEvent(ops) {
  for (const op of ops) {
    if (op.kind === OpKind.Listener || op.kind === OpKind.TwoWayListener || op.kind === OpKind.AnimationListener) {
      transformExpressionsInOp(op, expr => {
        if (expr instanceof LexicalReadExpr && expr.name === '$event') {
          if (op.kind === OpKind.Listener || op.kind === OpKind.AnimationListener) {
            op.consumesDollarEvent = true;
          }
          return new ReadVarExpr(expr.name);
        }
        return expr;
      }, VisitorContextFlag.InChildOperation);
    }
  }
}

function resolveForeignContent(job) {
  for (const unit of job.units) {
    const foreignComponents = new Map();
    for (const op of unit.create) {
      if (op.kind === OpKind.ForeignComponent) {
        foreignComponents.set(op.xref, op);
      }
    }
    for (const op of unit.create) {
      if (op.kind !== OpKind.Content) {
        continue;
      }
      const target = foreignComponents.get(op.target);
      if (target === undefined) {
        throw new Error(`AssertionError: ContentOp target not found`);
      }
      const templateName = op.propertyName.charAt(0).toUpperCase() + op.propertyName.slice(1);
      const templateOp = createTemplateOp(op.view, TemplateKind.NgTemplate, null, templateName, Namespace.HTML, undefined, op.startSourceSpan, op.sourceSpan);
      OpList.replace(op, templateOp);
      const foreignContent = new ForeignContentExpr(templateOp.xref, templateOp.handle, target.constIndex);
      const varXref = job.allocateXrefId();
      const variable = {
        kind: SemanticVariableKind.Identifier,
        name: null,
        identifier: op.propertyName,
        local: true
      };
      const varOp = createVariableOp(varXref, variable, foreignContent, VariableFlags.None);
      OpList.insertBefore(varOp, target);
      target.props.set(op.propertyName, new ReadVariableExpr(varXref));
    }
  }
}

function resolveI18nElementPlaceholders(job) {
  const i18nContexts = new Map();
  const elements = new Map();
  for (const unit of job.units) {
    for (const op of unit.create) {
      switch (op.kind) {
        case OpKind.I18nContext:
          i18nContexts.set(op.xref, op);
          break;
        case OpKind.ElementStart:
          elements.set(op.xref, op);
          break;
      }
    }
  }
  resolvePlaceholdersForView(job, job.root, i18nContexts, elements);
}
function resolvePlaceholdersForView(job, unit, i18nContexts, elements, pendingStructuralDirective) {
  let currentOps = null;
  let pendingStructuralDirectiveCloses = new Map();
  for (const op of unit.create) {
    switch (op.kind) {
      case OpKind.I18nStart:
        if (!op.context) {
          throw Error('Could not find i18n context for i18n op');
        }
        currentOps = {
          i18nBlock: op,
          i18nContext: i18nContexts.get(op.context)
        };
        break;
      case OpKind.I18nEnd:
        currentOps = null;
        break;
      case OpKind.ElementStart:
        if (op.i18nPlaceholder !== undefined) {
          if (currentOps === null) {
            throw Error('i18n tag placeholder should only occur inside an i18n block');
          }
          recordElementStart(op, currentOps.i18nContext, currentOps.i18nBlock, pendingStructuralDirective);
          if (pendingStructuralDirective && op.i18nPlaceholder.closeName) {
            pendingStructuralDirectiveCloses.set(op.xref, pendingStructuralDirective);
          }
          pendingStructuralDirective = undefined;
        }
        break;
      case OpKind.ElementEnd:
        const startOp = elements.get(op.xref);
        if (startOp && startOp.i18nPlaceholder !== undefined) {
          if (currentOps === null) {
            throw Error('AssertionError: i18n tag placeholder should only occur inside an i18n block');
          }
          recordElementClose(startOp, currentOps.i18nContext, currentOps.i18nBlock, pendingStructuralDirectiveCloses.get(op.xref));
          pendingStructuralDirectiveCloses.delete(op.xref);
        }
        break;
      case OpKind.Projection:
        if (op.i18nPlaceholder !== undefined) {
          if (currentOps === null) {
            throw Error('i18n tag placeholder should only occur inside an i18n block');
          }
          recordElementStart(op, currentOps.i18nContext, currentOps.i18nBlock, pendingStructuralDirective);
          recordElementClose(op, currentOps.i18nContext, currentOps.i18nBlock, pendingStructuralDirective);
          pendingStructuralDirective = undefined;
        }
        if (op.fallbackView !== null) {
          const view = job.views.get(op.fallbackView);
          if (op.fallbackViewI18nPlaceholder === undefined) {
            resolvePlaceholdersForView(job, view, i18nContexts, elements);
          } else {
            if (currentOps === null) {
              throw Error('i18n tag placeholder should only occur inside an i18n block');
            }
            recordTemplateStart(job, view, op.handle.slot, op.fallbackViewI18nPlaceholder, currentOps.i18nContext, currentOps.i18nBlock, pendingStructuralDirective);
            resolvePlaceholdersForView(job, view, i18nContexts, elements);
            recordTemplateClose(job, view, op.handle.slot, op.fallbackViewI18nPlaceholder, currentOps.i18nContext, currentOps.i18nBlock, pendingStructuralDirective);
            pendingStructuralDirective = undefined;
          }
        }
        break;
      case OpKind.ConditionalCreate:
      case OpKind.ConditionalBranchCreate:
      case OpKind.Template:
        const view = job.views.get(op.xref);
        if (op.i18nPlaceholder === undefined) {
          resolvePlaceholdersForView(job, view, i18nContexts, elements);
        } else {
          if (currentOps === null) {
            throw Error('i18n tag placeholder should only occur inside an i18n block');
          }
          if (op.templateKind === TemplateKind.Structural) {
            resolvePlaceholdersForView(job, view, i18nContexts, elements, op);
          } else {
            recordTemplateStart(job, view, op.handle.slot, op.i18nPlaceholder, currentOps.i18nContext, currentOps.i18nBlock, pendingStructuralDirective);
            resolvePlaceholdersForView(job, view, i18nContexts, elements);
            recordTemplateClose(job, view, op.handle.slot, op.i18nPlaceholder, currentOps.i18nContext, currentOps.i18nBlock, pendingStructuralDirective);
            pendingStructuralDirective = undefined;
          }
        }
        break;
      case OpKind.RepeaterCreate:
        if (pendingStructuralDirective !== undefined) {
          throw Error('AssertionError: Unexpected structural directive associated with @for block');
        }
        const forSlot = op.handle.slot + 1;
        const forView = job.views.get(op.xref);
        if (op.i18nPlaceholder === undefined) {
          resolvePlaceholdersForView(job, forView, i18nContexts, elements);
        } else {
          if (currentOps === null) {
            throw Error('i18n tag placeholder should only occur inside an i18n block');
          }
          recordTemplateStart(job, forView, forSlot, op.i18nPlaceholder, currentOps.i18nContext, currentOps.i18nBlock, pendingStructuralDirective);
          resolvePlaceholdersForView(job, forView, i18nContexts, elements);
          recordTemplateClose(job, forView, forSlot, op.i18nPlaceholder, currentOps.i18nContext, currentOps.i18nBlock, pendingStructuralDirective);
          pendingStructuralDirective = undefined;
        }
        if (op.emptyView !== null) {
          const emptySlot = op.handle.slot + 2;
          const emptyView = job.views.get(op.emptyView);
          if (op.emptyI18nPlaceholder === undefined) {
            resolvePlaceholdersForView(job, emptyView, i18nContexts, elements);
          } else {
            if (currentOps === null) {
              throw Error('i18n tag placeholder should only occur inside an i18n block');
            }
            recordTemplateStart(job, emptyView, emptySlot, op.emptyI18nPlaceholder, currentOps.i18nContext, currentOps.i18nBlock, pendingStructuralDirective);
            resolvePlaceholdersForView(job, emptyView, i18nContexts, elements);
            recordTemplateClose(job, emptyView, emptySlot, op.emptyI18nPlaceholder, currentOps.i18nContext, currentOps.i18nBlock, pendingStructuralDirective);
            pendingStructuralDirective = undefined;
          }
        }
        break;
    }
  }
}
function recordElementStart(op, i18nContext, i18nBlock, structuralDirective) {
  const {
    startName,
    closeName
  } = op.i18nPlaceholder;
  let flags = I18nParamValueFlags.ElementTag | I18nParamValueFlags.OpenTag;
  let value = op.handle.slot;
  if (structuralDirective !== undefined) {
    flags |= I18nParamValueFlags.TemplateTag;
    value = {
      element: value,
      template: structuralDirective.handle.slot
    };
  }
  if (!closeName) {
    flags |= I18nParamValueFlags.CloseTag;
  }
  addParam(i18nContext.params, startName, value, i18nBlock.subTemplateIndex, flags);
}
function recordElementClose(op, i18nContext, i18nBlock, structuralDirective) {
  const {
    closeName
  } = op.i18nPlaceholder;
  if (closeName) {
    let flags = I18nParamValueFlags.ElementTag | I18nParamValueFlags.CloseTag;
    let value = op.handle.slot;
    if (structuralDirective !== undefined) {
      flags |= I18nParamValueFlags.TemplateTag;
      value = {
        element: value,
        template: structuralDirective.handle.slot
      };
    }
    addParam(i18nContext.params, closeName, value, i18nBlock.subTemplateIndex, flags);
  }
}
function recordTemplateStart(job, view, slot, i18nPlaceholder, i18nContext, i18nBlock, structuralDirective) {
  let {
    startName,
    closeName
  } = i18nPlaceholder;
  let flags = I18nParamValueFlags.TemplateTag | I18nParamValueFlags.OpenTag;
  if (!closeName) {
    flags |= I18nParamValueFlags.CloseTag;
  }
  if (structuralDirective !== undefined) {
    addParam(i18nContext.params, startName, structuralDirective.handle.slot, i18nBlock.subTemplateIndex, flags);
  }
  addParam(i18nContext.params, startName, slot, getSubTemplateIndexForTemplateTag(job, i18nBlock, view), flags);
}
function recordTemplateClose(job, view, slot, i18nPlaceholder, i18nContext, i18nBlock, structuralDirective) {
  const {
    closeName
  } = i18nPlaceholder;
  const flags = I18nParamValueFlags.TemplateTag | I18nParamValueFlags.CloseTag;
  if (closeName) {
    addParam(i18nContext.params, closeName, slot, getSubTemplateIndexForTemplateTag(job, i18nBlock, view), flags);
    if (structuralDirective !== undefined) {
      addParam(i18nContext.params, closeName, structuralDirective.handle.slot, i18nBlock.subTemplateIndex, flags);
    }
  }
}
function getSubTemplateIndexForTemplateTag(job, i18nOp, view) {
  for (const childOp of view.create) {
    if (childOp.kind === OpKind.I18nStart) {
      return childOp.subTemplateIndex;
    }
  }
  return i18nOp.subTemplateIndex;
}
function addParam(params, placeholder, value, subTemplateIndex, flags) {
  const values = params.get(placeholder) ?? [];
  values.push({
    value,
    subTemplateIndex,
    flags
  });
  params.set(placeholder, values);
}

function resolveI18nExpressionPlaceholders(job) {
  const subTemplateIndices = new Map();
  const i18nContexts = new Map();
  const icuPlaceholders = new Map();
  for (const unit of job.units) {
    for (const op of unit.create) {
      switch (op.kind) {
        case OpKind.I18nStart:
          subTemplateIndices.set(op.xref, op.subTemplateIndex);
          break;
        case OpKind.I18nContext:
          i18nContexts.set(op.xref, op);
          break;
        case OpKind.IcuPlaceholder:
          icuPlaceholders.set(op.xref, op);
          break;
      }
    }
  }
  const expressionIndices = new Map();
  const referenceIndex = op => op.usage === I18nExpressionFor.I18nText ? op.i18nOwner : op.context;
  for (const unit of job.units) {
    for (const op of unit.update) {
      if (op.kind === OpKind.I18nExpression) {
        const index = expressionIndices.get(referenceIndex(op)) || 0;
        const subTemplateIndex = subTemplateIndices.get(op.i18nOwner) ?? null;
        const value = {
          value: index,
          subTemplateIndex: subTemplateIndex,
          flags: I18nParamValueFlags.ExpressionIndex
        };
        updatePlaceholder(op, value, i18nContexts, icuPlaceholders);
        expressionIndices.set(referenceIndex(op), index + 1);
      }
    }
  }
}
function updatePlaceholder(op, value, i18nContexts, icuPlaceholders) {
  if (op.i18nPlaceholder !== null) {
    const i18nContext = i18nContexts.get(op.context);
    const params = op.resolutionTime === I18nParamResolutionTime.Creation ? i18nContext.params : i18nContext.postprocessingParams;
    const values = params.get(op.i18nPlaceholder) || [];
    values.push(value);
    params.set(op.i18nPlaceholder, values);
  }
  if (op.icuPlaceholder !== null) {
    const icuPlaceholderOp = icuPlaceholders.get(op.icuPlaceholder);
    icuPlaceholderOp?.expressionPlaceholders.push(value);
  }
}

function resolveI18nAttrSanitizers(job) {
  const tagNamesByElement = new Map();
  for (const unit of job.units) {
    for (const op of unit.ops()) {
      if (op.kind === OpKind.ElementStart || op.kind === OpKind.Template) {
        let tag = op.tag ?? '';
        switch (op.namespace) {
          case Namespace.SVG:
            tag = `:${SVG_NAMESPACE}:${tag}`;
            break;
          case Namespace.Math:
            tag = `:${MATH_ML_NAMESPACE}:${tag}`;
            break;
        }
        tagNamesByElement.set(op.xref, tag);
      }
    }
  }
  for (const unit of job.units) {
    for (const op of unit.create) {
      if (op.kind === OpKind.ExtractedAttribute && op.i18nContext !== null && op.expression !== null) {
        const tagName = tagNamesByElement.get(op.target) ?? '';
        let expr = op.expression;
        switch (op.securityContext) {
          case SecurityContext.HTML:
            expr = importExpr(Identifiers.sanitizeHtml).callFn([expr]);
            break;
          case SecurityContext.STYLE:
            expr = importExpr(Identifiers.sanitizeStyle).callFn([expr]);
            break;
          case SecurityContext.SCRIPT:
            expr = importExpr(Identifiers.sanitizeScript).callFn([expr]);
            break;
          case SecurityContext.URL:
            expr = importExpr(Identifiers.sanitizeUrl).callFn([expr]);
            break;
          case SecurityContext.RESOURCE_URL:
            expr = importExpr(Identifiers.sanitizeResourceUrl).callFn([expr]);
            break;
          case SecurityContext.ATTRIBUTE_NO_BINDING:
            expr = importExpr(Identifiers.validateAttribute).callFn([expr, literal(tagName), literal(op.name)]);
            break;
        }
        op.expression = expr;
      }
    }
  }
}

function resolveNames(job) {
  for (const unit of job.units) {
    for (const expr of unit.functions) {
      processLexicalScope(unit, expr.ops, null);
    }
    processLexicalScope(unit, unit.create, null);
    processLexicalScope(unit, unit.update, null);
  }
}
function processLexicalScope(unit, ops, savedView) {
  const scope = new Map();
  const localDefinitions = new Map();
  for (const op of ops) {
    switch (op.kind) {
      case OpKind.Variable:
        switch (op.variable.kind) {
          case SemanticVariableKind.Identifier:
            if (op.variable.local) {
              if (localDefinitions.has(op.variable.identifier)) {
                continue;
              }
              localDefinitions.set(op.variable.identifier, op.xref);
            } else if (scope.has(op.variable.identifier)) {
              continue;
            }
            scope.set(op.variable.identifier, op.xref);
            break;
          case SemanticVariableKind.Alias:
            if (scope.has(op.variable.identifier)) {
              continue;
            }
            scope.set(op.variable.identifier, op.xref);
            break;
          case SemanticVariableKind.SavedView:
            savedView = {
              view: op.variable.view,
              variable: op.xref
            };
            break;
        }
        break;
      case OpKind.Animation:
      case OpKind.AnimationListener:
      case OpKind.Listener:
      case OpKind.TwoWayListener:
        processLexicalScope(unit, op.handlerOps, savedView);
        break;
      case OpKind.RepeaterCreate:
        if (op.trackByOps !== null) {
          processLexicalScope(unit, op.trackByOps, savedView);
        }
        break;
    }
  }
  for (const op of ops) {
    if (op.kind === OpKind.Listener || op.kind === OpKind.TwoWayListener || op.kind === OpKind.Animation || op.kind === OpKind.AnimationListener) {
      continue;
    }
    transformExpressionsInOp(op, expr => {
      if (expr instanceof LexicalReadExpr) {
        if (localDefinitions.has(expr.name)) {
          return new ReadVariableExpr(localDefinitions.get(expr.name));
        } else if (scope.has(expr.name)) {
          return new ReadVariableExpr(scope.get(expr.name));
        } else {
          return new ReadPropExpr(new ContextExpr(unit.job.root.xref), expr.name);
        }
      } else if (expr instanceof RestoreViewExpr && typeof expr.view === 'number') {
        if (savedView === null || savedView.view !== expr.view) {
          throw new Error(`AssertionError: no saved view ${expr.view} from view ${unit.xref}`);
        }
        expr.view = new ReadVariableExpr(savedView.variable);
        return expr;
      } else {
        return expr;
      }
    }, VisitorContextFlag.None);
  }
  for (const op of ops) {
    visitExpressionsInOp(op, expr => {
      if (expr instanceof LexicalReadExpr) {
        throw new Error(`AssertionError: no lexical reads should remain, but found read of ${expr.name}`);
      }
    });
  }
}

const sanitizerFns = new Map([[SecurityContext.HTML, Identifiers.sanitizeHtml], [SecurityContext.RESOURCE_URL, Identifiers.sanitizeResourceUrl], [SecurityContext.SCRIPT, Identifiers.sanitizeScript], [SecurityContext.STYLE, Identifiers.sanitizeStyle], [SecurityContext.URL, Identifiers.sanitizeUrl], [SecurityContext.ATTRIBUTE_NO_BINDING, Identifiers.validateAttribute]]);
const trustedValueFns = new Map([[SecurityContext.HTML, Identifiers.trustConstantHtml], [SecurityContext.RESOURCE_URL, Identifiers.trustConstantResourceUrl]]);
function resolveSanitizers(job) {
  for (const unit of job.units) {
    if (job.kind !== CompilationJobKind.Host) {
      for (const op of unit.create) {
        if (op.kind === OpKind.ExtractedAttribute) {
          const trustedValueFn = trustedValueFns.get(getOnlySecurityContext(op.securityContext)) ?? null;
          op.trustedValueFn = trustedValueFn !== null ? importExpr(trustedValueFn) : null;
        }
      }
    }
    for (const op of unit.update) {
      switch (op.kind) {
        case OpKind.Property:
        case OpKind.Attribute:
        case OpKind.DomProperty:
        case OpKind.TwoWayProperty:
          let sanitizerFn = null;
          if (Array.isArray(op.securityContext) && hasCompositeUrlSecurityContext(op.securityContext)) {
            sanitizerFn = Identifiers.sanitizeUrlOrResourceUrl;
          } else {
            sanitizerFn = sanitizerFns.get(getOnlySecurityContext(op.securityContext)) ?? null;
          }
          op.sanitizer = sanitizerFn !== null ? importExpr(sanitizerFn) : null;
          break;
      }
    }
  }
}
function hasCompositeUrlSecurityContext(securityContext) {
  let hasUrlContext = false;
  let hasResourceUrlContext = false;
  let hasNoneContext = false;
  for (const context of securityContext) {
    switch (context) {
      case SecurityContext.URL:
        hasUrlContext = true;
        break;
      case SecurityContext.RESOURCE_URL:
        hasResourceUrlContext = true;
        break;
      case SecurityContext.NONE:
        hasNoneContext = true;
        break;
      default:
        return false;
    }
  }
  return (hasUrlContext || hasResourceUrlContext) && hasNoneContext || hasUrlContext && hasResourceUrlContext;
}
function getOnlySecurityContext(securityContext) {
  if (!Array.isArray(securityContext)) {
    return securityContext;
  }
  if (securityContext.length < 2) {
    return securityContext[0] ?? SecurityContext.NONE;
  }
  const nonNoneSecurityContexts = securityContext.filter(context => context !== SecurityContext.NONE);
  if (nonNoneSecurityContexts.length > 1) {
    throw Error(`AssertionError: Ambiguous security context`);
  }
  return nonNoneSecurityContexts[0] ?? SecurityContext.NONE;
}

function removeSafeNavigationMigration(job) {
  for (const unit of job.units) {
    for (const op of unit.ops()) {
      transformExpressionsInOp(op, e => convertSafeNavigationMigrationCall(e), VisitorContextFlag.None);
    }
  }
}
function convertSafeNavigationMigrationCall(e) {
  if (e instanceof InvokeFunctionExpr && e.fn instanceof LexicalReadExpr && e.fn.name === '$safeNavigationMigration') {
    if (e.args.length !== 1) {
      throw new Error('The $safeNavigationMigration builtin function expects exactly one argument.');
    }
    return new SafeNavigationMigrationExpr(e.args[0]);
  }
  return e;
}

function saveAndRestoreView(job) {
  for (const unit of job.units) {
    for (const expr of unit.functions) {
      if (needsRestoreView(job, unit, expr.ops)) {
        addSaveRestoreViewOperation(unit, expr.ops, variable(expr.currentViewName));
      }
    }
    unit.create.prepend([createVariableOp(unit.job.allocateXrefId(), {
      kind: SemanticVariableKind.SavedView,
      name: null,
      view: unit.xref
    }, new GetCurrentViewExpr(), VariableFlags.None)]);
    for (const op of unit.create) {
      if (op.kind === OpKind.Listener || op.kind === OpKind.TwoWayListener || op.kind === OpKind.Animation || op.kind === OpKind.AnimationListener) {
        if (needsRestoreView(job, unit, op.handlerOps)) {
          addSaveRestoreViewOperation(unit, op.handlerOps, unit.xref);
        }
      }
    }
  }
}
function needsRestoreView(job, unit, opList) {
  let result = unit !== job.root;
  if (!result) {
    for (const innerOp of opList) {
      visitExpressionsInOp(innerOp, expr => {
        if (expr instanceof ReferenceExpr || expr instanceof ContextLetReferenceExpr) {
          result = true;
        }
      });
    }
  }
  return result;
}
function addSaveRestoreViewOperation(unit, opList, restoreViewTarget) {
  opList.prepend([createVariableOp(unit.job.allocateXrefId(), {
    kind: SemanticVariableKind.Context,
    name: null,
    view: unit.xref
  }, new RestoreViewExpr(restoreViewTarget), VariableFlags.None)]);
  for (const handlerOp of opList) {
    if (handlerOp.kind === OpKind.Statement && handlerOp.statement instanceof ReturnStatement) {
      handlerOp.statement.value = new ResetViewExpr(handlerOp.statement.value);
    }
  }
}

function allocateSlots(job) {
  for (const unit of job.units) {
    let slotCount = 0;
    for (const op of unit.create) {
      if (!hasConsumesSlotTrait(op)) {
        continue;
      }
      op.handle.slot = slotCount;
      slotCount += op.numSlotsUsed;
    }
    unit.decls = slotCount;
  }
  for (const unit of job.units) {
    for (const op of unit.ops()) {
      if (op.kind === OpKind.Template || op.kind === OpKind.ConditionalCreate || op.kind === OpKind.ConditionalBranchCreate || op.kind === OpKind.RepeaterCreate) {
        const childView = job.views.get(op.xref);
        op.decls = childView.decls;
      }
    }
  }
}

function optimizeStoreLet(job) {
  const letUsedExternally = new Set();
  const declareLetOps = new Map();
  for (const unit of job.units) {
    for (const op of unit.ops()) {
      if (op.kind === OpKind.DeclareLet) {
        declareLetOps.set(op.xref, op);
      }
      visitExpressionsInOp(op, expr => {
        if (expr instanceof ContextLetReferenceExpr) {
          letUsedExternally.add(expr.target);
        }
      });
    }
  }
  for (const unit of job.units) {
    for (const op of unit.update) {
      transformExpressionsInOp(op, expr => {
        if (expr instanceof StoreLetExpr && !letUsedExternally.has(expr.target)) {
          if (!hasPipe(expr)) {
            OpList.remove(declareLetOps.get(expr.target));
          }
          return expr.value;
        }
        return expr;
      }, VisitorContextFlag.None);
    }
  }
}
function hasPipe(root) {
  let result = false;
  transformExpressionsInExpression(root, expr => {
    if (expr instanceof PipeBindingExpr || expr instanceof PipeBindingVariadicExpr) {
      result = true;
    }
    return expr;
  }, VisitorContextFlag.None);
  return result;
}

function stripNonrequiredParentheses(job) {
  const requiredParens = new Set();
  for (const unit of job.units) {
    for (const op of unit.ops()) {
      visitExpressionsInOp(op, expr => {
        if (expr instanceof BinaryOperatorExpr) {
          switch (expr.operator) {
            case BinaryOperator.Exponentiation:
              checkExponentiationParens(expr, requiredParens);
              break;
            case BinaryOperator.NullishCoalesce:
              checkNullishCoalescingParens(expr, requiredParens);
              break;
            case BinaryOperator.And:
            case BinaryOperator.Or:
              checkAndOrParens(expr, requiredParens);
          }
        }
      });
    }
  }
  for (const unit of job.units) {
    for (const op of unit.ops()) {
      transformExpressionsInOp(op, expr => {
        if (expr instanceof ParenthesizedExpr) {
          return requiredParens.has(expr) ? expr : expr.expr;
        }
        return expr;
      }, VisitorContextFlag.None);
    }
  }
}
function checkExponentiationParens(expr, requiredParens) {
  if (expr.lhs instanceof ParenthesizedExpr && expr.lhs.expr instanceof UnaryOperatorExpr) {
    requiredParens.add(expr.lhs);
  }
}
function checkNullishCoalescingParens(expr, requiredParens) {
  if (expr.lhs instanceof ParenthesizedExpr && (isLogicalAndOr(expr.lhs.expr) || expr.lhs.expr instanceof ConditionalExpr)) {
    requiredParens.add(expr.lhs);
  }
  if (expr.rhs instanceof ParenthesizedExpr && (isLogicalAndOr(expr.rhs.expr) || expr.rhs.expr instanceof ConditionalExpr)) {
    requiredParens.add(expr.rhs);
  }
}
function checkAndOrParens(expr, requiredParens) {
  if (expr.lhs instanceof ParenthesizedExpr && expr.lhs.expr instanceof BinaryOperatorExpr && expr.lhs.expr.operator === BinaryOperator.NullishCoalesce) {
    requiredParens.add(expr.lhs);
  }
}
function isLogicalAndOr(expr) {
  return expr instanceof BinaryOperatorExpr && (expr.operator === BinaryOperator.And || expr.operator === BinaryOperator.Or);
}

function specializeStyleBindings(job) {
  for (const unit of job.units) {
    for (const op of unit.update) {
      if (op.kind !== OpKind.Binding) {
        continue;
      }
      switch (op.bindingKind) {
        case BindingKind.ClassName:
          if (op.expression instanceof Interpolation) {
            throw new Error(`Unexpected interpolation in ClassName binding`);
          }
          OpList.replace(op, createClassPropOp(op.target, op.name, op.expression, op.sourceSpan));
          break;
        case BindingKind.StyleProperty:
          OpList.replace(op, createStylePropOp(op.target, op.name, op.expression, op.unit, op.sourceSpan));
          break;
        case BindingKind.Property:
        case BindingKind.Template:
          if (op.name === 'style') {
            OpList.replace(op, createStyleMapOp(op.target, op.expression, op.sourceSpan));
          } else if (op.name === 'class') {
            OpList.replace(op, createClassMapOp(op.target, op.expression, op.sourceSpan));
          }
          break;
      }
    }
  }
}

function generateTemporaryVariables(job) {
  for (const unit of job.units) {
    unit.create.prepend(generateTemporaries(unit.create));
    unit.update.prepend(generateTemporaries(unit.update));
    for (const expr of unit.functions) {
      expr.ops.prepend(generateTemporaries(expr.ops));
    }
  }
}
function generateTemporaries(ops) {
  let opCount = 0;
  let generatedStatements = [];
  for (const op of ops) {
    const finalReads = new Map();
    visitExpressionsInOp(op, (expr, flag) => {
      if (flag & VisitorContextFlag.InChildOperation) {
        return;
      }
      if (expr instanceof ReadTemporaryExpr) {
        finalReads.set(expr.xref, expr);
      }
    });
    let count = 0;
    const assigned = new Set();
    const defs = new Map();
    visitExpressionsInOp(op, (expr, flag) => {
      if (flag & VisitorContextFlag.InChildOperation) {
        return;
      }
      if (expr instanceof AssignTemporaryExpr) {
        if (!assigned.has(expr.xref)) {
          assigned.add(expr.xref);
          defs.set(expr.xref, `tmp_${opCount}_${count++}`);
        }
        assignName(defs, expr);
      } else if (expr instanceof ReadTemporaryExpr) {
        if (finalReads.get(expr.xref) === expr) {
          count--;
        }
        assignName(defs, expr);
      }
    });
    generatedStatements.push(...Array.from(new Set(defs.values())).map(name => createStatementOp(new DeclareVarStmt(name))));
    opCount++;
    if (op.kind === OpKind.Listener || op.kind === OpKind.Animation || op.kind === OpKind.AnimationListener || op.kind === OpKind.TwoWayListener) {
      op.handlerOps.prepend(generateTemporaries(op.handlerOps));
    } else if (op.kind === OpKind.RepeaterCreate && op.trackByOps !== null) {
      op.trackByOps.prepend(generateTemporaries(op.trackByOps));
    }
  }
  return generatedStatements;
}
function assignName(names, expr) {
  const name = names.get(expr.xref);
  if (name === undefined) {
    throw new Error(`Found xref with unassigned name: ${expr.xref}`);
  }
  expr.name = name;
}

function optimizeTrackFns(job) {
  for (const unit of job.units) {
    for (const op of unit.create) {
      if (op.kind !== OpKind.RepeaterCreate) {
        continue;
      }
      if (op.track instanceof ReadVarExpr && op.track.name === '$index') {
        op.trackByFn = importExpr(Identifiers.repeaterTrackByIndex);
      } else if (op.track instanceof ReadVarExpr && op.track.name === '$item') {
        op.trackByFn = importExpr(Identifiers.repeaterTrackByIdentity);
      } else if (isTrackByFunctionCall(job.root.xref, op.track)) {
        op.usesComponentInstance = true;
        if (op.track.receiver.receiver.view === unit.xref) {
          op.trackByFn = op.track.receiver;
        } else {
          op.trackByFn = importExpr(Identifiers.componentInstance).callFn([]).prop(op.track.receiver.name);
          op.track = op.trackByFn;
        }
      } else {
        op.track = transformExpressionsInExpression(op.track, expr => {
          if (expr instanceof PipeBindingExpr || expr instanceof PipeBindingVariadicExpr) {
            throw new Error(`Illegal State: Pipes are not allowed in this context`);
          } else if (expr instanceof ContextExpr) {
            op.usesComponentInstance = true;
            return new TrackContextExpr(expr.view);
          }
          return expr;
        }, VisitorContextFlag.None);
        const trackOpList = new OpList();
        trackOpList.push(createStatementOp(new ReturnStatement(op.track, op.track.sourceSpan, [tsIgnoreComment()])));
        op.trackByOps = trackOpList;
      }
    }
  }
}
function isTrackByFunctionCall(rootView, expr) {
  if (!(expr instanceof InvokeFunctionExpr) || expr.args.length === 0 || expr.args.length > 2) {
    return false;
  }
  if (!(expr.receiver instanceof ReadPropExpr && expr.receiver.receiver instanceof ContextExpr) || expr.receiver.receiver.view !== rootView) {
    return false;
  }
  const [arg0, arg1] = expr.args;
  if (!(arg0 instanceof ReadVarExpr) || arg0.name !== '$index') {
    return false;
  } else if (expr.args.length === 1) {
    return true;
  }
  if (!(arg1 instanceof ReadVarExpr) || arg1.name !== '$item') {
    return false;
  }
  return true;
}

function generateTrackVariables(job) {
  for (const unit of job.units) {
    for (const op of unit.create) {
      if (op.kind !== OpKind.RepeaterCreate) {
        continue;
      }
      op.track = transformExpressionsInExpression(op.track, expr => {
        if (expr instanceof LexicalReadExpr) {
          if (op.varNames.$index.has(expr.name)) {
            return variable('$index');
          } else if (expr.name === op.varNames.$implicit) {
            return variable('$item');
          }
        }
        return expr;
      }, VisitorContextFlag.None);
    }
  }
}

function transformTwoWayBindingSet(job) {
  for (const unit of job.units) {
    for (const op of unit.create) {
      if (op.kind === OpKind.TwoWayListener) {
        transformExpressionsInOp(op, expr => {
          if (!(expr instanceof TwoWayBindingSetExpr)) {
            return expr;
          }
          const {
            target,
            value
          } = expr;
          if (target instanceof ReadPropExpr || target instanceof ReadKeyExpr) {
            return twoWayBindingSet(target, value).or(target.set(value));
          }
          if (target instanceof ReadVariableExpr) {
            return twoWayBindingSet(target, value);
          }
          throw new Error(`Unsupported expression in two-way action binding.`);
        }, VisitorContextFlag.InChildOperation);
      }
    }
  }
}

function countVariables(job) {
  for (const unit of job.units) {
    let varCount = 0;
    for (const op of unit.ops()) {
      if (hasConsumesVarsTrait(op)) {
        varCount += varsUsedByOp(op);
      }
    }
    const firstPassCountExpressionVars = expr => {
      if (!isIrExpression(expr)) {
        return;
      }
      if (expr instanceof PureFunctionExpr) {
        return;
      }
      if (hasUsesVarOffsetTrait(expr)) {
        expr.varOffset = varCount;
      }
      if (hasConsumesVarsTrait(expr)) {
        varCount += varsUsedByIrExpression(expr);
      }
    };
    const secondPassCountExpressionVars = expr => {
      if (!isIrExpression(expr) || !(expr instanceof PureFunctionExpr)) {
        return;
      }
      if (hasUsesVarOffsetTrait(expr)) {
        expr.varOffset = varCount;
      }
      if (hasConsumesVarsTrait(expr)) {
        varCount += varsUsedByIrExpression(expr);
      }
    };
    for (const createOp of unit.create) {
      visitExpressionsInOp(createOp, firstPassCountExpressionVars);
    }
    for (const updateOp of unit.update) {
      visitExpressionsInOp(updateOp, firstPassCountExpressionVars);
    }
    for (const createOp of unit.create) {
      visitExpressionsInOp(createOp, secondPassCountExpressionVars);
    }
    for (const updateOp of unit.update) {
      visitExpressionsInOp(updateOp, secondPassCountExpressionVars);
    }
    unit.vars = varCount;
  }
  if (job instanceof ComponentCompilationJob) {
    for (const unit of job.units) {
      for (const op of unit.create) {
        if (op.kind !== OpKind.Template && op.kind !== OpKind.RepeaterCreate && op.kind !== OpKind.ConditionalCreate && op.kind !== OpKind.ConditionalBranchCreate) {
          continue;
        }
        const childView = job.views.get(op.xref);
        op.vars = childView.vars;
      }
    }
  }
}
function varsUsedByOp(op) {
  let slots;
  switch (op.kind) {
    case OpKind.Attribute:
      slots = 1;
      if (op.expression instanceof Interpolation && !isSingletonInterpolation(op.expression)) {
        slots += op.expression.expressions.length;
      }
      return slots;
    case OpKind.Property:
    case OpKind.DomProperty:
      slots = 1;
      if (op.expression instanceof Interpolation) {
        slots += op.expression.expressions.length;
      }
      return slots;
    case OpKind.Control:
      return 2;
    case OpKind.TwoWayProperty:
      return 1;
    case OpKind.StyleProp:
    case OpKind.ClassProp:
    case OpKind.StyleMap:
    case OpKind.ClassMap:
      slots = 2;
      if (op.expression instanceof Interpolation) {
        slots += op.expression.expressions.length;
      }
      return slots;
    case OpKind.InterpolateText:
      return op.interpolation.expressions.length;
    case OpKind.I18nExpression:
    case OpKind.Conditional:
    case OpKind.DeferWhen:
    case OpKind.StoreLet:
      return 1;
    case OpKind.RepeaterCreate:
      return op.emptyView ? 1 : 0;
    default:
      throw new Error(`Unhandled op: ${OpKind[op.kind]}`);
  }
}
function varsUsedByIrExpression(expr) {
  switch (expr.kind) {
    case ExpressionKind.PureFunctionExpr:
      return 1 + expr.args.length;
    case ExpressionKind.PipeBinding:
      return 1 + expr.args.length;
    case ExpressionKind.PipeBindingVariadic:
      return 1 + expr.numArgs;
    case ExpressionKind.StoreLet:
    case ExpressionKind.ArrowFunction:
      return 1;
    default:
      throw new Error(`AssertionError: unhandled ConsumesVarsTrait expression ${expr.constructor.name}`);
  }
}
function isSingletonInterpolation(expr) {
  if (expr.expressions.length !== 1 || expr.strings.length !== 2) {
    return false;
  }
  if (expr.strings[0] !== '' || expr.strings[1] !== '') {
    return false;
  }
  return true;
}

function optimizeVariables(job) {
  for (const unit of job.units) {
    for (const expr of unit.functions) {
      inlineAlwaysInlineVariables(expr.ops);
    }
    inlineAlwaysInlineVariables(unit.create);
    inlineAlwaysInlineVariables(unit.update);
    for (const op of unit.create) {
      if (op.kind === OpKind.Listener || op.kind === OpKind.Animation || op.kind === OpKind.AnimationListener || op.kind === OpKind.TwoWayListener) {
        inlineAlwaysInlineVariables(op.handlerOps);
      } else if (op.kind === OpKind.RepeaterCreate && op.trackByOps !== null) {
        inlineAlwaysInlineVariables(op.trackByOps);
      }
    }
    for (const expr of unit.functions) {
      optimizeVariablesInOpList(expr.ops, null);
      optimizeSaveRestoreView(expr.ops);
    }
    for (const op of unit.create) {
      if (op.kind === OpKind.Listener || op.kind === OpKind.Animation || op.kind === OpKind.AnimationListener || op.kind === OpKind.TwoWayListener) {
        optimizeVariablesInOpList(op.handlerOps, skipArrowFunctionOps);
        optimizeSaveRestoreView(op.handlerOps);
      } else if (op.kind === OpKind.RepeaterCreate && op.trackByOps !== null) {
        optimizeVariablesInOpList(op.trackByOps, skipArrowFunctionOps);
      }
    }
    optimizeVariablesInOpList(unit.create, skipArrowFunctionOps);
    optimizeVariablesInOpList(unit.update, skipArrowFunctionOps);
  }
}
var Fence;
(function (Fence) {
  Fence[Fence["None"] = 0] = "None";
  Fence[Fence["ViewContextRead"] = 1] = "ViewContextRead";
  Fence[Fence["ViewContextWrite"] = 2] = "ViewContextWrite";
  Fence[Fence["SideEffectful"] = 4] = "SideEffectful";
})(Fence || (Fence = {}));
function skipArrowFunctionOps(flags) {
  return !(flags & VisitorContextFlag.InArrowFunctionOperation);
}
function inlineAlwaysInlineVariables(ops) {
  const vars = new Map();
  for (const op of ops) {
    if (op.kind === OpKind.Variable && op.flags & VariableFlags.AlwaysInline) {
      visitExpressionsInOp(op, expr => {
        if (isIrExpression(expr) && fencesForIrExpression(expr) !== Fence.None) {
          throw new Error(`AssertionError: A context-sensitive variable was marked AlwaysInline`);
        }
      });
      vars.set(op.xref, op);
    }
    transformExpressionsInOp(op, expr => {
      if (expr instanceof ReadVariableExpr && vars.has(expr.xref)) {
        const varOp = vars.get(expr.xref);
        return varOp.initializer.clone();
      }
      return expr;
    }, VisitorContextFlag.None);
  }
  for (const op of vars.values()) {
    OpList.remove(op);
  }
}
function optimizeVariablesInOpList(ops, predicate) {
  const varDecls = new Map();
  const varUsages = new Map();
  const varRemoteUsages = new Set();
  const opMap = new Map();
  for (const op of ops) {
    if (op.kind === OpKind.Variable) {
      if (varDecls.has(op.xref) || varUsages.has(op.xref)) {
        throw new Error(`Should not see two declarations of the same variable: ${op.xref}`);
      }
      varDecls.set(op.xref, op);
      varUsages.set(op.xref, 0);
    }
    opMap.set(op, collectOpInfo(op, predicate));
    countVariableUsages(op, varUsages, varRemoteUsages, predicate);
  }
  let contextIsUsed = false;
  for (const op of ops.reversed()) {
    const opInfo = opMap.get(op);
    if (op.kind === OpKind.Variable && varUsages.get(op.xref) === 0) {
      if (contextIsUsed && opInfo.fences & Fence.ViewContextWrite || opInfo.fences & Fence.SideEffectful) {
        const stmtOp = createStatementOp(op.initializer.toStmt());
        opMap.set(stmtOp, opInfo);
        OpList.replace(op, stmtOp);
      } else {
        uncountVariableUsages(op, varUsages);
        OpList.remove(op);
      }
      opMap.delete(op);
      varDecls.delete(op.xref);
      varUsages.delete(op.xref);
      continue;
    }
    if (opInfo.fences & Fence.ViewContextRead) {
      contextIsUsed = true;
    }
  }
  const toInline = [];
  for (const [id, count] of varUsages) {
    const decl = varDecls.get(id);
    const isAlwaysInline = !!(decl.flags & VariableFlags.AlwaysInline);
    if (count !== 1 || isAlwaysInline) {
      continue;
    }
    if (varRemoteUsages.has(id)) {
      continue;
    }
    toInline.push(id);
  }
  let candidate;
  while (candidate = toInline.pop()) {
    const decl = varDecls.get(candidate);
    const varInfo = opMap.get(decl);
    const isAlwaysInline = !!(decl.flags & VariableFlags.AlwaysInline);
    if (isAlwaysInline) {
      throw new Error(`AssertionError: Found an 'AlwaysInline' variable after the always inlining pass.`);
    }
    for (let targetOp = decl.next; targetOp.kind !== OpKind.ListEnd; targetOp = targetOp.next) {
      const opInfo = opMap.get(targetOp);
      if (opInfo.variablesUsed.has(candidate)) {
        if (!allowConservativeInlining(decl, targetOp)) {
          break;
        }
        if (tryInlineVariableInitializer(candidate, decl.initializer, targetOp, varInfo.fences)) {
          opInfo.variablesUsed.delete(candidate);
          for (const id of varInfo.variablesUsed) {
            opInfo.variablesUsed.add(id);
          }
          opInfo.fences |= varInfo.fences;
          varDecls.delete(candidate);
          varUsages.delete(candidate);
          opMap.delete(decl);
          OpList.remove(decl);
        }
        break;
      }
      if (!safeToInlinePastFences(opInfo.fences, varInfo.fences)) {
        break;
      }
    }
  }
}
function fencesForIrExpression(expr) {
  switch (expr.kind) {
    case ExpressionKind.NextContext:
      return Fence.ViewContextRead | Fence.ViewContextWrite;
    case ExpressionKind.RestoreView:
      return Fence.ViewContextRead | Fence.ViewContextWrite | Fence.SideEffectful;
    case ExpressionKind.StoreLet:
      return Fence.SideEffectful;
    case ExpressionKind.Reference:
    case ExpressionKind.ContextLetReference:
      return Fence.ViewContextRead;
    default:
      return Fence.None;
  }
}
function collectOpInfo(op, predicate) {
  let fences = Fence.None;
  const variablesUsed = new Set();
  visitExpressionsInOp(op, (expr, flags) => {
    if (!isIrExpression(expr) || predicate !== null && !predicate(flags)) {
      return;
    }
    if (expr.kind === ExpressionKind.ReadVariable) {
      variablesUsed.add(expr.xref);
    } else if (!(flags & VisitorContextFlag.InChildOperation)) {
      fences |= fencesForIrExpression(expr);
    }
  });
  return {
    fences,
    variablesUsed
  };
}
function countVariableUsages(op, varUsages, varRemoteUsage, predicate) {
  visitExpressionsInOp(op, (expr, flags) => {
    if (!isIrExpression(expr) || predicate !== null && !predicate(flags)) {
      return;
    }
    if (expr.kind !== ExpressionKind.ReadVariable) {
      return;
    }
    const count = varUsages.get(expr.xref);
    if (count === undefined) {
      return;
    }
    varUsages.set(expr.xref, count + 1);
    if (flags & VisitorContextFlag.InChildOperation) {
      varRemoteUsage.add(expr.xref);
    }
  });
}
function uncountVariableUsages(op, varUsages) {
  visitExpressionsInOp(op, expr => {
    if (!isIrExpression(expr)) {
      return;
    }
    if (expr.kind !== ExpressionKind.ReadVariable) {
      return;
    }
    const count = varUsages.get(expr.xref);
    if (count === undefined) {
      return;
    } else if (count === 0) {
      throw new Error(`Inaccurate variable count: ${expr.xref} - found another read but count is already 0`);
    }
    varUsages.set(expr.xref, count - 1);
  });
}
function safeToInlinePastFences(fences, declFences) {
  if (fences & Fence.ViewContextWrite) {
    if (declFences & Fence.ViewContextRead) {
      return false;
    }
  } else if (fences & Fence.ViewContextRead) {
    if (declFences & Fence.ViewContextWrite) {
      return false;
    }
  }
  return true;
}
function tryInlineVariableInitializer(id, initializer, target, declFences) {
  let inlined = false;
  let inliningAllowed = true;
  transformExpressionsInOp(target, (expr, flags) => {
    if (!isIrExpression(expr)) {
      return expr;
    }
    if (inlined || !inliningAllowed) {
      return expr;
    } else if (flags & VisitorContextFlag.InChildOperation && declFences & Fence.ViewContextRead) {
      return expr;
    }
    switch (expr.kind) {
      case ExpressionKind.ReadVariable:
        if (expr.xref === id) {
          inlined = true;
          return initializer;
        }
        break;
      default:
        const exprFences = fencesForIrExpression(expr);
        inliningAllowed = inliningAllowed && safeToInlinePastFences(exprFences, declFences);
        break;
    }
    return expr;
  }, VisitorContextFlag.None);
  return inlined;
}
function allowConservativeInlining(decl, target) {
  switch (decl.variable.kind) {
    case SemanticVariableKind.Identifier:
      if (decl.initializer instanceof ReadVarExpr && decl.initializer.name === CONTEXT_NAME) {
        return true;
      }
      return false;
    case SemanticVariableKind.Context:
      return target.kind === OpKind.Variable;
    default:
      return true;
  }
}
function optimizeSaveRestoreView(ops) {
  const head = ops.head.next;
  const tail = ops.tail.prev;
  if (head !== null && tail !== null && head.next === tail && head.kind === OpKind.Statement && head.statement instanceof ExpressionStatement && head.statement.expr instanceof RestoreViewExpr && tail.kind === OpKind.Statement && tail.statement instanceof ReturnStatement && tail.statement.value instanceof ResetViewExpr) {
    OpList.remove(head);
    tail.statement.value = tail.statement.value.expr;
  }
}

function wrapI18nIcus(job) {
  for (const unit of job.units) {
    let currentI18nOp = null;
    let addedI18nId = null;
    for (const op of unit.create) {
      switch (op.kind) {
        case OpKind.I18nStart:
          currentI18nOp = op;
          break;
        case OpKind.I18nEnd:
          currentI18nOp = null;
          break;
        case OpKind.IcuStart:
          if (currentI18nOp === null) {
            addedI18nId = job.allocateXrefId();
            OpList.insertBefore(createI18nStartOp(addedI18nId, op.message, undefined, null), op);
          }
          break;
        case OpKind.IcuEnd:
          if (addedI18nId !== null) {
            OpList.insertAfter(createI18nEndOp(addedI18nId, null), op);
            addedI18nId = null;
          }
          break;
      }
    }
  }
}

/**
 *
 * @license
 * Copyright Google LLC All Rights Reserved.
 *
 * Use of this source code is governed by an MIT-style license that can be
 * found in the LICENSE file at https://angular.dev/license
 */
const phases = [{
  kind: CompilationJobKind.Tmpl,
  fn: resolveForeignContent
}, {
  kind: CompilationJobKind.Tmpl,
  fn: removeContentSelectors
}, {
  kind: CompilationJobKind.Both,
  fn: optimizeRegularExpressions
}, {
  kind: CompilationJobKind.Host,
  fn: parseHostStyleProperties
}, {
  kind: CompilationJobKind.Tmpl,
  fn: emitNamespaceChanges
}, {
  kind: CompilationJobKind.Tmpl,
  fn: propagateI18nBlocks
}, {
  kind: CompilationJobKind.Tmpl,
  fn: wrapI18nIcus
}, {
  kind: CompilationJobKind.Both,
  fn: deduplicateTextBindings
}, {
  kind: CompilationJobKind.Both,
  fn: specializeStyleBindings
}, {
  kind: CompilationJobKind.Both,
  fn: specializeBindings
}, {
  kind: CompilationJobKind.Tmpl,
  fn: specializeControlProperties
}, {
  kind: CompilationJobKind.Both,
  fn: convertAnimations
}, {
  kind: CompilationJobKind.Both,
  fn: extractAttributes
}, {
  kind: CompilationJobKind.Tmpl,
  fn: createI18nContexts
}, {
  kind: CompilationJobKind.Both,
  fn: parseExtractedStyles
}, {
  kind: CompilationJobKind.Tmpl,
  fn: removeEmptyBindings
}, {
  kind: CompilationJobKind.Both,
  fn: collapseSingletonInterpolations
}, {
  kind: CompilationJobKind.Both,
  fn: orderOps
}, {
  kind: CompilationJobKind.Tmpl,
  fn: generateConditionalExpressions
}, {
  kind: CompilationJobKind.Tmpl,
  fn: createPipes
}, {
  kind: CompilationJobKind.Tmpl,
  fn: configureDeferInstructions
}, {
  kind: CompilationJobKind.Tmpl,
  fn: insertIncrementalHydrationRuntime
}, {
  kind: CompilationJobKind.Tmpl,
  fn: createVariadicPipes
}, {
  kind: CompilationJobKind.Both,
  fn: generateArrowFunctions
}, {
  kind: CompilationJobKind.Both,
  fn: generatePureLiteralStructures
}, {
  kind: CompilationJobKind.Tmpl,
  fn: generateProjectionDefs
}, {
  kind: CompilationJobKind.Tmpl,
  fn: generateLocalLetReferences
}, {
  kind: CompilationJobKind.Tmpl,
  fn: generateVariables
}, {
  kind: CompilationJobKind.Tmpl,
  fn: saveAndRestoreView
}, {
  kind: CompilationJobKind.Both,
  fn: deleteAnyCasts
}, {
  kind: CompilationJobKind.Both,
  fn: removeSafeNavigationMigration
}, {
  kind: CompilationJobKind.Both,
  fn: resolveDollarEvent
}, {
  kind: CompilationJobKind.Tmpl,
  fn: generateTrackVariables
}, {
  kind: CompilationJobKind.Tmpl,
  fn: removeIllegalLetReferences
}, {
  kind: CompilationJobKind.Both,
  fn: resolveNames
}, {
  kind: CompilationJobKind.Tmpl,
  fn: resolveDeferTargetNames
}, {
  kind: CompilationJobKind.Tmpl,
  fn: transformTwoWayBindingSet
}, {
  kind: CompilationJobKind.Tmpl,
  fn: optimizeTrackFns
}, {
  kind: CompilationJobKind.Both,
  fn: resolveContexts
}, {
  kind: CompilationJobKind.Both,
  fn: resolveSanitizers
}, {
  kind: CompilationJobKind.Tmpl,
  fn: liftLocalRefs
}, {
  kind: CompilationJobKind.Both,
  fn: expandSafeReads
}, {
  kind: CompilationJobKind.Both,
  fn: stripNonrequiredParentheses
}, {
  kind: CompilationJobKind.Both,
  fn: generateTemporaryVariables
}, {
  kind: CompilationJobKind.Both,
  fn: optimizeVariables
}, {
  kind: CompilationJobKind.Both,
  fn: optimizeStoreLet
}, {
  kind: CompilationJobKind.Tmpl,
  fn: convertI18nText
}, {
  kind: CompilationJobKind.Tmpl,
  fn: convertI18nBindings
}, {
  kind: CompilationJobKind.Tmpl,
  fn: removeUnusedI18nAttributesOps
}, {
  kind: CompilationJobKind.Tmpl,
  fn: assignI18nSlotDependencies
}, {
  kind: CompilationJobKind.Tmpl,
  fn: applyI18nExpressions
}, {
  kind: CompilationJobKind.Tmpl,
  fn: allocateSlots
}, {
  kind: CompilationJobKind.Tmpl,
  fn: resolveI18nElementPlaceholders
}, {
  kind: CompilationJobKind.Tmpl,
  fn: resolveI18nExpressionPlaceholders
}, {
  kind: CompilationJobKind.Tmpl,
  fn: extractI18nMessages
}, {
  kind: CompilationJobKind.Tmpl,
  fn: collectI18nConsts
}, {
  kind: CompilationJobKind.Tmpl,
  fn: resolveI18nAttrSanitizers
}, {
  kind: CompilationJobKind.Tmpl,
  fn: collectConstExpressions
}, {
  kind: CompilationJobKind.Both,
  fn: collectElementConsts
}, {
  kind: CompilationJobKind.Tmpl,
  fn: removeI18nContexts
}, {
  kind: CompilationJobKind.Both,
  fn: countVariables
}, {
  kind: CompilationJobKind.Tmpl,
  fn: generateAdvance
}, {
  kind: CompilationJobKind.Both,
  fn: nameFunctionsAndVariables
}, {
  kind: CompilationJobKind.Tmpl,
  fn: resolveDeferDepsFns
}, {
  kind: CompilationJobKind.Tmpl,
  fn: mergeNextContextExpressions
}, {
  kind: CompilationJobKind.Tmpl,
  fn: generateNgContainerOps
}, {
  kind: CompilationJobKind.Tmpl,
  fn: collapseEmptyInstructions
}, {
  kind: CompilationJobKind.Tmpl,
  fn: attachSourceLocations
}, {
  kind: CompilationJobKind.Tmpl,
  fn: disableBindings$1
}, {
  kind: CompilationJobKind.Both,
  fn: extractPureFunctions
}, {
  kind: CompilationJobKind.Both,
  fn: reify
}, {
  kind: CompilationJobKind.Both,
  fn: chain
}];
function transform(job, kind) {
  for (const phase of phases) {
    if (phase.kind === kind || phase.kind === CompilationJobKind.Both) {
      phase.fn(job);
    }
  }
}
function emitTemplateFn(tpl, pool) {
  const rootFn = emitView(tpl.root);
  emitChildViews(tpl.root, pool);
  return rootFn;
}
function emitChildViews(parent, pool) {
  for (const unit of parent.job.units) {
    if (unit.parent !== parent.xref) {
      continue;
    }
    emitChildViews(unit, pool);
    const viewFn = emitView(unit);
    pool.statements.push(viewFn.toDeclStmt(viewFn.name));
  }
}
function emitView(view) {
  if (view.fnName === null) {
    throw new Error(`AssertionError: view ${view.xref} is unnamed`);
  }
  const createStatements = [];
  for (const op of view.create) {
    if (op.kind !== OpKind.Statement) {
      throw new Error(`AssertionError: expected all create ops to have been compiled, but got ${OpKind[op.kind]}`);
    }
    createStatements.push(op.statement);
  }
  const updateStatements = [];
  for (const op of view.update) {
    if (op.kind !== OpKind.Statement) {
      throw new Error(`AssertionError: expected all update ops to have been compiled, but got ${OpKind[op.kind]}`);
    }
    updateStatements.push(op.statement);
  }
  const createCond = maybeGenerateRfBlock(1, createStatements);
  const updateCond = maybeGenerateRfBlock(2, updateStatements);
  return fn([new FnParam(RENDER_FLAGS, NUMBER_TYPE), new FnParam(CONTEXT_NAME, DYNAMIC_TYPE)], [...createCond, ...updateCond], undefined, undefined, view.fnName);
}
function maybeGenerateRfBlock(flag, statements) {
  if (statements.length === 0) {
    return [];
  }
  return [ifStmt(new BinaryOperatorExpr(BinaryOperator.BitwiseAnd, variable(RENDER_FLAGS), literal(flag)), statements)];
}
function emitHostBindingFunction(job) {
  if (job.root.fnName === null) {
    throw new Error(`AssertionError: host binding function is unnamed`);
  }
  const createStatements = [];
  for (const op of job.root.create) {
    if (op.kind !== OpKind.Statement) {
      throw new Error(`AssertionError: expected all create ops to have been compiled, but got ${OpKind[op.kind]}`);
    }
    createStatements.push(op.statement);
  }
  const updateStatements = [];
  for (const op of job.root.update) {
    if (op.kind !== OpKind.Statement) {
      throw new Error(`AssertionError: expected all update ops to have been compiled, but got ${OpKind[op.kind]}`);
    }
    updateStatements.push(op.statement);
  }
  if (createStatements.length === 0 && updateStatements.length === 0) {
    return null;
  }
  const createCond = maybeGenerateRfBlock(1, createStatements);
  const updateCond = maybeGenerateRfBlock(2, updateStatements);
  return fn([new FnParam(RENDER_FLAGS, NUMBER_TYPE), new FnParam(CONTEXT_NAME, DYNAMIC_TYPE)], [...createCond, ...updateCond], undefined, undefined, job.root.fnName);
}

const PROPERTY_PARTS_SEPARATOR = '.';
const ATTRIBUTE_PREFIX = 'attr';
const ANIMATE_PREFIX$1 = 'animate';
const CLASS_PREFIX = 'class';
const STYLE_PREFIX = 'style';
const TEMPLATE_ATTR_PREFIX$1 = '*';
const LEGACY_ANIMATE_PROP_PREFIX = 'animate-';
class BindingParser {
  _exprParser;
  _schemaRegistry;
  errors;
  constructor(_exprParser, _schemaRegistry, errors) {
    this._exprParser = _exprParser;
    this._schemaRegistry = _schemaRegistry;
    this.errors = errors;
  }
  createBoundHostProperties(properties, sourceSpan) {
    const boundProps = [];
    for (const propName of Object.keys(properties)) {
      const expression = properties[propName];
      if (typeof expression === 'string') {
        this.parsePropertyBinding(propName, expression, true, false, sourceSpan, sourceSpan.start.offset, undefined, [], boundProps, sourceSpan);
      } else {
        this._reportError(`Value of the host property binding "${propName}" needs to be a string representing an expression but got "${expression}" (${typeof expression})`, sourceSpan);
      }
    }
    return boundProps;
  }
  createDirectiveHostEventAsts(hostListeners, sourceSpan) {
    const targetEvents = [];
    for (const propName of Object.keys(hostListeners)) {
      const expression = hostListeners[propName];
      if (typeof expression === 'string') {
        this.parseEvent(propName, expression, false, sourceSpan, sourceSpan, [], targetEvents, sourceSpan);
      } else {
        this._reportError(`Value of the host listener "${propName}" needs to be a string representing an expression but got "${expression}" (${typeof expression})`, sourceSpan);
      }
    }
    return targetEvents;
  }
  parseInterpolation(value, sourceSpan, interpolatedTokens) {
    const absoluteOffset = sourceSpan.fullStart.offset;
    try {
      const ast = this._exprParser.parseInterpolation(value, sourceSpan, absoluteOffset, interpolatedTokens);
      if (ast) {
        this.errors.push(...ast.errors);
      }
      return ast;
    } catch (e) {
      this._reportError(`${e}`, sourceSpan);
      return this._exprParser.wrapLiteralPrimitive('ERROR', sourceSpan, absoluteOffset);
    }
  }
  parseInterpolationExpression(expression, sourceSpan) {
    const absoluteOffset = sourceSpan.start.offset;
    try {
      const ast = this._exprParser.parseInterpolationExpression(expression, sourceSpan, absoluteOffset);
      if (ast) {
        this.errors.push(...ast.errors);
      }
      return ast;
    } catch (e) {
      this._reportError(`${e}`, sourceSpan);
      return this._exprParser.wrapLiteralPrimitive('ERROR', sourceSpan, absoluteOffset);
    }
  }
  parseInlineTemplateBinding(tplKey, tplValue, sourceSpan, absoluteValueOffset, targetMatchableAttrs, targetProps, targetVars, isIvyAst) {
    const absoluteKeyOffset = sourceSpan.start.offset + TEMPLATE_ATTR_PREFIX$1.length;
    const bindings = this._parseTemplateBindings(tplKey, tplValue, sourceSpan, absoluteKeyOffset, absoluteValueOffset);
    for (const binding of bindings) {
      const bindingSpan = moveParseSourceSpan(sourceSpan, binding.sourceSpan);
      const key = binding.key.source;
      const keySpan = moveParseSourceSpan(sourceSpan, binding.key.span);
      if (binding instanceof VariableBinding) {
        const value = binding.value ? binding.value.source : '$implicit';
        const valueSpan = binding.value ? moveParseSourceSpan(sourceSpan, binding.value.span) : undefined;
        targetVars.push(new ParsedVariable(key, value, bindingSpan, keySpan, valueSpan));
      } else if (binding.value) {
        const srcSpan = isIvyAst ? bindingSpan : sourceSpan;
        const valueSpan = moveParseSourceSpan(sourceSpan, binding.value.ast.sourceSpan);
        this._parsePropertyAst(key, binding.value, false, srcSpan, keySpan, valueSpan, targetMatchableAttrs, targetProps);
      } else {
        targetMatchableAttrs.push([key, '']);
        this.parseLiteralAttr(key, null, keySpan, absoluteValueOffset, undefined, targetMatchableAttrs, targetProps, keySpan);
      }
    }
  }
  _parseTemplateBindings(tplKey, tplValue, sourceSpan, absoluteKeyOffset, absoluteValueOffset) {
    try {
      const bindingsResult = this._exprParser.parseTemplateBindings(tplKey, tplValue, sourceSpan, absoluteKeyOffset, absoluteValueOffset);
      bindingsResult.errors.forEach(e => this.errors.push(e));
      bindingsResult.warnings.forEach(warning => {
        this._reportError(warning, sourceSpan, ParseErrorLevel.WARNING);
      });
      return bindingsResult.templateBindings;
    } catch (e) {
      this._reportError(`${e}`, sourceSpan);
      return [];
    }
  }
  parseLiteralAttr(name, value, sourceSpan, absoluteOffset, valueSpan, targetMatchableAttrs, targetProps, keySpan) {
    if (isLegacyAnimationLabel(name)) {
      name = name.substring(1);
      if (keySpan !== undefined) {
        keySpan = moveParseSourceSpan(keySpan, new AbsoluteSourceSpan(keySpan.start.offset + 1, keySpan.end.offset));
      }
      if (value) {
        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);
      }
      this._parseLegacyAnimation(name, value, sourceSpan, absoluteOffset, keySpan, valueSpan, targetMatchableAttrs, targetProps);
    } else {
      targetProps.push(new ParsedProperty(name, this._exprParser.wrapLiteralPrimitive(value, '', absoluteOffset), ParsedPropertyType.LITERAL_ATTR, sourceSpan, keySpan, valueSpan));
    }
  }
  parsePropertyBinding(name, expression, isHost, isPartOfAssignmentBinding, sourceSpan, absoluteOffset, valueSpan, targetMatchableAttrs, targetProps, keySpan) {
    if (name.length === 0) {
      this._reportError(`Property name is missing in binding`, sourceSpan);
    }
    let isLegacyAnimationProp = false;
    if (name.startsWith(LEGACY_ANIMATE_PROP_PREFIX)) {
      isLegacyAnimationProp = true;
      name = name.substring(LEGACY_ANIMATE_PROP_PREFIX.length);
      if (keySpan !== undefined) {
        keySpan = moveParseSourceSpan(keySpan, new AbsoluteSourceSpan(keySpan.start.offset + LEGACY_ANIMATE_PROP_PREFIX.length, keySpan.end.offset));
      }
    } else if (isLegacyAnimationLabel(name)) {
      isLegacyAnimationProp = true;
      name = name.substring(1);
      if (keySpan !== undefined) {
        keySpan = moveParseSourceSpan(keySpan, new AbsoluteSourceSpan(keySpan.start.offset + 1, keySpan.end.offset));
      }
    }
    if (isLegacyAnimationProp) {
      this._parseLegacyAnimation(name, expression, sourceSpan, absoluteOffset, keySpan, valueSpan, targetMatchableAttrs, targetProps);
    } else if (name.startsWith(`${ANIMATE_PREFIX$1}${PROPERTY_PARTS_SEPARATOR}`)) {
      this._parseAnimation(name, this.parseBinding(expression, isHost, valueSpan || sourceSpan, absoluteOffset), sourceSpan, keySpan, valueSpan, targetMatchableAttrs, targetProps);
    } else {
      this._parsePropertyAst(name, this.parseBinding(expression, isHost, valueSpan || sourceSpan, absoluteOffset), isPartOfAssignmentBinding, sourceSpan, keySpan, valueSpan, targetMatchableAttrs, targetProps);
    }
  }
  parsePropertyInterpolation(name, value, sourceSpan, valueSpan, targetMatchableAttrs, targetProps, keySpan, interpolatedTokens) {
    const expr = this.parseInterpolation(value, valueSpan || sourceSpan, interpolatedTokens);
    if (expr) {
      this._parsePropertyAst(name, expr, false, sourceSpan, keySpan, valueSpan, targetMatchableAttrs, targetProps);
      return true;
    }
    return false;
  }
  _parsePropertyAst(name, ast, isPartOfAssignmentBinding, sourceSpan, keySpan, valueSpan, targetMatchableAttrs, targetProps) {
    targetMatchableAttrs.push([name, ast.source]);
    targetProps.push(new ParsedProperty(name, ast, isPartOfAssignmentBinding ? ParsedPropertyType.TWO_WAY : ParsedPropertyType.DEFAULT, sourceSpan, keySpan, valueSpan));
  }
  _parseAnimation(name, ast, sourceSpan, keySpan, valueSpan, targetMatchableAttrs, targetProps) {
    targetMatchableAttrs.push([name, ast.source]);
    targetProps.push(new ParsedProperty(name, ast, ParsedPropertyType.ANIMATION, sourceSpan, keySpan, valueSpan));
  }
  _parseLegacyAnimation(name, expression, sourceSpan, absoluteOffset, keySpan, valueSpan, targetMatchableAttrs, targetProps) {
    if (name.length === 0) {
      this._reportError('Animation trigger is missing', sourceSpan);
    }
    const ast = this.parseBinding(expression || 'undefined', false, valueSpan || sourceSpan, absoluteOffset);
    targetMatchableAttrs.push([name, ast.source]);
    targetProps.push(new ParsedProperty(name, ast, ParsedPropertyType.LEGACY_ANIMATION, sourceSpan, keySpan, valueSpan));
  }
  parseBinding(value, isHostBinding, sourceSpan, absoluteOffset) {
    try {
      const ast = isHostBinding ? this._exprParser.parseSimpleBinding(value, sourceSpan, absoluteOffset) : this._exprParser.parseBinding(value, sourceSpan, absoluteOffset);
      if (ast) {
        this.errors.push(...ast.errors);
      }
      return ast;
    } catch (e) {
      this._reportError(`${e}`, sourceSpan);
      return this._exprParser.wrapLiteralPrimitive('ERROR', sourceSpan, absoluteOffset);
    }
  }
  createBoundElementProperty(elementSelector, boundProp, skipValidation = false, mapPropertyName = true) {
    if (boundProp.isLegacyAnimation) {
      return new BoundElementProperty(boundProp.name, BindingType.LegacyAnimation, SecurityContext.NONE, boundProp.expression, null, boundProp.sourceSpan, boundProp.keySpan, boundProp.valueSpan);
    }
    let unit = null;
    let bindingType = undefined;
    let boundPropertyName = null;
    const parts = boundProp.name.split(PROPERTY_PARTS_SEPARATOR);
    let securityContexts = undefined;
    if (parts.length > 1) {
      if (parts[0] == ATTRIBUTE_PREFIX) {
        boundPropertyName = parts.slice(1).join(PROPERTY_PARTS_SEPARATOR);
        if (!skipValidation) {
          this._validatePropertyOrAttributeName(boundPropertyName, boundProp.sourceSpan, true);
        }
        securityContexts = calcPossibleSecurityContexts(this._schemaRegistry, elementSelector, boundPropertyName, true);
        const nsSeparatorIdx = boundPropertyName.indexOf(':');
        if (nsSeparatorIdx > -1) {
          const ns = boundPropertyName.substring(0, nsSeparatorIdx);
          const name = boundPropertyName.substring(nsSeparatorIdx + 1);
          boundPropertyName = mergeNsAndName(ns, name);
        }
        bindingType = BindingType.Attribute;
      } else if (parts[0] == CLASS_PREFIX) {
        boundPropertyName = parts[1];
        bindingType = BindingType.Class;
        securityContexts = [SecurityContext.NONE];
      } else if (parts[0] == STYLE_PREFIX) {
        unit = parts.length > 2 ? parts[2] : null;
        const boundName = parts[1];
        if (!boundName.startsWith('--')) {
          boundPropertyName = boundName;
        } else {
          try {
            boundPropertyName = namespaceCssVariable(boundName);
          } catch (e) {
            this._reportError(e.message, boundProp.sourceSpan);
          }
        }
        bindingType = BindingType.Style;
        securityContexts = [SecurityContext.STYLE];
      } else if (parts[0] == ANIMATE_PREFIX$1) {
        boundPropertyName = boundProp.name;
        bindingType = BindingType.Animation;
        securityContexts = [SecurityContext.NONE];
      }
    }
    if (boundPropertyName === null) {
      const mappedPropName = this._schemaRegistry.getMappedPropName(boundProp.name);
      boundPropertyName = mapPropertyName ? mappedPropName : boundProp.name;
      securityContexts = calcPossibleSecurityContexts(this._schemaRegistry, elementSelector, mappedPropName, false);
      bindingType = boundProp.type === ParsedPropertyType.TWO_WAY ? BindingType.TwoWay : BindingType.Property;
      if (!skipValidation) {
        this._validatePropertyOrAttributeName(mappedPropName, boundProp.sourceSpan, false);
      }
    }
    return new BoundElementProperty(boundPropertyName, bindingType, securityContexts[0], boundProp.expression, unit, boundProp.sourceSpan, boundProp.keySpan, boundProp.valueSpan);
  }
  parseEvent(name, expression, isAssignmentEvent, sourceSpan, handlerSpan, targetMatchableAttrs, targetEvents, keySpan) {
    if (name.length === 0) {
      this._reportError(`Event name is missing in binding`, sourceSpan);
    }
    if (isLegacyAnimationLabel(name)) {
      name = name.slice(1);
      if (keySpan !== undefined) {
        keySpan = moveParseSourceSpan(keySpan, new AbsoluteSourceSpan(keySpan.start.offset + 1, keySpan.end.offset));
      }
      this._parseLegacyAnimationEvent(name, expression, sourceSpan, handlerSpan, targetEvents, keySpan);
    } else {
      this._parseRegularEvent(name, expression, isAssignmentEvent, sourceSpan, handlerSpan, targetMatchableAttrs, targetEvents, keySpan);
    }
  }
  calcPossibleSecurityContexts(selector, propName, isAttribute) {
    const prop = this._schemaRegistry.getMappedPropName(propName);
    return calcPossibleSecurityContexts(this._schemaRegistry, selector, prop, isAttribute);
  }
  parseEventListenerName(rawName) {
    const [target, eventName] = splitAtColon(rawName, [null, rawName]);
    return {
      eventName: eventName,
      target
    };
  }
  parseLegacyAnimationEventName(rawName) {
    const matches = splitAtPeriod(rawName, [rawName, null]);
    return {
      eventName: matches[0],
      phase: matches[1] === null ? null : matches[1].toLowerCase()
    };
  }
  _parseLegacyAnimationEvent(name, expression, sourceSpan, handlerSpan, targetEvents, keySpan) {
    const {
      eventName,
      phase
    } = this.parseLegacyAnimationEventName(name);
    const ast = this._parseAction(expression, handlerSpan);
    targetEvents.push(new ParsedEvent(eventName, phase, ParsedEventType.LegacyAnimation, ast, sourceSpan, handlerSpan, keySpan));
    if (eventName.length === 0) {
      this._reportError(`Animation event name is missing in binding`, sourceSpan);
    }
    if (phase) {
      if (phase !== 'start' && phase !== 'done') {
        this._reportError(`The provided animation output phase value "${phase}" for "@${eventName}" is not supported (use start or done)`, sourceSpan);
      }
    } else {
      this._reportError(`The animation trigger output event (@${eventName}) is missing its phase value name (start or done are currently supported)`, sourceSpan);
    }
  }
  _parseRegularEvent(name, expression, isAssignmentEvent, sourceSpan, handlerSpan, targetMatchableAttrs, targetEvents, keySpan) {
    const {
      eventName,
      target
    } = this.parseEventListenerName(name);
    const prevErrorCount = this.errors.length;
    const ast = this._parseAction(expression, handlerSpan);
    const isValid = this.errors.length === prevErrorCount;
    targetMatchableAttrs.push([name, ast.source]);
    if (isAssignmentEvent && isValid && !this._isAllowedAssignmentEvent(ast)) {
      this._reportError('Unsupported expression in a two-way binding', sourceSpan);
    }
    let eventType = ParsedEventType.Regular;
    if (isAssignmentEvent) {
      eventType = ParsedEventType.TwoWay;
    }
    if (name.startsWith(`${ANIMATE_PREFIX$1}${PROPERTY_PARTS_SEPARATOR}`)) {
      eventType = ParsedEventType.Animation;
    }
    targetEvents.push(new ParsedEvent(eventName, target, eventType, ast, sourceSpan, handlerSpan, keySpan));
  }
  _parseAction(value, sourceSpan) {
    const absoluteOffset = sourceSpan && sourceSpan.start ? sourceSpan.start.offset : 0;
    try {
      const ast = this._exprParser.parseAction(value, sourceSpan, absoluteOffset);
      if (ast) {
        this.errors.push(...ast.errors);
      }
      if (!ast || ast.ast instanceof EmptyExpr$1) {
        this._reportError(`Empty expressions are not allowed`, sourceSpan);
        return this._exprParser.wrapLiteralPrimitive('ERROR', sourceSpan, absoluteOffset);
      }
      return ast;
    } catch (e) {
      this._reportError(`${e}`, sourceSpan);
      return this._exprParser.wrapLiteralPrimitive('ERROR', sourceSpan, absoluteOffset);
    }
  }
  _reportError(message, sourceSpan, level = ParseErrorLevel.ERROR) {
    this.errors.push(new ParseError(sourceSpan, message, level));
  }
  _validatePropertyOrAttributeName(propName, sourceSpan, isAttr) {
    const report = isAttr ? this._schemaRegistry.validateAttribute(propName) : this._schemaRegistry.validateProperty(propName);
    if (report.error) {
      this._reportError(report.msg, sourceSpan, ParseErrorLevel.ERROR);
    }
  }
  _isAllowedAssignmentEvent(ast) {
    if (ast instanceof ASTWithSource) {
      return this._isAllowedAssignmentEvent(ast.ast);
    }
    if (ast instanceof NonNullAssert) {
      return this._isAllowedAssignmentEvent(ast.expression);
    }
    if (ast instanceof Call && ast.args.length === 1 && ast.receiver instanceof PropertyRead && ast.receiver.name === '$any' && ast.receiver.receiver instanceof ImplicitReceiver) {
      return this._isAllowedAssignmentEvent(ast.args[0]);
    }
    if (ast instanceof PropertyRead || ast instanceof KeyedRead) {
      if (!hasRecursiveSafeReceiver(ast)) {
        return true;
      }
    }
    return false;
  }
}
function hasRecursiveSafeReceiver(ast) {
  if (ast instanceof SafePropertyRead || ast instanceof SafeKeyedRead) {
    return true;
  }
  if (ast instanceof ParenthesizedExpression) {
    return hasRecursiveSafeReceiver(ast.expression);
  }
  if (ast instanceof PropertyRead || ast instanceof KeyedRead || ast instanceof Call) {
    return hasRecursiveSafeReceiver(ast.receiver);
  }
  return false;
}
function isLegacyAnimationLabel(name) {
  return name[0] == '@';
}
function calcPossibleSecurityContexts(registry, selector, propName, isAttribute) {
  let ctxs;
  const [namespaceKey, baseSelector] = selector ? splitNsName(selector, false) : [null, selector];
  const nameToContext = elName => {
    const [nsStr, name] = splitNsName(elName, false);
    const ns = nsStr ?? namespaceKey;
    const fullName = ns ? `:${ns}:${name}` : name;
    return registry.securityContext(fullName, propName, isAttribute);
  };
  const allKnownElements = registry.allKnownElementNames();
  if (baseSelector === null) {
    ctxs = allKnownElements.map(nameToContext);
  } else {
    ctxs = [];
    CssSelector.parse(baseSelector).forEach(selector => {
      let elementNames = selector.element ? [selector.element] : allKnownElements;
      if (selector.element && !registry.hasElement(selector.element, [])) {
        const svgElement = `:${SVG_NAMESPACE}:${selector.element}`;
        const mathElement = `:${MATH_ML_NAMESPACE}:${selector.element}`;
        if (registry.hasElement(svgElement, [])) {
          elementNames = [svgElement];
        } else if (registry.hasElement(mathElement, [])) {
          elementNames = [mathElement];
        }
      }
      const notElementNames = new Set(selector.notSelectors.filter(selector => selector.isElementSelector()).map(selector => selector.element?.toLowerCase()));
      const possibleElementNames = elementNames.filter(elName => {
        const elNameLowerCase = elName.toLowerCase();
        return !notElementNames.has(elNameLowerCase) && !notElementNames.has(splitNsName(elNameLowerCase)[1]);
      });
      ctxs.push(...possibleElementNames.map(nameToContext));
    });
  }
  return ctxs.length === 0 ? [SecurityContext.NONE] : Array.from(new Set(ctxs)).sort();
}
function moveParseSourceSpan(sourceSpan, absoluteSpan) {
  const startDiff = absoluteSpan.start - sourceSpan.start.offset;
  const endDiff = absoluteSpan.end - sourceSpan.end.offset;
  return new ParseSourceSpan(sourceSpan.start.moveBy(startDiff), sourceSpan.end.moveBy(endDiff), sourceSpan.fullStart.moveBy(startDiff), sourceSpan.details);
}

const domSchema = new DomElementSchemaRegistry();
const NG_TEMPLATE_TAG_NAME = 'ng-template';
const ANIMATE_PREFIX = 'animate.';
function isI18nRootNode(meta) {
  return meta instanceof Message;
}
function isSingleI18nIcu(meta) {
  return isI18nRootNode(meta) && meta.nodes.length === 1 && meta.nodes[0] instanceof Icu;
}
function ingestComponent(componentName, template, constantPool, compilationMode, relativeContextFilePath, i18nUseExternalIds, deferMeta, allDeferrableDepsFn, relativeTemplatePath, enableDebugLocations, legacyOptionalChaining, foreignImports) {
  const job = new ComponentCompilationJob(componentName, constantPool, compilationMode, relativeContextFilePath, i18nUseExternalIds, deferMeta, allDeferrableDepsFn, relativeTemplatePath, enableDebugLocations, legacyOptionalChaining, foreignImports);
  ingestNodes(job.root, template);
  return job;
}
function ingestHostBinding(input, bindingParser, constantPool) {
  const job = new HostBindingCompilationJob(input.componentName, constantPool, TemplateCompilationMode.DomOnly, input.legacyOptionalChaining);
  for (const property of input.properties ?? []) {
    let bindingKind = BindingKind.Property;
    if (property.name.startsWith('attr.')) {
      property.name = property.name.substring('attr.'.length);
      bindingKind = BindingKind.Attribute;
    }
    if (property.isLegacyAnimation) {
      bindingKind = BindingKind.LegacyAnimation;
    }
    if (property.isAnimation) {
      bindingKind = BindingKind.Animation;
    }
    const securityContexts = calcHostBindingSecurityContexts(bindingParser, input.componentSelector, property.name, bindingKind === BindingKind.Attribute);
    ingestDomProperty(job, property, bindingKind, securityContexts);
  }
  for (const [name, expr] of Object.entries(input.attributes) ?? []) {
    const securityContexts = calcHostBindingSecurityContexts(bindingParser, input.componentSelector, name, true);
    ingestHostAttribute(job, name, expr, securityContexts);
  }
  for (const event of input.events ?? []) {
    ingestHostEvent(job, event);
  }
  return job;
}
function calcHostBindingSecurityContexts(bindingParser, selector, name, isAttribute) {
  const declaringSelectorContexts = bindingParser.calcPossibleSecurityContexts(selector, name, isAttribute);
  const concreteHostContexts = calcPossibleSecurityContexts(domSchema, null, domSchema.getMappedPropName(name), isAttribute);
  const concreteHostNonNoneContexts = concreteHostContexts.filter(context => context !== SecurityContext.NONE);
  const concreteHostNonNoneCount = concreteHostNonNoneContexts.length;
  const hasConcreteHostNoneContext = concreteHostNonNoneCount !== concreteHostContexts.length;
  if (hasConcreteHostNoneContext && concreteHostNonNoneCount > 0) {
    return concreteHostContexts;
  }
  if (concreteHostNonNoneContexts.some(context => !declaringSelectorContexts.includes(context))) {
    return concreteHostContexts;
  }
  return declaringSelectorContexts.filter(context => context !== SecurityContext.NONE);
}
function ingestDomProperty(job, property, bindingKind, securityContexts) {
  let expression;
  const ast = property.expression.ast;
  if (ast instanceof Interpolation$1) {
    expression = new Interpolation(ast.strings, ast.expressions.map(expr => convertAst(expr, job, property.sourceSpan)), []);
  } else {
    expression = convertAst(ast, job, property.sourceSpan);
  }
  job.root.update.push(createBindingOp(job.root.xref, bindingKind, property.name, expression, null, securityContexts, false, false, null, null, property.sourceSpan));
}
function ingestHostAttribute(job, name, value, securityContexts) {
  const attrBinding = createBindingOp(job.root.xref, BindingKind.Attribute, name, value, null, securityContexts, true, false, null, null, value.sourceSpan);
  job.root.update.push(attrBinding);
}
function ingestHostEvent(job, event) {
  let eventBinding;
  if (event.type === ParsedEventType.Animation) {
    eventBinding = createAnimationListenerOp(job.root.xref, new SlotHandle(), event.name, null, makeListenerHandlerOps(job.root, event.handler, event.handlerSpan), event.name.endsWith('enter') ? "enter" : "leave", event.targetOrPhase, true, event.sourceSpan);
  } else {
    const [phase, target] = event.type !== ParsedEventType.LegacyAnimation ? [null, event.targetOrPhase] : [event.targetOrPhase, null];
    eventBinding = createListenerOp(job.root.xref, new SlotHandle(), event.name, null, makeListenerHandlerOps(job.root, event.handler, event.handlerSpan), phase, target, true, event.sourceSpan);
  }
  job.root.create.push(eventBinding);
}
function ingestNodes(unit, template) {
  for (const node of template) {
    if (node instanceof Element$1) {
      ingestElement(unit, node);
    } else if (node instanceof Template) {
      ingestTemplate(unit, node);
    } else if (node instanceof Content) {
      ingestContent(unit, node);
    } else if (node instanceof Text$3) {
      ingestText(unit, node, null);
    } else if (node instanceof BoundText) {
      ingestBoundText(unit, node, null);
    } else if (node instanceof IfBlock) {
      ingestIfBlock(unit, node);
    } else if (node instanceof SwitchBlock) {
      ingestSwitchBlock(unit, node);
    } else if (node instanceof DeferredBlock) {
      ingestDeferBlock(unit, node);
    } else if (node instanceof Icu$1) {
      ingestIcu(unit, node);
    } else if (node instanceof ForLoopBlock) {
      ingestForBlock(unit, node);
    } else if (node instanceof LetDeclaration$1) {
      ingestLetDeclaration(unit, node);
    } else if (node instanceof Component$1) ; else {
      throw new Error(`Unsupported template node: ${node.constructor.name}`);
    }
  }
}
function ingestElement(unit, element) {
  if (element.i18n !== undefined && !(element.i18n instanceof Message || element.i18n instanceof TagPlaceholder)) {
    throw Error(`Unhandled i18n metadata type for element: ${element.i18n.constructor.name}`);
  }
  const id = unit.job.allocateXrefId();
  const foreignComp = unit.job.getForeignComponent(element);
  if (foreignComp) {
    ingestForeignComponent(unit, id, element, foreignComp);
    return;
  }
  const [namespaceKey, elementName] = splitNsName(element.name);
  const startOp = createElementStartOp(elementName, id, namespaceForKey(namespaceKey), element.i18n instanceof TagPlaceholder ? element.i18n : undefined, element.startSourceSpan, element.sourceSpan);
  unit.create.push(startOp);
  ingestElementBindings(unit, startOp, element);
  ingestReferences(startOp, element);
  let i18nBlockId = null;
  if (element.i18n instanceof Message) {
    i18nBlockId = unit.job.allocateXrefId();
    unit.create.push(createI18nStartOp(i18nBlockId, element.i18n, undefined, element.startSourceSpan));
  }
  ingestNodes(unit, element.children);
  const endOp = createElementEndOp(id, element.endSourceSpan ?? element.startSourceSpan);
  unit.create.push(endOp);
  if (i18nBlockId !== null) {
    OpList.insertBefore(createI18nEndOp(i18nBlockId, element.endSourceSpan ?? element.startSourceSpan), endOp);
  }
}
function ingestForeignComponent(unit, id, element, foreignComp) {
  const props = new Map();
  for (const attr of element.attributes) {
    props.set(attr.name, literal(attr.value));
  }
  for (const input of element.inputs) {
    props.set(input.name, convertAst(input.value, unit.job, input.sourceSpan));
  }
  const contentBlocks = [];
  const childNodes = [];
  for (const child of element.children) {
    if (child instanceof ContentBlock) {
      contentBlocks.push(child);
    } else {
      childNodes.push(child);
    }
  }
  for (const block of contentBlocks) {
    const blockView = unit.job.allocateView(unit.xref);
    for (let i = 0; i < block.variables.length; i++) {
      blockView.contextVariables.set(block.variables[i].name, i);
    }
    ingestNodes(blockView, block.children);
    unit.create.push(createContentOp(id, blockView.xref, block.name, block.startSourceSpan, block.sourceSpan));
  }
  if (childNodes.length > 0) {
    const childView = unit.job.allocateView(unit.xref);
    ingestNodes(childView, childNodes);
    unit.create.push(createContentOp(id, childView.xref, 'children', element.startSourceSpan, element.sourceSpan));
  }
  const constIndex = unit.job.addConst(foreignComp.component);
  unit.create.push(createForeignComponentOp(id, constIndex, props, element.startSourceSpan));
}
function ingestTemplate(unit, tmpl) {
  if (tmpl.i18n !== undefined && !(tmpl.i18n instanceof Message || tmpl.i18n instanceof TagPlaceholder)) {
    throw Error(`Unhandled i18n metadata type for template: ${tmpl.i18n.constructor.name}`);
  }
  const childView = unit.job.allocateView(unit.xref);
  let tagNameWithoutNamespace = tmpl.tagName;
  let namespacePrefix = '';
  if (tmpl.tagName) {
    [namespacePrefix, tagNameWithoutNamespace] = splitNsName(tmpl.tagName);
  }
  const i18nPlaceholder = tmpl.i18n instanceof TagPlaceholder ? tmpl.i18n : undefined;
  const namespace = namespaceForKey(namespacePrefix);
  const functionNameSuffix = tagNameWithoutNamespace === null ? '' : prefixWithNamespace(tagNameWithoutNamespace, namespace);
  const templateKind = isPlainTemplate(tmpl) ? TemplateKind.NgTemplate : TemplateKind.Structural;
  const templateOp = createTemplateOp(childView.xref, templateKind, tagNameWithoutNamespace, functionNameSuffix, namespace, i18nPlaceholder, tmpl.startSourceSpan, tmpl.sourceSpan);
  unit.create.push(templateOp);
  ingestTemplateBindings(unit, templateOp, tmpl, templateKind);
  ingestReferences(templateOp, tmpl);
  ingestNodes(childView, tmpl.children);
  for (const {
    name,
    value
  } of tmpl.variables) {
    childView.contextVariables.set(name, value !== '' ? value : '$implicit');
  }
  if (templateKind === TemplateKind.NgTemplate && tmpl.i18n instanceof Message) {
    const id = unit.job.allocateXrefId();
    OpList.insertAfter(createI18nStartOp(id, tmpl.i18n, undefined, tmpl.startSourceSpan), childView.create.head);
    OpList.insertBefore(createI18nEndOp(id, tmpl.endSourceSpan ?? tmpl.startSourceSpan), childView.create.tail);
  }
}
function ingestContent(unit, content) {
  if (content.i18n !== undefined && !(content.i18n instanceof TagPlaceholder)) {
    throw Error(`Unhandled i18n metadata type for element: ${content.i18n.constructor.name}`);
  }
  let fallbackView = null;
  if (content.children.some(child => !(child instanceof Comment$1) && (!(child instanceof Text$3) || child.value.trim().length > 0))) {
    fallbackView = unit.job.allocateView(unit.xref);
    ingestNodes(fallbackView, content.children);
  }
  const id = unit.job.allocateXrefId();
  const op = createProjectionOp(id, content.selector, content.i18n, fallbackView?.xref ?? null, content.sourceSpan);
  for (const attr of content.attributes) {
    const securityContext = domSchema.securityContext(content.name, attr.name, true);
    unit.update.push(createBindingOp(op.xref, BindingKind.Attribute, attr.name, literal(attr.value), null, securityContext, true, false, null, asMessage(attr.i18n), attr.sourceSpan));
  }
  unit.create.push(op);
}
function ingestText(unit, text, icuPlaceholder) {
  unit.create.push(createTextOp(unit.job.allocateXrefId(), text.value, icuPlaceholder, text.sourceSpan));
}
function ingestBoundText(unit, text, icuPlaceholder) {
  let value = text.value;
  if (value instanceof ASTWithSource) {
    value = value.ast;
  }
  if (!(value instanceof Interpolation$1)) {
    throw new Error(`AssertionError: expected Interpolation for BoundText node, got ${value.constructor.name}`);
  }
  if (text.i18n !== undefined && !(text.i18n instanceof Container)) {
    throw Error(`Unhandled i18n metadata type for text interpolation: ${text.i18n?.constructor.name}`);
  }
  const i18nPlaceholders = text.i18n instanceof Container ? text.i18n.children.filter(node => node instanceof Placeholder).map(placeholder => placeholder.name) : [];
  if (i18nPlaceholders.length > 0 && i18nPlaceholders.length !== value.expressions.length) {
    throw Error(`Unexpected number of i18n placeholders (${value.expressions.length}) for BoundText with ${value.expressions.length} expressions`);
  }
  const textXref = unit.job.allocateXrefId();
  unit.create.push(createTextOp(textXref, '', icuPlaceholder, text.sourceSpan));
  unit.update.push(createInterpolateTextOp(textXref, new Interpolation(value.strings, value.expressions.map(expr => convertAst(expr, unit.job, null)), i18nPlaceholders), text.sourceSpan));
}
function ingestIfBlock(unit, ifBlock) {
  let firstXref = null;
  let conditions = [];
  for (let i = 0; i < ifBlock.branches.length; i++) {
    const ifCase = ifBlock.branches[i];
    const cView = unit.job.allocateView(unit.xref);
    const tagName = ingestControlFlowInsertionPoint(unit, cView.xref, ifCase);
    if (ifCase.expressionAlias !== null) {
      cView.contextVariables.set(ifCase.expressionAlias.name, CTX_REF);
    }
    let ifCaseI18nMeta = undefined;
    if (ifCase.i18n !== undefined) {
      if (!(ifCase.i18n instanceof BlockPlaceholder)) {
        throw Error(`Unhandled i18n metadata type for if block: ${ifCase.i18n?.constructor.name}`);
      }
      ifCaseI18nMeta = ifCase.i18n;
    }
    const createOp = i === 0 ? createConditionalCreateOp : createConditionalBranchCreateOp;
    const conditionalCreateOp = createOp(cView.xref, TemplateKind.Block, tagName, 'Conditional', Namespace.HTML, ifCaseI18nMeta, ifCase.startSourceSpan, ifCase.sourceSpan);
    unit.create.push(conditionalCreateOp);
    if (firstXref === null) {
      firstXref = cView.xref;
    }
    const caseExpr = ifCase.expression ? convertAst(ifCase.expression, unit.job, null) : null;
    const conditionalCaseExpr = new ConditionalCaseExpr(caseExpr, conditionalCreateOp.xref, conditionalCreateOp.handle, ifCase.expressionAlias);
    conditions.push(conditionalCaseExpr);
    ingestNodes(cView, ifCase.children);
  }
  unit.update.push(createConditionalOp(firstXref, null, conditions, ifBlock.sourceSpan));
}
function ingestSwitchBlock(unit, switchBlock) {
  if (switchBlock.groups.length === 0) {
    return;
  }
  let firstXref = null;
  let conditions = [];
  for (let i = 0; i < switchBlock.groups.length; i++) {
    const switchCaseGroup = switchBlock.groups[i];
    const cView = unit.job.allocateView(unit.xref);
    const tagName = ingestControlFlowInsertionPoint(unit, cView.xref, switchCaseGroup);
    let switchCaseI18nMeta = undefined;
    if (switchCaseGroup.i18n !== undefined) {
      if (!(switchCaseGroup.i18n instanceof BlockPlaceholder)) {
        throw Error(`Unhandled i18n metadata type for switch block: ${switchCaseGroup.i18n?.constructor.name}`);
      }
      switchCaseI18nMeta = switchCaseGroup.i18n;
    }
    const createOp = i === 0 ? createConditionalCreateOp : createConditionalBranchCreateOp;
    const conditionalCreateOp = createOp(cView.xref, TemplateKind.Block, tagName, 'Case', Namespace.HTML, switchCaseI18nMeta, switchCaseGroup.startSourceSpan, switchCaseGroup.sourceSpan);
    unit.create.push(conditionalCreateOp);
    if (firstXref === null) {
      firstXref = cView.xref;
    }
    for (const switchCase of switchCaseGroup.cases) {
      const caseExpr = switchCase.expression ? convertAst(switchCase.expression, unit.job, switchBlock.startSourceSpan) : null;
      const conditionalCaseExpr = new ConditionalCaseExpr(caseExpr, conditionalCreateOp.xref, conditionalCreateOp.handle);
      conditions.push(conditionalCaseExpr);
    }
    ingestNodes(cView, switchCaseGroup.children);
  }
  unit.update.push(createConditionalOp(firstXref, convertAst(switchBlock.expression, unit.job, null), conditions, switchBlock.sourceSpan));
}
function ingestDeferView(unit, suffix, i18nMeta, children, sourceSpan) {
  if (i18nMeta !== undefined && !(i18nMeta instanceof BlockPlaceholder)) {
    throw Error('Unhandled i18n metadata type for defer block');
  }
  if (children === undefined) {
    return null;
  }
  const secondaryView = unit.job.allocateView(unit.xref);
  ingestNodes(secondaryView, children);
  const templateOp = createTemplateOp(secondaryView.xref, TemplateKind.Block, null, `Defer${suffix}`, Namespace.HTML, i18nMeta, sourceSpan, sourceSpan);
  unit.create.push(templateOp);
  return templateOp;
}
function ingestDeferBlock(unit, deferBlock) {
  let ownResolverFn = null;
  if (unit.job.deferMeta.mode === 0) {
    if (!unit.job.deferMeta.blocks.has(deferBlock)) {
      throw new Error(`AssertionError: unable to find a dependency function for this deferred block`);
    }
    ownResolverFn = unit.job.deferMeta.blocks.get(deferBlock) ?? null;
  }
  const main = ingestDeferView(unit, '', deferBlock.i18n, deferBlock.children, deferBlock.sourceSpan);
  const loading = ingestDeferView(unit, 'Loading', deferBlock.loading?.i18n, deferBlock.loading?.children, deferBlock.loading?.sourceSpan);
  const placeholder = ingestDeferView(unit, 'Placeholder', deferBlock.placeholder?.i18n, deferBlock.placeholder?.children, deferBlock.placeholder?.sourceSpan);
  const error = ingestDeferView(unit, 'Error', deferBlock.error?.i18n, deferBlock.error?.children, deferBlock.error?.sourceSpan);
  const deferXref = unit.job.allocateXrefId();
  const deferOp = createDeferOp(deferXref, main.xref, main.handle, ownResolverFn, unit.job.allDeferrableDepsFn, deferBlock.sourceSpan);
  deferOp.placeholderView = placeholder?.xref ?? null;
  deferOp.placeholderSlot = placeholder?.handle ?? null;
  deferOp.loadingSlot = loading?.handle ?? null;
  deferOp.errorSlot = error?.handle ?? null;
  deferOp.placeholderMinimumTime = deferBlock.placeholder?.minimumTime ?? null;
  deferOp.loadingMinimumTime = deferBlock.loading?.minimumTime ?? null;
  deferOp.loadingAfterTime = deferBlock.loading?.afterTime ?? null;
  deferOp.flags = calcDeferBlockFlags(deferBlock);
  unit.create.push(deferOp);
  const deferOnOps = [];
  const deferWhenOps = [];
  ingestDeferTriggers("hydrate", deferBlock.hydrateTriggers, deferOnOps, deferWhenOps, unit, deferXref);
  ingestDeferTriggers("none", deferBlock.triggers, deferOnOps, deferWhenOps, unit, deferXref);
  ingestDeferTriggers("prefetch", deferBlock.prefetchTriggers, deferOnOps, deferWhenOps, unit, deferXref);
  const hasConcreteTrigger = deferOnOps.some(op => op.modifier === "none") || deferWhenOps.some(op => op.modifier === "none");
  if (!hasConcreteTrigger) {
    deferOnOps.push(createDeferOnOp(deferXref, {
      kind: DeferTriggerKind.Idle,
      timeout: null
    }, "none", null));
  }
  unit.create.push(deferOnOps);
  unit.update.push(deferWhenOps);
}
function calcDeferBlockFlags(deferBlockDetails) {
  if (Object.keys(deferBlockDetails.hydrateTriggers).length > 0) {
    return 1;
  }
  return null;
}
function ingestDeferTriggers(modifier, triggers, onOps, whenOps, unit, deferXref) {
  if (triggers.idle !== undefined) {
    const deferOnOp = createDeferOnOp(deferXref, {
      kind: DeferTriggerKind.Idle,
      timeout: triggers.idle.timeout ?? null
    }, modifier, triggers.idle.sourceSpan);
    onOps.push(deferOnOp);
  }
  if (triggers.immediate !== undefined) {
    const deferOnOp = createDeferOnOp(deferXref, {
      kind: DeferTriggerKind.Immediate
    }, modifier, triggers.immediate.sourceSpan);
    onOps.push(deferOnOp);
  }
  if (triggers.timer !== undefined) {
    const deferOnOp = createDeferOnOp(deferXref, {
      kind: DeferTriggerKind.Timer,
      delay: triggers.timer.delay
    }, modifier, triggers.timer.sourceSpan);
    onOps.push(deferOnOp);
  }
  if (triggers.hover !== undefined) {
    const deferOnOp = createDeferOnOp(deferXref, {
      kind: DeferTriggerKind.Hover,
      targetName: triggers.hover.reference,
      targetXref: null,
      targetSlot: null,
      targetView: null,
      targetSlotViewSteps: null
    }, modifier, triggers.hover.sourceSpan);
    onOps.push(deferOnOp);
  }
  if (triggers.interaction !== undefined) {
    const deferOnOp = createDeferOnOp(deferXref, {
      kind: DeferTriggerKind.Interaction,
      targetName: triggers.interaction.reference,
      targetXref: null,
      targetSlot: null,
      targetView: null,
      targetSlotViewSteps: null
    }, modifier, triggers.interaction.sourceSpan);
    onOps.push(deferOnOp);
  }
  if (triggers.viewport !== undefined) {
    const deferOnOp = createDeferOnOp(deferXref, {
      kind: DeferTriggerKind.Viewport,
      targetName: triggers.viewport.reference,
      targetXref: null,
      targetSlot: null,
      targetView: null,
      targetSlotViewSteps: null,
      options: triggers.viewport.options ? convertAst(triggers.viewport.options, unit.job, triggers.viewport.sourceSpan) : null
    }, modifier, triggers.viewport.sourceSpan);
    onOps.push(deferOnOp);
  }
  if (triggers.never !== undefined) {
    const deferOnOp = createDeferOnOp(deferXref, {
      kind: DeferTriggerKind.Never
    }, modifier, triggers.never.sourceSpan);
    onOps.push(deferOnOp);
  }
  if (triggers.when !== undefined) {
    if (triggers.when.value instanceof Interpolation$1) {
      throw new Error(`Unexpected interpolation in defer block when trigger`);
    }
    const deferOnOp = createDeferWhenOp(deferXref, convertAst(triggers.when.value, unit.job, triggers.when.sourceSpan), modifier, triggers.when.sourceSpan);
    whenOps.push(deferOnOp);
  }
}
function ingestIcu(unit, icu) {
  if (icu.i18n instanceof Message && isSingleI18nIcu(icu.i18n)) {
    const xref = unit.job.allocateXrefId();
    unit.create.push(createIcuStartOp(xref, icu.i18n, icuFromI18nMessage(icu.i18n).name, null));
    for (const [placeholder, text] of Object.entries({
      ...icu.vars,
      ...icu.placeholders
    })) {
      if (text instanceof BoundText) {
        ingestBoundText(unit, text, placeholder);
      } else {
        ingestText(unit, text, placeholder);
      }
    }
    unit.create.push(createIcuEndOp(xref));
  } else {
    throw Error(`Unhandled i18n metadata type for ICU: ${icu.i18n?.constructor.name}`);
  }
}
function ingestForBlock(unit, forBlock) {
  const repeaterView = unit.job.allocateView(unit.xref);
  const indexName = `ɵ$index_${repeaterView.xref}`;
  const countName = `ɵ$count_${repeaterView.xref}`;
  const indexVarNames = new Set();
  repeaterView.contextVariables.set(forBlock.item.name, forBlock.item.value);
  for (const variable of forBlock.contextVariables) {
    if (variable.value === '$index') {
      indexVarNames.add(variable.name);
    }
    if (variable.name === '$index') {
      repeaterView.contextVariables.set('$index', variable.value).set(indexName, variable.value);
    } else if (variable.name === '$count') {
      repeaterView.contextVariables.set('$count', variable.value).set(countName, variable.value);
    } else {
      repeaterView.aliases.add({
        kind: SemanticVariableKind.Alias,
        name: null,
        identifier: variable.name,
        expression: getComputedForLoopVariableExpression(variable, indexName, countName)
      });
    }
  }
  let track;
  if (forBlock.trackBy === null) {
    track = variable('$index');
  } else {
    track = convertAst(forBlock.trackBy, unit.job, convertSourceSpan(forBlock.trackBy.span, forBlock.sourceSpan));
  }
  ingestNodes(repeaterView, forBlock.children);
  let emptyView = null;
  let emptyTagName = null;
  if (forBlock.empty !== null) {
    emptyView = unit.job.allocateView(unit.xref);
    ingestNodes(emptyView, forBlock.empty.children);
    emptyTagName = ingestControlFlowInsertionPoint(unit, emptyView.xref, forBlock.empty);
  }
  const varNames = {
    $index: indexVarNames,
    $implicit: forBlock.item.name
  };
  if (forBlock.i18n !== undefined && !(forBlock.i18n instanceof BlockPlaceholder)) {
    throw Error('AssertionError: Unhandled i18n metadata type or @for');
  }
  if (forBlock.empty?.i18n !== undefined && !(forBlock.empty.i18n instanceof BlockPlaceholder)) {
    throw Error('AssertionError: Unhandled i18n metadata type or @empty');
  }
  const i18nPlaceholder = forBlock.i18n;
  const emptyI18nPlaceholder = forBlock.empty?.i18n;
  const tagName = ingestControlFlowInsertionPoint(unit, repeaterView.xref, forBlock);
  const repeaterCreate = createRepeaterCreateOp(repeaterView.xref, emptyView?.xref ?? null, tagName, track, varNames, emptyTagName, i18nPlaceholder, emptyI18nPlaceholder, forBlock.startSourceSpan, forBlock.sourceSpan);
  unit.create.push(repeaterCreate);
  const expression = convertAst(forBlock.expression, unit.job, convertSourceSpan(forBlock.expression.span, forBlock.sourceSpan));
  const repeater = createRepeaterOp(repeaterCreate.xref, repeaterCreate.handle, expression, forBlock.sourceSpan);
  unit.update.push(repeater);
}
function getComputedForLoopVariableExpression(variable, indexName, countName) {
  switch (variable.value) {
    case '$index':
      return new LexicalReadExpr(indexName);
    case '$count':
      return new LexicalReadExpr(countName);
    case '$first':
      return new LexicalReadExpr(indexName).identical(literal(0));
    case '$last':
      return new LexicalReadExpr(indexName).identical(new LexicalReadExpr(countName).minus(literal(1)));
    case '$even':
      return new LexicalReadExpr(indexName).modulo(literal(2)).identical(literal(0));
    case '$odd':
      return new LexicalReadExpr(indexName).modulo(literal(2)).notIdentical(literal(0));
    default:
      throw new Error(`AssertionError: unknown @for loop variable ${variable.value}`);
  }
}
function ingestLetDeclaration(unit, node) {
  const target = unit.job.allocateXrefId();
  unit.create.push(createDeclareLetOp(target, node.name, node.sourceSpan));
  unit.update.push(createStoreLetOp(target, node.name, convertAst(node.value, unit.job, node.valueSpan), node.sourceSpan));
}
function convertAst(ast, job, baseSourceSpan) {
  if (ast instanceof ASTWithSource) {
    return convertAst(ast.ast, job, baseSourceSpan);
  } else if (ast instanceof PropertyRead) {
    if (ast.receiver instanceof ImplicitReceiver) {
      return new LexicalReadExpr(ast.name);
    } else {
      return new ReadPropExpr(convertAst(ast.receiver, job, baseSourceSpan), ast.name, null, convertSourceSpan(ast.span, baseSourceSpan));
    }
  } else if (ast instanceof Call) {
    if (ast.receiver instanceof ImplicitReceiver) {
      throw new Error(`Unexpected ImplicitReceiver`);
    } else {
      return new InvokeFunctionExpr(convertAst(ast.receiver, job, baseSourceSpan), ast.args.map(arg => convertAst(arg, job, baseSourceSpan)), undefined, convertSourceSpan(ast.span, baseSourceSpan));
    }
  } else if (ast instanceof LiteralPrimitive) {
    return literal(ast.value, undefined, convertSourceSpan(ast.span, baseSourceSpan));
  } else if (ast instanceof Unary) {
    switch (ast.operator) {
      case '+':
        return new UnaryOperatorExpr(UnaryOperator.Plus, convertAst(ast.expr, job, baseSourceSpan), undefined, convertSourceSpan(ast.span, baseSourceSpan));
      case '-':
        return new UnaryOperatorExpr(UnaryOperator.Minus, convertAst(ast.expr, job, baseSourceSpan), undefined, convertSourceSpan(ast.span, baseSourceSpan));
      default:
        throw new Error(`AssertionError: unknown unary operator ${ast.operator}`);
    }
  } else if (ast instanceof Binary) {
    const operator = BINARY_OPERATORS.get(ast.operation);
    if (operator === undefined) {
      throw new Error(`AssertionError: unknown binary operator ${ast.operation}`);
    }
    return new BinaryOperatorExpr(operator, convertAst(ast.left, job, baseSourceSpan), convertAst(ast.right, job, baseSourceSpan), undefined, convertSourceSpan(ast.span, baseSourceSpan));
  } else if (ast instanceof ThisReceiver) {
    return new ContextExpr(job.root.xref);
  } else if (ast instanceof KeyedRead) {
    return new ReadKeyExpr(convertAst(ast.receiver, job, baseSourceSpan), convertAst(ast.key, job, baseSourceSpan), undefined, convertSourceSpan(ast.span, baseSourceSpan));
  } else if (ast instanceof Chain) {
    throw new Error(`AssertionError: Chain in unknown context`);
  } else if (ast instanceof LiteralMap) {
    const entries = ast.keys.map((key, idx) => {
      const value = convertAst(ast.values[idx], job, baseSourceSpan);
      return key.kind === 'spread' ? new LiteralMapSpreadAssignment(value) : new LiteralMapPropertyAssignment(key.key, value, key.quoted);
    });
    return new LiteralMapExpr(entries, undefined, convertSourceSpan(ast.span, baseSourceSpan));
  } else if (ast instanceof LiteralArray) {
    return new LiteralArrayExpr(ast.expressions.map(expr => convertAst(expr, job, baseSourceSpan)));
  } else if (ast instanceof Conditional) {
    return new ConditionalExpr(convertAst(ast.condition, job, baseSourceSpan), convertAst(ast.trueExp, job, baseSourceSpan), convertAst(ast.falseExp, job, baseSourceSpan), undefined, convertSourceSpan(ast.span, baseSourceSpan));
  } else if (ast instanceof NonNullAssert) {
    return convertAst(ast.expression, job, baseSourceSpan);
  } else if (ast instanceof BindingPipe) {
    return new PipeBindingExpr(job.allocateXrefId(), new SlotHandle(), ast.name, [convertAst(ast.exp, job, baseSourceSpan), ...ast.args.map(arg => convertAst(arg, job, baseSourceSpan))]);
  } else if (ast instanceof SafeKeyedRead) {
    return new SafeKeyedReadExpr(convertAst(ast.receiver, job, baseSourceSpan), convertAst(ast.key, job, baseSourceSpan), convertSourceSpan(ast.span, baseSourceSpan));
  } else if (ast instanceof SafePropertyRead) {
    return new SafePropertyReadExpr(convertAst(ast.receiver, job, baseSourceSpan), ast.name);
  } else if (ast instanceof SafeCall) {
    return new InvokeFunctionExpr(convertAst(ast.receiver, job, baseSourceSpan), ast.args.map(a => convertAst(a, job, baseSourceSpan)), null, convertSourceSpan(ast.span, baseSourceSpan), false, [], true);
  } else if (ast instanceof EmptyExpr$1) {
    return new EmptyExpr(convertSourceSpan(ast.span, baseSourceSpan));
  } else if (ast instanceof PrefixNot) {
    return not(convertAst(ast.expression, job, baseSourceSpan), convertSourceSpan(ast.span, baseSourceSpan));
  } else if (ast instanceof TypeofExpression) {
    return typeofExpr(convertAst(ast.expression, job, baseSourceSpan));
  } else if (ast instanceof VoidExpression) {
    return new VoidExpr(convertAst(ast.expression, job, baseSourceSpan), undefined, convertSourceSpan(ast.span, baseSourceSpan));
  } else if (ast instanceof TemplateLiteral) {
    return convertTemplateLiteral(ast, job, baseSourceSpan);
  } else if (ast instanceof TaggedTemplateLiteral) {
    return new TaggedTemplateLiteralExpr(convertAst(ast.tag, job, baseSourceSpan), convertTemplateLiteral(ast.template, job, baseSourceSpan), undefined, convertSourceSpan(ast.span, baseSourceSpan));
  } else if (ast instanceof ParenthesizedExpression) {
    return new ParenthesizedExpr(convertAst(ast.expression, job, baseSourceSpan), undefined, convertSourceSpan(ast.span, baseSourceSpan));
  } else if (ast instanceof RegularExpressionLiteral) {
    return new RegularExpressionLiteralExpr(ast.body, ast.flags, baseSourceSpan);
  } else if (ast instanceof SpreadElement) {
    return new SpreadElementExpr(convertAst(ast.expression, job, baseSourceSpan));
  } else if (ast instanceof ArrowFunction) {
    return updateParameterReferences(arrowFn(ast.parameters.map(arg => new FnParam(arg.name, DYNAMIC_TYPE)), convertAst(ast.body, job, baseSourceSpan)));
  } else {
    throw new Error(`Unhandled expression type "${ast.constructor.name}" in file "${baseSourceSpan?.start.file.url}"`);
  }
}
function convertTemplateLiteral(ast, job, baseSourceSpan) {
  return new TemplateLiteralExpr(ast.elements.map(el => {
    return new TemplateLiteralElementExpr(el.text, convertSourceSpan(el.span, baseSourceSpan));
  }), ast.expressions.map(expr => convertAst(expr, job, baseSourceSpan)), convertSourceSpan(ast.span, baseSourceSpan));
}
function convertAstWithInterpolation(job, value, i18nMeta, sourceSpan) {
  let expression;
  if (value instanceof Interpolation$1) {
    expression = new Interpolation(value.strings, value.expressions.map(e => convertAst(e, job, null)), Object.keys(asMessage(i18nMeta)?.placeholders ?? {}));
  } else if (value instanceof AST) {
    expression = convertAst(value, job, null);
  } else {
    expression = literal(value);
  }
  return expression;
}
const BINDING_KINDS = new Map([[BindingType.Property, BindingKind.Property], [BindingType.TwoWay, BindingKind.TwoWayProperty], [BindingType.Attribute, BindingKind.Attribute], [BindingType.Class, BindingKind.ClassName], [BindingType.Style, BindingKind.StyleProperty], [BindingType.LegacyAnimation, BindingKind.LegacyAnimation], [BindingType.Animation, BindingKind.Animation]]);
function isPlainTemplate(tmpl) {
  return splitNsName(tmpl.tagName ?? '')[1] === NG_TEMPLATE_TAG_NAME;
}
function asMessage(i18nMeta) {
  if (i18nMeta == null) {
    return null;
  }
  if (!(i18nMeta instanceof Message)) {
    throw Error(`Expected i18n meta to be a Message, but got: ${i18nMeta.constructor.name}`);
  }
  return i18nMeta;
}
function ingestElementBindings(unit, op, element) {
  let bindings = new Array();
  let i18nAttributeBindingNames = new Set();
  for (const attr of element.attributes) {
    const [ns, elementName] = splitNsName(element.name);
    let namespace = ns;
    if (!ns) {
      switch (op.namespace) {
        case Namespace.SVG:
          namespace = SVG_NAMESPACE;
          break;
        case Namespace.Math:
          namespace = MATH_ML_NAMESPACE;
          break;
      }
    }
    const securityContext = domSchema.securityContext(namespace ? `:${namespace}:${elementName}` : elementName, attr.name, true);
    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));
    if (attr.i18n) {
      i18nAttributeBindingNames.add(attr.name);
    }
  }
  for (const input of element.inputs) {
    if (i18nAttributeBindingNames.has(input.name)) {
      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.`);
    }
    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));
  }
  unit.create.push(bindings.filter(b => b?.kind === OpKind.ExtractedAttribute));
  unit.update.push(bindings.filter(b => b?.kind === OpKind.Binding));
  for (const output of element.outputs) {
    if (output.type === ParsedEventType.LegacyAnimation && output.phase === null) {
      throw Error('Animation listener should have a phase');
    }
    if (output.type === ParsedEventType.TwoWay) {
      unit.create.push(createTwoWayListenerOp(op.xref, op.handle, output.name, op.tag, makeTwoWayListenerHandlerOps(unit, output.handler, output.handlerSpan), output.sourceSpan));
    } else if (output.type === ParsedEventType.Animation) {
      unit.create.push(createAnimationListenerOp(op.xref, op.handle, output.name, op.tag, makeListenerHandlerOps(unit, output.handler, output.handlerSpan), output.name.endsWith('enter') ? "enter" : "leave", output.target, false, output.sourceSpan));
    } else {
      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));
    }
  }
  if (bindings.some(b => b?.i18nMessage) !== null) {
    unit.create.push(createI18nAttributesOp(unit.job.allocateXrefId(), new SlotHandle(), op.xref));
  }
}
function ingestTemplateBindings(unit, op, template, templateKind) {
  let bindings = new Array();
  for (const attr of template.templateAttrs) {
    if (attr instanceof TextAttribute) {
      const securityContext = domSchema.securityContext(NG_TEMPLATE_TAG_NAME, attr.name, true);
      bindings.push(createTemplateBinding(unit, op.xref, BindingType.Attribute, attr.name, attr.value, null, securityContext, true, templateKind, asMessage(attr.i18n), attr.sourceSpan));
    } else {
      bindings.push(createTemplateBinding(unit, op.xref, attr.type, attr.name, astOf(attr.value), attr.unit, attr.securityContext, true, templateKind, asMessage(attr.i18n), attr.sourceSpan));
    }
  }
  for (const attr of template.attributes) {
    const securityContext = domSchema.securityContext(NG_TEMPLATE_TAG_NAME, attr.name, true);
    bindings.push(createTemplateBinding(unit, op.xref, BindingType.Attribute, attr.name, attr.value, null, securityContext, false, templateKind, asMessage(attr.i18n), attr.sourceSpan));
  }
  for (const input of template.inputs) {
    bindings.push(createTemplateBinding(unit, op.xref, input.type, input.name, astOf(input.value), input.unit, input.securityContext, false, templateKind, asMessage(input.i18n), input.sourceSpan));
  }
  unit.create.push(bindings.filter(b => b?.kind === OpKind.ExtractedAttribute));
  unit.update.push(bindings.filter(b => b?.kind === OpKind.Binding));
  for (const output of template.outputs) {
    if (output.type === ParsedEventType.LegacyAnimation && output.phase === null) {
      throw Error('Animation listener should have a phase');
    }
    if (templateKind === TemplateKind.NgTemplate) {
      if (output.type === ParsedEventType.TwoWay) {
        unit.create.push(createTwoWayListenerOp(op.xref, op.handle, output.name, op.tag, makeTwoWayListenerHandlerOps(unit, output.handler, output.handlerSpan), output.sourceSpan));
      } else {
        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));
      }
    }
    if (templateKind === TemplateKind.Structural && output.type !== ParsedEventType.LegacyAnimation) {
      const securityContext = domSchema.securityContext(NG_TEMPLATE_TAG_NAME, output.name, false);
      unit.create.push(createExtractedAttributeOp(op.xref, BindingKind.Property, null, output.name, null, null, null, securityContext));
    }
  }
  if (bindings.some(b => b?.i18nMessage) !== null) {
    unit.create.push(createI18nAttributesOp(unit.job.allocateXrefId(), new SlotHandle(), op.xref));
  }
}
function createTemplateBinding(view, xref, type, name, value, unit, securityContext, isStructuralTemplateAttribute, templateKind, i18nMessage, sourceSpan) {
  const isTextBinding = typeof value === 'string';
  if (templateKind === TemplateKind.Structural) {
    if (!isStructuralTemplateAttribute) {
      switch (type) {
        case BindingType.Property:
        case BindingType.Class:
        case BindingType.Style:
          return createExtractedAttributeOp(xref, BindingKind.Property, null, name, null, null, i18nMessage, securityContext);
        case BindingType.TwoWay:
          return createExtractedAttributeOp(xref, BindingKind.TwoWayProperty, null, name, null, null, i18nMessage, securityContext);
      }
    }
    if (!isTextBinding && (type === BindingType.Attribute || type === BindingType.LegacyAnimation || type === BindingType.Animation)) {
      return null;
    }
  }
  let bindingType = BINDING_KINDS.get(type);
  if (templateKind === TemplateKind.NgTemplate) {
    if (type === BindingType.Class || type === BindingType.Style || type === BindingType.Attribute && !isTextBinding) {
      bindingType = BindingKind.Property;
    }
  }
  return createBindingOp(xref, bindingType, name, convertAstWithInterpolation(view.job, value, i18nMessage), unit, securityContext, isTextBinding, isStructuralTemplateAttribute, templateKind, i18nMessage, sourceSpan);
}
function makeListenerHandlerOps(unit, handler, handlerSpan) {
  handler = astOf(handler);
  const handlerOps = new Array();
  let handlerExprs = handler instanceof Chain ? handler.expressions : [handler];
  if (handlerExprs.length === 0) {
    throw new Error('Expected listener to have non-empty expression list.');
  }
  const expressions = handlerExprs.map(expr => convertAst(expr, unit.job, handlerSpan));
  const returnExpr = expressions.pop();
  handlerOps.push(...expressions.map(e => createStatementOp(new ExpressionStatement(e, e.sourceSpan))));
  handlerOps.push(createStatementOp(new ReturnStatement(returnExpr, returnExpr.sourceSpan)));
  return handlerOps;
}
function makeTwoWayListenerHandlerOps(unit, handler, handlerSpan) {
  handler = astOf(handler);
  const handlerOps = new Array();
  if (handler instanceof Chain) {
    if (handler.expressions.length === 1) {
      handler = handler.expressions[0];
    } else {
      throw new Error('Expected two-way listener to have a single expression.');
    }
  }
  const handlerExpr = convertAst(handler, unit.job, handlerSpan);
  const eventReference = new LexicalReadExpr('$event');
  const twoWaySetExpr = new TwoWayBindingSetExpr(handlerExpr, eventReference);
  handlerOps.push(createStatementOp(new ExpressionStatement(twoWaySetExpr)));
  handlerOps.push(createStatementOp(new ReturnStatement(eventReference)));
  return handlerOps;
}
function astOf(ast) {
  return ast instanceof ASTWithSource ? ast.ast : ast;
}
function ingestReferences(op, element) {
  assertIsArray(op.localRefs);
  for (const {
    name,
    value
  } of element.references) {
    op.localRefs.push({
      name,
      target: value
    });
  }
}
function assertIsArray(value) {
  if (!Array.isArray(value)) {
    throw new Error(`AssertionError: expected an array`);
  }
}
function convertSourceSpan(span, baseSourceSpan) {
  if (baseSourceSpan === null) {
    return null;
  }
  const start = baseSourceSpan.start.moveBy(span.start);
  const end = baseSourceSpan.start.moveBy(span.end);
  const fullStart = baseSourceSpan.fullStart.moveBy(span.start);
  return new ParseSourceSpan(start, end, fullStart);
}
function ingestControlFlowInsertionPoint(unit, xref, node) {
  let root = null;
  for (const child of node.children) {
    if (child instanceof Comment$1 || child instanceof LetDeclaration$1) {
      continue;
    }
    if (root !== null) {
      return null;
    }
    if (child instanceof Element$1 && unit.job.getForeignComponent(child) === null || child instanceof Template && child.tagName !== null) {
      root = child;
    } else {
      return null;
    }
  }
  if (root !== null) {
    for (const attr of root.attributes) {
      if (!attr.name.startsWith(ANIMATE_PREFIX)) {
        const securityContext = domSchema.securityContext(NG_TEMPLATE_TAG_NAME, attr.name, true);
        unit.update.push(createBindingOp(xref, BindingKind.Attribute, attr.name, literal(attr.value), null, securityContext, true, false, null, asMessage(attr.i18n), attr.sourceSpan));
      }
    }
    for (const attr of root.inputs) {
      if (attr.type !== BindingType.LegacyAnimation && attr.type !== BindingType.Animation && attr.type !== BindingType.Attribute) {
        const securityContext = domSchema.securityContext(NG_TEMPLATE_TAG_NAME, attr.name, true);
        unit.create.push(createExtractedAttributeOp(xref, BindingKind.Property, null, attr.name, null, null, null, securityContext));
      }
    }
    const tagName = root instanceof Element$1 ? root.name : root.tagName;
    return tagName === NG_TEMPLATE_TAG_NAME ? null : tagName;
  }
  return null;
}
function updateParameterReferences(root) {
  const parameterNames = new Set(root.params.map(param => param.name));
  return transformExpressionsInExpression(root, expr => {
    if (expr instanceof ArrowFunctionExpr$1) {
      for (const param of expr.params) {
        parameterNames.add(param.name);
      }
    } else if (expr instanceof LexicalReadExpr && parameterNames.has(expr.name)) {
      return variable(expr.name);
    }
    return expr;
  }, VisitorContextFlag.None);
}

const ENABLE_TEMPLATE_SOURCE_LOCATIONS = false;

function renderFlagCheckIfStmt(flags, statements) {
  return ifStmt(variable(RENDER_FLAGS).bitwiseAnd(literal(flags), null), statements);
}
function toQueryFlags(query) {
  return (query.descendants ? 1 : 0) | (query.static ? 2 : 0) | (query.emitDistinctChangesOnly ? 4 : 0);
}
function getQueryPredicate(query, constantPool) {
  if (Array.isArray(query.predicate)) {
    let predicate = [];
    query.predicate.forEach(selector => {
      const selectors = selector.split(',').map(token => literal(token.trim()));
      predicate.push(...selectors);
    });
    return constantPool.getConstLiteral(literalArr(predicate), true);
  } else {
    switch (query.predicate.forwardRef) {
      case 0:
      case 2:
        return query.predicate.expression;
      case 1:
        return importExpr(Identifiers.resolveForwardRef).callFn([query.predicate.expression]);
    }
  }
}
function getQueryCreateParameters(query, constantPool, prependParams) {
  const parameters = [];
  if (prependParams !== undefined) {
    parameters.push(...prependParams);
  }
  if (query.isSignal) {
    parameters.push(new ReadPropExpr(variable(CONTEXT_NAME), query.propertyName));
  }
  parameters.push(getQueryPredicate(query, constantPool), literal(toQueryFlags(query)));
  if (query.read) {
    parameters.push(query.read);
  }
  return parameters;
}
const queryAdvancePlaceholder = Symbol('queryAdvancePlaceholder');
function collapseAdvanceStatements(statements) {
  const result = [];
  let advanceCollapseCount = 0;
  const flushAdvanceCount = () => {
    if (advanceCollapseCount > 0) {
      result.unshift(importExpr(Identifiers.queryAdvance).callFn(advanceCollapseCount === 1 ? [] : [literal(advanceCollapseCount)]).toStmt());
      advanceCollapseCount = 0;
    }
  };
  for (let i = statements.length - 1; i >= 0; i--) {
    const st = statements[i];
    if (st === queryAdvancePlaceholder) {
      advanceCollapseCount++;
    } else {
      flushAdvanceCount();
      result.unshift(st);
    }
  }
  flushAdvanceCount();
  return result;
}
function createViewQueriesFunction(viewQueries, constantPool, name) {
  const createStatements = [];
  const updateStatements = [];
  const tempAllocator = temporaryAllocator(st => updateStatements.push(st), TEMPORARY_NAME);
  let viewQuerySignalCall = null;
  let viewQueryCall = null;
  viewQueries.forEach(query => {
    const params = getQueryCreateParameters(query, constantPool);
    if (query.isSignal) {
      viewQuerySignalCall ??= importExpr(Identifiers.viewQuerySignal);
      viewQuerySignalCall = viewQuerySignalCall.callFn(params);
    } else {
      viewQueryCall ??= importExpr(Identifiers.viewQuery);
      viewQueryCall = viewQueryCall.callFn(params);
    }
    if (query.isSignal) {
      updateStatements.push(queryAdvancePlaceholder);
      return;
    }
    const temporary = tempAllocator();
    const getQueryList = importExpr(Identifiers.loadQuery).callFn([]);
    const refresh = importExpr(Identifiers.queryRefresh).callFn([temporary.set(getQueryList)]);
    const updateDirective = variable(CONTEXT_NAME).prop(query.propertyName).set(query.first ? temporary.prop('first') : temporary);
    updateStatements.push(refresh.and(updateDirective).toStmt());
  });
  if (viewQuerySignalCall !== null) {
    createStatements.push(new ExpressionStatement(viewQuerySignalCall));
  }
  if (viewQueryCall !== null) {
    createStatements.push(new ExpressionStatement(viewQueryCall));
  }
  const viewQueryFnName = name ? `${name}_Query` : null;
  return fn([new FnParam(RENDER_FLAGS, NUMBER_TYPE), new FnParam(CONTEXT_NAME, DYNAMIC_TYPE)], [renderFlagCheckIfStmt(1, createStatements), renderFlagCheckIfStmt(2, collapseAdvanceStatements(updateStatements))], INFERRED_TYPE, null, viewQueryFnName);
}
function createContentQueriesFunction(queries, constantPool, name) {
  const createStatements = [];
  const updateStatements = [];
  const tempAllocator = temporaryAllocator(st => updateStatements.push(st), TEMPORARY_NAME);
  let contentQuerySignalCall = null;
  let contentQueryCall = null;
  for (const query of queries) {
    const params = getQueryCreateParameters(query, constantPool, [variable('dirIndex')]);
    if (query.isSignal) {
      contentQuerySignalCall ??= importExpr(Identifiers.contentQuerySignal);
      contentQuerySignalCall = contentQuerySignalCall.callFn(params);
    } else {
      contentQueryCall ??= importExpr(Identifiers.contentQuery);
      contentQueryCall = contentQueryCall.callFn(params);
    }
    if (query.isSignal) {
      updateStatements.push(queryAdvancePlaceholder);
      continue;
    }
    const temporary = tempAllocator();
    const getQueryList = importExpr(Identifiers.loadQuery).callFn([]);
    const refresh = importExpr(Identifiers.queryRefresh).callFn([temporary.set(getQueryList)]);
    const updateDirective = variable(CONTEXT_NAME).prop(query.propertyName).set(query.first ? temporary.prop('first') : temporary);
    updateStatements.push(refresh.and(updateDirective).toStmt());
  }
  if (contentQuerySignalCall !== null) {
    createStatements.push(new ExpressionStatement(contentQuerySignalCall));
  }
  if (contentQueryCall !== null) {
    createStatements.push(new ExpressionStatement(contentQueryCall));
  }
  const contentQueriesFnName = name ? `${name}_ContentQueries` : null;
  return fn([new FnParam(RENDER_FLAGS, NUMBER_TYPE), new FnParam(CONTEXT_NAME, DYNAMIC_TYPE), new FnParam('dirIndex', NUMBER_TYPE)], [renderFlagCheckIfStmt(1, createStatements), renderFlagCheckIfStmt(2, collapseAdvanceStatements(updateStatements))], INFERRED_TYPE, null, contentQueriesFnName);
}

class HtmlParser extends Parser$1 {
  constructor() {
    super(getHtmlTagDefinition);
  }
  parse(source, url, options) {
    return super.parse(source, url, options);
  }
}

function isStyleUrlResolvable(url) {
  if (url == null || url.length === 0 || url[0] == '/') return false;
  const schemeMatch = url.match(URL_WITH_SCHEMA_REGEXP);
  return schemeMatch === null || schemeMatch[1] == 'package' || schemeMatch[1] == 'asset';
}
const URL_WITH_SCHEMA_REGEXP = /^([^:/?#]+):/;

const NG_CONTENT_SELECT_ATTR = 'select';
const LINK_ELEMENT = 'link';
const LINK_STYLE_REL_ATTR = 'rel';
const LINK_STYLE_HREF_ATTR = 'href';
const LINK_STYLE_REL_VALUE = 'stylesheet';
const STYLE_ELEMENT = 'style';
const SCRIPT_ELEMENTS = new Set([':math:script', ':svg:script', 'script']);
const NG_NON_BINDABLE_ATTR = 'ngNonBindable';
const NG_PROJECT_AS = 'ngProjectAs';
function preparseElement(ast) {
  let selectAttr = null;
  let hrefAttr = null;
  let relAttr = null;
  let nonBindable = false;
  let projectAs = '';
  for (const attr of ast.attrs) {
    const lcAttrName = attr.name.toLowerCase();
    if (lcAttrName == NG_CONTENT_SELECT_ATTR) {
      selectAttr = attr.value;
    } else if (lcAttrName == LINK_STYLE_HREF_ATTR) {
      hrefAttr = attr.value;
    } else if (lcAttrName == LINK_STYLE_REL_ATTR) {
      relAttr = attr.value;
    } else if (attr.name == NG_NON_BINDABLE_ATTR) {
      nonBindable = true;
    } else if (attr.name == NG_PROJECT_AS) {
      if (attr.value.length > 0) {
        projectAs = attr.value;
      }
    }
  }
  selectAttr ||= '*';
  const nodeName = ast.name.toLowerCase();
  let type = PreparsedElementType.OTHER;
  if (isNgContent(nodeName)) {
    type = PreparsedElementType.NG_CONTENT;
  } else if (STYLE_ELEMENT === nodeName) {
    type = PreparsedElementType.STYLE;
  } else if (SCRIPT_ELEMENTS.has(nodeName)) {
    type = PreparsedElementType.SCRIPT;
  } else if (nodeName == LINK_ELEMENT && relAttr == LINK_STYLE_REL_VALUE) {
    type = PreparsedElementType.STYLESHEET;
  }
  return new PreparsedElement(type, selectAttr, hrefAttr, nonBindable, projectAs);
}
var PreparsedElementType;
(function (PreparsedElementType) {
  PreparsedElementType[PreparsedElementType["NG_CONTENT"] = 0] = "NG_CONTENT";
  PreparsedElementType[PreparsedElementType["STYLE"] = 1] = "STYLE";
  PreparsedElementType[PreparsedElementType["STYLESHEET"] = 2] = "STYLESHEET";
  PreparsedElementType[PreparsedElementType["SCRIPT"] = 3] = "SCRIPT";
  PreparsedElementType[PreparsedElementType["OTHER"] = 4] = "OTHER";
})(PreparsedElementType || (PreparsedElementType = {}));
class PreparsedElement {
  type;
  selectAttr;
  hrefAttr;
  nonBindable;
  projectAs;
  constructor(type, selectAttr, hrefAttr, nonBindable, projectAs) {
    this.type = type;
    this.selectAttr = selectAttr;
    this.hrefAttr = hrefAttr;
    this.nonBindable = nonBindable;
    this.projectAs = projectAs;
  }
}

function createContentBlock(ast, visitor) {
  const errors = [];
  if (ast.parameters.length < 1 || ast.parameters.length > 2) {
    errors.push(new ParseError(ast.startSourceSpan, '@content block must have one or two parameters, e.g. ' + '"@content(header)" or "@content(items; let item, index)"'));
    return {
      node: null,
      errors
    };
  }
  const nameParam = ast.parameters[0];
  const name = nameParam.expression.trim();
  if (name.includes(',')) {
    errors.push(new ParseError(ast.startSourceSpan, '@content block must have exactly one name parameter'));
    return {
      node: null,
      errors
    };
  }
  if (!IDENTIFIER_PATTERN.test(name)) {
    errors.push(new ParseError(nameParam.sourceSpan, '@content name must be a valid JavaScript identifier'));
    return {
      node: null,
      errors
    };
  }
  const variables = parseContentBlockVariables(ast, errors);
  if (variables === null) {
    return {
      node: null,
      errors
    };
  }
  const node = new ContentBlock(name, variables, visitAll(visitor, ast.children, ast.children), ast.nameSpan, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan, ast.i18n);
  return {
    node,
    errors
  };
}
function parseContentBlockVariables(ast, errors) {
  const variables = [];
  if (ast.parameters.length < 2) {
    return variables;
  }
  const varsParam = ast.parameters[1];
  const varsExpr = varsParam.expression.trim();
  const letMatch = varsExpr.match(LET_PATTERN);
  if (!letMatch) {
    errors.push(new ParseError(varsParam.sourceSpan, '@content block variables must start with "let", e.g. "let item, index"'));
    return null;
  }
  const varNames = letMatch[1].split(',').map(v => v.trim());
  const variablesRawString = letMatch[1];
  const variablesStartOffset = varsParam.expression.indexOf(variablesRawString);
  const variablesStartLocation = varsParam.sourceSpan.start.moveBy(variablesStartOffset);
  let searchIndex = 0;
  for (let varName of varNames) {
    if (varName === '') {
      errors.push(new ParseError(varsParam.sourceSpan, 'Invalid variable name in @content block'));
      continue;
    }
    let varSpan;
    const index = variablesRawString.indexOf(varName, searchIndex);
    const varStart = variablesStartLocation.moveBy(index);
    if (varName.includes('=')) {
      const eqIndex = varName.indexOf('=');
      const namePart = varName.substring(0, eqIndex).trim();
      const fullVarSpan = new ParseSourceSpan(varStart, varStart.moveBy(varName.length));
      errors.push(new ParseError(fullVarSpan, `@content block variables cannot be assigned a value`));
      varName = namePart;
      varSpan = new ParseSourceSpan(varStart, varStart.moveBy(varName.length));
    } else {
      varSpan = new ParseSourceSpan(varStart, varStart.moveBy(varName.length));
    }
    if (!IDENTIFIER_PATTERN.test(varName)) {
      errors.push(new ParseError(varSpan, `Variable name "${varName}" must be a valid JavaScript identifier`));
      searchIndex = index + varName.length;
      continue;
    }
    if (variables.some(v => v.name === varName)) {
      errors.push(new ParseError(varSpan, `Duplicate variable name "${varName}" in @content block`));
      searchIndex = index + varName.length;
      continue;
    }
    variables.push(new Variable(varName, '', varSpan, varSpan));
    searchIndex = index + varName.length;
  }
  return variables;
}

const FOR_LOOP_EXPRESSION_PATTERN = /^\s*([0-9A-Za-z_$]*)\s+of\s+([\S\s]*)/;
const FOR_LOOP_TRACK_PATTERN = /^track\s+([\S\s]*)/;
const CONDITIONAL_ALIAS_PATTERN = /^(as\s+)(.*)/;
const CHARACTERS_IN_SURROUNDING_WHITESPACE_PATTERN = /(\s*)(\S+)(\s*)/;
const ALLOWED_FOR_LOOP_LET_VARIABLES = new Set(['$index', '$first', '$last', '$even', '$odd', '$count']);
function isConnectedForLoopBlock(name) {
  return name === 'empty';
}
function isConnectedIfLoopBlock(name) {
  return name === 'else' || name === 'else if';
}
function createIfBlock(ast, connectedBlocks, visitor, bindingParser) {
  const errors = validateIfConnectedBlocks(connectedBlocks);
  const branches = [];
  const mainBlockParams = parseConditionalBlockParameters(ast, errors, bindingParser);
  if (mainBlockParams !== null) {
    branches.push(new IfBlockBranch(mainBlockParams.expression, visitAll(visitor, ast.children, ast.children), mainBlockParams.expressionAlias, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan, ast.nameSpan, ast.i18n));
  }
  for (const block of connectedBlocks) {
    if (block.name === 'else if') {
      const params = parseConditionalBlockParameters(block, errors, bindingParser);
      if (params !== null) {
        const children = visitAll(visitor, block.children, block.children);
        branches.push(new IfBlockBranch(params.expression, children, params.expressionAlias, block.sourceSpan, block.startSourceSpan, block.endSourceSpan, block.nameSpan, block.i18n));
      }
    } else if (block.name === 'else') {
      const children = visitAll(visitor, block.children, block.children);
      branches.push(new IfBlockBranch(null, children, null, block.sourceSpan, block.startSourceSpan, block.endSourceSpan, block.nameSpan, block.i18n));
    }
  }
  const ifBlockStartSourceSpan = branches.length > 0 ? branches[0].startSourceSpan : ast.startSourceSpan;
  const ifBlockEndSourceSpan = branches.length > 0 ? branches[branches.length - 1].endSourceSpan : ast.endSourceSpan;
  let wholeSourceSpan = ast.sourceSpan;
  const lastBranch = branches[branches.length - 1];
  if (lastBranch !== undefined) {
    wholeSourceSpan = new ParseSourceSpan(ifBlockStartSourceSpan.start, lastBranch.sourceSpan.end);
  }
  return {
    node: new IfBlock(branches, wholeSourceSpan, ast.startSourceSpan, ifBlockEndSourceSpan, ast.nameSpan),
    errors
  };
}
function createForLoop(ast, connectedBlocks, visitor, bindingParser) {
  const errors = [];
  const params = parseForLoopParameters(ast, errors, bindingParser);
  let node = null;
  let empty = null;
  for (const block of connectedBlocks) {
    if (block.name === 'empty') {
      if (empty !== null) {
        errors.push(new ParseError(block.sourceSpan, '@for loop can only have one @empty block'));
      } else if (block.parameters.length > 0) {
        errors.push(new ParseError(block.sourceSpan, '@empty block cannot have parameters'));
      } else {
        empty = new ForLoopBlockEmpty(visitAll(visitor, block.children, block.children), block.sourceSpan, block.startSourceSpan, block.endSourceSpan, block.nameSpan, block.i18n);
      }
    } else {
      errors.push(new ParseError(block.sourceSpan, `Unrecognized @for loop block "${block.name}"`));
    }
  }
  if (params !== null) {
    const endSpan = empty?.endSourceSpan ?? ast.endSourceSpan;
    const sourceSpan = new ParseSourceSpan(ast.sourceSpan.start, endSpan?.end ?? ast.sourceSpan.end);
    let trackExpression;
    let trackKeywordSpan;
    if (params.trackBy === null) {
      trackExpression = trackKeywordSpan = null;
      errors.push(new ParseError(ast.startSourceSpan, '@for loop must have a "track" expression'));
    } else {
      trackExpression = params.trackBy.expression;
      trackKeywordSpan = params.trackBy.keywordSpan;
      validateTrackByExpression(params.trackBy.expression, params.trackBy.keywordSpan, errors);
    }
    node = new ForLoopBlock(params.itemName, params.expression, trackExpression, trackKeywordSpan, params.context, visitAll(visitor, ast.children, ast.children), empty, sourceSpan, ast.sourceSpan, ast.startSourceSpan, endSpan, ast.nameSpan, ast.i18n);
  }
  return {
    node,
    errors
  };
}
function createSwitchBlock(ast, visitor, bindingParser) {
  const errors = validateSwitchBlock(ast);
  const primaryExpression = ast.parameters.length > 0 ? parseBlockParameterToBinding(ast.parameters[0], bindingParser) : bindingParser.parseBinding('', false, ast.sourceSpan, 0);
  const groups = [];
  const unknownBlocks = [];
  let collectedCases = [];
  let firstCaseStart = null;
  let exhaustiveCheck = null;
  for (const node of ast.children) {
    if (!(node instanceof Block)) {
      continue;
    }
    if ((node.name !== 'case' || node.parameters.length === 0) && node.name !== 'default' && node.name !== 'default never') {
      unknownBlocks.push(new UnknownBlock(node.name, node.sourceSpan, node.nameSpan));
      continue;
    }
    if (exhaustiveCheck !== null) {
      errors.push(new ParseError(node.sourceSpan, '@default block with "never" parameter must be the last case in a switch'));
    }
    const isCase = node.name === 'case';
    let expression = null;
    if (isCase) {
      expression = parseBlockParameterToBinding(node.parameters[0], bindingParser);
    } else if (node.name === 'default never') {
      if (node.parameters.length > 0) {
        expression = parseBlockParameterToBinding(node.parameters[0], bindingParser);
      }
      if (node.children.length > 0 || node.endSourceSpan !== null && node.endSourceSpan.start.offset !== node.endSourceSpan.end.offset) {
        errors.push(new ParseError(node.sourceSpan, '@default block with "never" parameter cannot have a body'));
      }
      if (collectedCases.length > 0) {
        errors.push(new ParseError(node.sourceSpan, 'A @case block with no body cannot be followed by a @default block with "never" parameter'));
      }
      exhaustiveCheck = new SwitchExhaustiveCheck(expression, node.sourceSpan, node.startSourceSpan, node.endSourceSpan, node.nameSpan);
      continue;
    }
    const switchCase = new SwitchBlockCase(expression, node.sourceSpan, node.startSourceSpan, node.endSourceSpan, node.nameSpan);
    collectedCases.push(switchCase);
    const caseWithoutBody = node.children.length === 0 && node.endSourceSpan !== null && node.endSourceSpan.start.offset === node.endSourceSpan.end.offset;
    if (caseWithoutBody) {
      if (firstCaseStart === null) {
        firstCaseStart = node.sourceSpan;
      }
      continue;
    }
    let sourceSpan = node.sourceSpan;
    let startSourceSpan = node.startSourceSpan;
    if (firstCaseStart !== null) {
      sourceSpan = new ParseSourceSpan(firstCaseStart.start, node.sourceSpan.end);
      startSourceSpan = new ParseSourceSpan(firstCaseStart.start, node.startSourceSpan.end);
      firstCaseStart = null;
    }
    const group = new SwitchBlockCaseGroup(collectedCases, visitAll(visitor, node.children, node.children), sourceSpan, startSourceSpan, node.endSourceSpan, node.nameSpan, node.i18n);
    groups.push(group);
    collectedCases = [];
  }
  const node = new SwitchBlock(primaryExpression, groups, unknownBlocks, exhaustiveCheck, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan, ast.nameSpan);
  return {
    node,
    errors
  };
}
function parseForLoopParameters(block, errors, bindingParser) {
  if (block.parameters.length === 0) {
    errors.push(new ParseError(block.startSourceSpan, '@for loop does not have an expression'));
    return null;
  }
  const [expressionParam, ...secondaryParams] = block.parameters;
  const match = stripOptionalParentheses(expressionParam, errors)?.match(FOR_LOOP_EXPRESSION_PATTERN);
  if (!match || match[2].trim().length === 0) {
    errors.push(new ParseError(expressionParam.sourceSpan, 'Cannot parse expression. @for loop expression must match the pattern "<identifier> of <expression>"'));
    return null;
  }
  const [, itemName, rawExpression] = match;
  if (ALLOWED_FOR_LOOP_LET_VARIABLES.has(itemName)) {
    errors.push(new ParseError(expressionParam.sourceSpan, `@for loop item name cannot be one of ${Array.from(ALLOWED_FOR_LOOP_LET_VARIABLES).join(', ')}.`));
  }
  const variableName = expressionParam.expression.split(' ')[0];
  const variableSpan = new ParseSourceSpan(expressionParam.sourceSpan.start, expressionParam.sourceSpan.start.moveBy(variableName.length));
  const result = {
    itemName: new Variable(itemName, '$implicit', variableSpan, variableSpan),
    trackBy: null,
    expression: parseBlockParameterToBinding(expressionParam, bindingParser, rawExpression),
    context: Array.from(ALLOWED_FOR_LOOP_LET_VARIABLES, variableName => {
      const emptySpanAfterForBlockStart = new ParseSourceSpan(block.startSourceSpan.end, block.startSourceSpan.end);
      return new Variable(variableName, variableName, emptySpanAfterForBlockStart, emptySpanAfterForBlockStart);
    })
  };
  for (const param of secondaryParams) {
    const letMatch = param.expression.match(LET_PATTERN);
    if (letMatch !== null) {
      const variablesSpan = new ParseSourceSpan(param.sourceSpan.start.moveBy(letMatch[0].length - letMatch[1].length), param.sourceSpan.end);
      parseLetParameter(param.sourceSpan, letMatch[1], variablesSpan, itemName, result.context, errors);
      continue;
    }
    const trackMatch = param.expression.match(FOR_LOOP_TRACK_PATTERN);
    if (trackMatch !== null) {
      if (result.trackBy !== null) {
        errors.push(new ParseError(param.sourceSpan, '@for loop can only have one "track" expression'));
      } else {
        const expression = parseBlockParameterToBinding(param, bindingParser, trackMatch[1]);
        if (expression.ast instanceof EmptyExpr$1) {
          errors.push(new ParseError(block.startSourceSpan, '@for loop must have a "track" expression'));
        }
        const keywordSpan = new ParseSourceSpan(param.sourceSpan.start, param.sourceSpan.start.moveBy('track'.length));
        result.trackBy = {
          expression,
          keywordSpan
        };
      }
      continue;
    }
    errors.push(new ParseError(param.sourceSpan, `Unrecognized @for loop parameter "${param.expression}"`));
  }
  return result;
}
function validateTrackByExpression(expression, parseSourceSpan, errors) {
  const visitor = new PipeVisitor();
  expression.ast.visit(visitor);
  if (visitor.hasPipe) {
    errors.push(new ParseError(parseSourceSpan, 'Cannot use pipes in track expressions'));
  }
}
function parseLetParameter(sourceSpan, expression, span, loopItemName, context, errors) {
  const parts = expression.split(',');
  let startSpan = span.start;
  for (const part of parts) {
    const expressionParts = part.split('=');
    const name = expressionParts.length === 2 ? expressionParts[0].trim() : '';
    const variableName = expressionParts.length === 2 ? expressionParts[1].trim() : '';
    if (name.length === 0 || variableName.length === 0) {
      errors.push(new ParseError(sourceSpan, `Invalid @for loop "let" parameter. Parameter should match the pattern "<name> = <variable name>"`));
    } else if (!ALLOWED_FOR_LOOP_LET_VARIABLES.has(variableName)) {
      errors.push(new ParseError(sourceSpan, `Unknown "let" parameter variable "${variableName}". The allowed variables are: ${Array.from(ALLOWED_FOR_LOOP_LET_VARIABLES).join(', ')}`));
    } else if (name === loopItemName) {
      errors.push(new ParseError(sourceSpan, `Invalid @for loop "let" parameter. Variable cannot be called "${loopItemName}"`));
    } else if (context.some(v => v.name === name)) {
      errors.push(new ParseError(sourceSpan, `Duplicate "let" parameter variable "${variableName}"`));
    } else {
      const [, keyLeadingWhitespace, keyName] = expressionParts[0].match(CHARACTERS_IN_SURROUNDING_WHITESPACE_PATTERN) ?? [];
      const keySpan = keyLeadingWhitespace !== undefined && expressionParts.length === 2 ? new ParseSourceSpan(startSpan.moveBy(keyLeadingWhitespace.length), startSpan.moveBy(keyLeadingWhitespace.length + keyName.length)) : span;
      let valueSpan = undefined;
      if (expressionParts.length === 2) {
        const [, valueLeadingWhitespace, implicit] = expressionParts[1].match(CHARACTERS_IN_SURROUNDING_WHITESPACE_PATTERN) ?? [];
        valueSpan = valueLeadingWhitespace !== undefined ? new ParseSourceSpan(startSpan.moveBy(expressionParts[0].length + 1 + valueLeadingWhitespace.length), startSpan.moveBy(expressionParts[0].length + 1 + valueLeadingWhitespace.length + implicit.length)) : undefined;
      }
      const sourceSpan = new ParseSourceSpan(keySpan.start, valueSpan?.end ?? keySpan.end);
      context.push(new Variable(name, variableName, sourceSpan, keySpan, valueSpan));
    }
    startSpan = startSpan.moveBy(part.length + 1);
  }
}
function validateIfConnectedBlocks(connectedBlocks) {
  const errors = [];
  let hasElse = false;
  for (let i = 0; i < connectedBlocks.length; i++) {
    const block = connectedBlocks[i];
    if (block.name === 'else') {
      if (hasElse) {
        errors.push(new ParseError(block.startSourceSpan, 'Conditional can only have one @else block'));
      } else if (connectedBlocks.length > 1 && i < connectedBlocks.length - 1) {
        errors.push(new ParseError(block.startSourceSpan, '@else block must be last inside the conditional'));
      } else if (block.parameters.length > 0) {
        errors.push(new ParseError(block.startSourceSpan, '@else block cannot have parameters'));
      }
      hasElse = true;
    } else if (block.name !== 'else if') {
      errors.push(new ParseError(block.startSourceSpan, `Unrecognized conditional block @${block.name}`));
    }
  }
  return errors;
}
function validateSwitchBlock(ast) {
  const errors = [];
  let hasDefault = false;
  if (ast.parameters.length !== 1) {
    errors.push(new ParseError(ast.startSourceSpan, '@switch block must have exactly one parameter'));
    return errors;
  }
  for (const node of ast.children) {
    if (node instanceof Comment || node instanceof Text && node.value.trim().length === 0) {
      continue;
    }
    if (!(node instanceof Block) || node.name !== 'case' && node.name !== 'default' && node.name !== 'default never') {
      errors.push(new ParseError(node.sourceSpan, '@switch block can only contain @case and @default blocks'));
      continue;
    }
    if (node.name === 'default never') {
      if (hasDefault) {
        errors.push(new ParseError(node.startSourceSpan, '@switch block can only have one @default block'));
      }
      hasDefault = true;
    } else if (node.name === 'default') {
      if (hasDefault) {
        errors.push(new ParseError(node.startSourceSpan, '@switch block can only have one @default block'));
      } else if (node.parameters.length > 0) {
        errors.push(new ParseError(node.startSourceSpan, '@default block cannot have parameters'));
      }
      hasDefault = true;
    } else if (node.name === 'case' && node.parameters.length !== 1) {
      errors.push(new ParseError(node.startSourceSpan, '@case block must have exactly one parameter'));
    }
  }
  return errors;
}
function parseBlockParameterToBinding(ast, bindingParser, part) {
  let start;
  let end;
  if (typeof part === 'string') {
    start = Math.max(0, ast.expression.lastIndexOf(part));
    end = start + part.length;
  } else {
    start = 0;
    end = ast.expression.length;
  }
  return bindingParser.parseBinding(ast.expression.slice(start, end), false, ast.sourceSpan, ast.sourceSpan.start.offset + start);
}
function parseConditionalBlockParameters(block, errors, bindingParser) {
  if (block.parameters.length === 0) {
    errors.push(new ParseError(block.startSourceSpan, 'Conditional block does not have an expression'));
    return null;
  }
  const expression = parseBlockParameterToBinding(block.parameters[0], bindingParser);
  let expressionAlias = null;
  for (let i = 1; i < block.parameters.length; i++) {
    const param = block.parameters[i];
    const aliasMatch = param.expression.match(CONDITIONAL_ALIAS_PATTERN);
    if (aliasMatch === null) {
      errors.push(new ParseError(param.sourceSpan, `Unrecognized conditional parameter "${param.expression}"`));
    } else if (block.name !== 'if' && block.name !== 'else if') {
      errors.push(new ParseError(param.sourceSpan, '"as" expression is only allowed on `@if` and `@else if` blocks'));
    } else if (expressionAlias !== null) {
      errors.push(new ParseError(param.sourceSpan, 'Conditional can only have one "as" expression'));
    } else {
      const name = aliasMatch[2].trim();
      if (IDENTIFIER_PATTERN.test(name)) {
        const variableStart = param.sourceSpan.start.moveBy(aliasMatch[1].length);
        const variableSpan = new ParseSourceSpan(variableStart, variableStart.moveBy(name.length));
        expressionAlias = new Variable(name, name, variableSpan, variableSpan);
      } else {
        errors.push(new ParseError(param.sourceSpan, '"as" expression must be a valid JavaScript identifier'));
      }
    }
  }
  return {
    expression,
    expressionAlias
  };
}
function stripOptionalParentheses(param, errors) {
  const expression = param.expression;
  const spaceRegex = /^\s$/;
  let openParens = 0;
  let start = 0;
  let end = expression.length - 1;
  for (let i = 0; i < expression.length; i++) {
    const char = expression[i];
    if (char === '(') {
      start = i + 1;
      openParens++;
    } else if (spaceRegex.test(char)) {
      continue;
    } else {
      break;
    }
  }
  if (openParens === 0) {
    return expression;
  }
  for (let i = expression.length - 1; i > -1; i--) {
    const char = expression[i];
    if (char === ')') {
      end = i;
      openParens--;
      if (openParens === 0) {
        break;
      }
    } else if (spaceRegex.test(char)) {
      continue;
    } else {
      break;
    }
  }
  if (openParens !== 0) {
    errors.push(new ParseError(param.sourceSpan, 'Unclosed parentheses in expression'));
    return null;
  }
  return expression.slice(start, end);
}
class PipeVisitor extends RecursiveAstVisitor {
  hasPipe = false;
  visitPipe() {
    this.hasPipe = true;
  }
}

const TIME_PATTERN = /^\d+\.?\d*(ms|s)?$/;
const SEPARATOR_PATTERN = /^\s$/;
const COMMA_DELIMITED_SYNTAX = new Map([[$LBRACE, $RBRACE], [$LBRACKET, $RBRACKET], [$LPAREN, $RPAREN]]);
var OnTriggerType;
(function (OnTriggerType) {
  OnTriggerType["IDLE"] = "idle";
  OnTriggerType["TIMER"] = "timer";
  OnTriggerType["INTERACTION"] = "interaction";
  OnTriggerType["IMMEDIATE"] = "immediate";
  OnTriggerType["HOVER"] = "hover";
  OnTriggerType["VIEWPORT"] = "viewport";
  OnTriggerType["NEVER"] = "never";
})(OnTriggerType || (OnTriggerType = {}));
function parseNeverTrigger({
  expression,
  sourceSpan
}, triggers, errors) {
  const neverIndex = expression.indexOf('never');
  const neverSourceSpan = new ParseSourceSpan(sourceSpan.start.moveBy(neverIndex), sourceSpan.start.moveBy(neverIndex + 'never'.length));
  const prefetchSpan = getPrefetchSpan(expression, sourceSpan);
  const hydrateSpan = getHydrateSpan(expression, sourceSpan);
  if (neverIndex === -1) {
    errors.push(new ParseError(sourceSpan, `Could not find "never" keyword in expression`));
  } else {
    trackTrigger('never', triggers, errors, new NeverDeferredTrigger(neverSourceSpan, sourceSpan, prefetchSpan, null, hydrateSpan));
  }
}
function parseWhenTrigger({
  expression,
  sourceSpan
}, bindingParser, triggers, errors) {
  const whenIndex = expression.indexOf('when');
  const whenSourceSpan = new ParseSourceSpan(sourceSpan.start.moveBy(whenIndex), sourceSpan.start.moveBy(whenIndex + 'when'.length));
  const prefetchSpan = getPrefetchSpan(expression, sourceSpan);
  const hydrateSpan = getHydrateSpan(expression, sourceSpan);
  if (whenIndex === -1) {
    errors.push(new ParseError(sourceSpan, `Could not find "when" keyword in expression`));
  } else {
    const start = getTriggerParametersStart(expression, whenIndex + 1);
    const parsed = bindingParser.parseBinding(expression.slice(start), false, sourceSpan, sourceSpan.start.offset + start);
    trackTrigger('when', triggers, errors, new BoundDeferredTrigger(parsed, sourceSpan, prefetchSpan, whenSourceSpan, hydrateSpan));
  }
}
function parseOnTrigger({
  expression,
  sourceSpan
}, bindingParser, triggers, errors, placeholder) {
  const onIndex = expression.indexOf('on');
  const onSourceSpan = new ParseSourceSpan(sourceSpan.start.moveBy(onIndex), sourceSpan.start.moveBy(onIndex + 'on'.length));
  const prefetchSpan = getPrefetchSpan(expression, sourceSpan);
  const hydrateSpan = getHydrateSpan(expression, sourceSpan);
  if (onIndex === -1) {
    errors.push(new ParseError(sourceSpan, `Could not find "on" keyword in expression`));
  } else {
    const start = getTriggerParametersStart(expression, onIndex + 1);
    const isHydrationTrigger = expression.startsWith('hydrate');
    const parser = new OnTriggerParser(expression, bindingParser, start, sourceSpan, triggers, errors, isHydrationTrigger ? validateHydrateReferenceBasedTrigger : validatePlainReferenceBasedTrigger, isHydrationTrigger, prefetchSpan, onSourceSpan, hydrateSpan);
    parser.parse();
  }
}
function getPrefetchSpan(expression, sourceSpan) {
  if (!expression.startsWith('prefetch')) {
    return null;
  }
  return new ParseSourceSpan(sourceSpan.start, sourceSpan.start.moveBy('prefetch'.length));
}
function getHydrateSpan(expression, sourceSpan) {
  if (!expression.startsWith('hydrate')) {
    return null;
  }
  return new ParseSourceSpan(sourceSpan.start, sourceSpan.start.moveBy('hydrate'.length));
}
class OnTriggerParser {
  expression;
  bindingParser;
  start;
  span;
  triggers;
  errors;
  validator;
  isHydrationTrigger;
  prefetchSpan;
  onSourceSpan;
  hydrateSpan;
  index = 0;
  tokens;
  constructor(expression, bindingParser, start, span, triggers, errors, validator, isHydrationTrigger, prefetchSpan, onSourceSpan, hydrateSpan) {
    this.expression = expression;
    this.bindingParser = bindingParser;
    this.start = start;
    this.span = span;
    this.triggers = triggers;
    this.errors = errors;
    this.validator = validator;
    this.isHydrationTrigger = isHydrationTrigger;
    this.prefetchSpan = prefetchSpan;
    this.onSourceSpan = onSourceSpan;
    this.hydrateSpan = hydrateSpan;
    this.tokens = new Lexer().tokenize(expression.slice(start));
  }
  parse() {
    while (this.tokens.length > 0 && this.index < this.tokens.length) {
      const token = this.token();
      if (!token.isIdentifier()) {
        this.unexpectedToken(token);
        break;
      }
      if (this.isFollowedByOrLast($COMMA)) {
        this.consumeTrigger(token, []);
        this.advance();
      } else if (this.isFollowedByOrLast($LPAREN)) {
        this.advance();
        const prevErrors = this.errors.length;
        const parameters = this.consumeParameters();
        if (this.errors.length !== prevErrors) {
          break;
        }
        this.consumeTrigger(token, parameters);
        this.advance();
      } else if (this.index < this.tokens.length - 1) {
        this.unexpectedToken(this.tokens[this.index + 1]);
      }
      this.advance();
    }
  }
  advance() {
    this.index++;
  }
  isFollowedByOrLast(char) {
    if (this.index === this.tokens.length - 1) {
      return true;
    }
    return this.tokens[this.index + 1].isCharacter(char);
  }
  token() {
    return this.tokens[Math.min(this.index, this.tokens.length - 1)];
  }
  consumeTrigger(identifier, parameters) {
    const triggerNameStartSpan = this.span.start.moveBy(this.start + identifier.index - this.tokens[0].index);
    const nameSpan = new ParseSourceSpan(triggerNameStartSpan, triggerNameStartSpan.moveBy(identifier.strValue.length));
    const endSpan = triggerNameStartSpan.moveBy(this.token().end - identifier.index);
    const isFirstTrigger = identifier.index === 0;
    const onSourceSpan = isFirstTrigger ? this.onSourceSpan : null;
    const prefetchSourceSpan = isFirstTrigger ? this.prefetchSpan : null;
    const hydrateSourceSpan = isFirstTrigger ? this.hydrateSpan : null;
    const sourceSpan = new ParseSourceSpan(isFirstTrigger ? this.span.start : triggerNameStartSpan, endSpan);
    try {
      switch (identifier.toString()) {
        case OnTriggerType.IDLE:
          this.trackTrigger('idle', createIdleTrigger(parameters, nameSpan, sourceSpan, prefetchSourceSpan, onSourceSpan, hydrateSourceSpan));
          break;
        case OnTriggerType.TIMER:
          this.trackTrigger('timer', createTimerTrigger(parameters, nameSpan, sourceSpan, this.prefetchSpan, this.onSourceSpan, this.hydrateSpan));
          break;
        case OnTriggerType.INTERACTION:
          this.trackTrigger('interaction', createInteractionTrigger(parameters, nameSpan, sourceSpan, this.prefetchSpan, this.onSourceSpan, this.hydrateSpan, this.validator));
          break;
        case OnTriggerType.IMMEDIATE:
          this.trackTrigger('immediate', createImmediateTrigger(parameters, nameSpan, sourceSpan, this.prefetchSpan, this.onSourceSpan, this.hydrateSpan));
          break;
        case OnTriggerType.HOVER:
          this.trackTrigger('hover', createHoverTrigger(parameters, nameSpan, sourceSpan, this.prefetchSpan, this.onSourceSpan, this.hydrateSpan, this.validator));
          break;
        case OnTriggerType.VIEWPORT:
          this.trackTrigger('viewport', createViewportTrigger(this.start, this.isHydrationTrigger, this.bindingParser, parameters, nameSpan, sourceSpan, this.prefetchSpan, this.onSourceSpan, this.hydrateSpan, this.validator));
          break;
        default:
          throw new Error(`Unrecognized trigger type "${identifier}"`);
      }
    } catch (e) {
      this.error(identifier, e.message);
    }
  }
  consumeParameters() {
    const parameters = [];
    if (!this.token().isCharacter($LPAREN)) {
      this.unexpectedToken(this.token());
      return parameters;
    }
    this.advance();
    const commaDelimStack = [];
    let tokens = [];
    while (this.index < this.tokens.length) {
      const token = this.token();
      if (token.isCharacter($RPAREN) && commaDelimStack.length === 0) {
        if (tokens.length) {
          parameters.push({
            expression: this.tokenRangeText(tokens),
            start: tokens[0].index
          });
        }
        break;
      }
      if (token.type === TokenType.Character && COMMA_DELIMITED_SYNTAX.has(token.numValue)) {
        commaDelimStack.push(COMMA_DELIMITED_SYNTAX.get(token.numValue));
      }
      if (commaDelimStack.length > 0 && token.isCharacter(commaDelimStack[commaDelimStack.length - 1])) {
        commaDelimStack.pop();
      }
      if (commaDelimStack.length === 0 && token.isCharacter($COMMA) && tokens.length > 0) {
        parameters.push({
          expression: this.tokenRangeText(tokens),
          start: tokens[0].index
        });
        this.advance();
        tokens = [];
        continue;
      }
      tokens.push(token);
      this.advance();
    }
    if (!this.token().isCharacter($RPAREN) || commaDelimStack.length > 0) {
      this.error(this.token(), 'Unexpected end of expression');
    }
    if (this.index < this.tokens.length - 1 && !this.tokens[this.index + 1].isCharacter($COMMA)) {
      this.unexpectedToken(this.tokens[this.index + 1]);
    }
    return parameters;
  }
  tokenRangeText(tokens) {
    if (tokens.length === 0) {
      return '';
    }
    return this.expression.slice(this.start + tokens[0].index, this.start + tokens[tokens.length - 1].end);
  }
  trackTrigger(name, trigger) {
    trackTrigger(name, this.triggers, this.errors, trigger);
  }
  error(token, message) {
    const newStart = this.span.start.moveBy(this.start + token.index);
    const newEnd = newStart.moveBy(token.end - token.index);
    this.errors.push(new ParseError(new ParseSourceSpan(newStart, newEnd), message));
  }
  unexpectedToken(token) {
    this.error(token, `Unexpected token "${token}"`);
  }
}
function trackTrigger(name, allTriggers, errors, trigger) {
  if (allTriggers[name]) {
    errors.push(new ParseError(trigger.sourceSpan, `Duplicate "${name}" trigger is not allowed`));
  } else {
    allTriggers[name] = trigger;
  }
}
function createIdleTrigger(parameters, nameSpan, sourceSpan, prefetchSpan, onSourceSpan, hydrateSpan) {
  if (parameters.length > 1) {
    throw new Error(`"${OnTriggerType.IDLE}" trigger can only have zero or one parameters`);
  }
  let timeout = null;
  if (parameters[0]) {
    timeout = parseDeferredTime(parameters[0].expression);
    if (timeout === null) {
      throw new Error(`Could not parse time value of trigger "${OnTriggerType.IDLE}"`);
    }
  }
  return new IdleDeferredTrigger(nameSpan, sourceSpan, prefetchSpan, onSourceSpan, hydrateSpan, timeout);
}
function createTimerTrigger(parameters, nameSpan, sourceSpan, prefetchSpan, onSourceSpan, hydrateSpan) {
  if (parameters.length !== 1) {
    throw new Error(`"${OnTriggerType.TIMER}" trigger must have exactly one parameter`);
  }
  const delay = parseDeferredTime(parameters[0].expression);
  if (delay === null) {
    throw new Error(`Could not parse time value of trigger "${OnTriggerType.TIMER}"`);
  }
  return new TimerDeferredTrigger(delay, nameSpan, sourceSpan, prefetchSpan, onSourceSpan, hydrateSpan);
}
function createImmediateTrigger(parameters, nameSpan, sourceSpan, prefetchSpan, onSourceSpan, hydrateSpan) {
  if (parameters.length > 0) {
    throw new Error(`"${OnTriggerType.IMMEDIATE}" trigger cannot have parameters`);
  }
  return new ImmediateDeferredTrigger(nameSpan, sourceSpan, prefetchSpan, onSourceSpan, hydrateSpan);
}
function createHoverTrigger(parameters, nameSpan, sourceSpan, prefetchSpan, onSourceSpan, hydrateSpan, validator) {
  validator(OnTriggerType.HOVER, parameters);
  return new HoverDeferredTrigger(parameters[0]?.expression ?? null, nameSpan, sourceSpan, prefetchSpan, onSourceSpan, hydrateSpan);
}
function createInteractionTrigger(parameters, nameSpan, sourceSpan, prefetchSpan, onSourceSpan, hydrateSpan, validator) {
  validator(OnTriggerType.INTERACTION, parameters);
  return new InteractionDeferredTrigger(parameters[0]?.expression ?? null, nameSpan, sourceSpan, prefetchSpan, onSourceSpan, hydrateSpan);
}
function createViewportTrigger(start, isHydrationTrigger, bindingParser, parameters, nameSpan, sourceSpan, prefetchSpan, onSourceSpan, hydrateSpan, validator) {
  validator(OnTriggerType.VIEWPORT, parameters);
  let reference;
  let options;
  if (parameters.length === 0) {
    reference = options = null;
  } else if (!parameters[0].expression.startsWith('{')) {
    reference = parameters[0].expression;
    options = null;
  } else {
    const parsed = bindingParser.parseBinding(parameters[0].expression, false, sourceSpan, sourceSpan.start.offset + start + parameters[0].start);
    if (!(parsed.ast instanceof LiteralMap)) {
      throw new Error('Options parameter of the "viewport" trigger must be an object literal');
    } else if (parsed.ast.keys.some(key => key.kind === 'spread')) {
      throw new Error('Spread operator are not allowed in this context');
    } else if (parsed.ast.keys.some(key => key.kind === 'property' && key.key === 'root')) {
      throw new Error('The "root" option is not supported in the options parameter of the "viewport" trigger');
    }
    const triggerIndex = parsed.ast.keys.findIndex(key => key.kind === 'property' && key.key === 'trigger');
    if (triggerIndex === -1) {
      reference = null;
      options = parsed.ast;
    } else {
      const value = parsed.ast.values[triggerIndex];
      const triggerFilter = (_, index) => index !== triggerIndex;
      if (!(value instanceof PropertyRead) || !(value.receiver instanceof ImplicitReceiver)) {
        throw new Error(`"trigger" option of the "viewport" trigger must be an identifier`);
      }
      reference = value.name;
      options = new LiteralMap(parsed.ast.span, parsed.ast.sourceSpan, parsed.ast.keys.filter(triggerFilter), parsed.ast.values.filter(triggerFilter));
    }
  }
  if (isHydrationTrigger && reference !== null) {
    throw new Error(`"viewport" hydration trigger cannot have a "trigger"`);
  } else if (options) {
    const dynamicNode = DynamicAstValidator.findDynamicNode(options);
    if (dynamicNode !== null) {
      throw new Error(`Options of the "viewport" trigger must be an object ` + `literal containing only literal values, but "${dynamicNode.constructor.name}" was found`);
    }
  }
  return new ViewportDeferredTrigger(reference, options, nameSpan, sourceSpan, prefetchSpan, onSourceSpan, hydrateSpan);
}
function validatePlainReferenceBasedTrigger(type, parameters) {
  if (parameters.length > 1) {
    throw new Error(`"${type}" trigger can only have zero or one parameters`);
  }
}
function validateHydrateReferenceBasedTrigger(type, parameters) {
  if (type === OnTriggerType.VIEWPORT) {
    if (parameters.length > 1) {
      throw new Error(`Hydration trigger "${type}" cannot have more than one parameter`);
    }
    return;
  }
  if (parameters.length > 0) {
    throw new Error(`Hydration trigger "${type}" cannot have parameters`);
  }
}
function getTriggerParametersStart(value, startPosition = 0) {
  let hasFoundSeparator = false;
  for (let i = startPosition; i < value.length; i++) {
    if (SEPARATOR_PATTERN.test(value[i])) {
      hasFoundSeparator = true;
    } else if (hasFoundSeparator) {
      return i;
    }
  }
  return -1;
}
function parseDeferredTime(value) {
  const match = value.match(TIME_PATTERN);
  if (!match) {
    return null;
  }
  const [time, units] = match;
  return parseFloat(time) * (units === 's' ? 1000 : 1);
}
class DynamicAstValidator extends RecursiveAstVisitor {
  dynamicNode = null;
  static findDynamicNode(ast) {
    const visitor = new DynamicAstValidator();
    visitor.visit(ast);
    return visitor.dynamicNode;
  }
  visit(ast) {
    if (!(ast instanceof ASTWithSource) && !(ast instanceof LiteralPrimitive) && !(ast instanceof LiteralArray) && !(ast instanceof LiteralMap)) {
      this.dynamicNode = ast;
    } else {
      super.visit(ast);
    }
  }
}

const PREFETCH_WHEN_PATTERN = /^prefetch\s+when\s/;
const PREFETCH_ON_PATTERN = /^prefetch\s+on\s/;
const HYDRATE_WHEN_PATTERN = /^hydrate\s+when\s/;
const HYDRATE_ON_PATTERN = /^hydrate\s+on\s/;
const HYDRATE_NEVER_PATTERN = /^hydrate\s+never(\s*)$/;
const MINIMUM_PARAMETER_PATTERN = /^minimum\s/;
const AFTER_PARAMETER_PATTERN = /^after\s/;
const WHEN_PARAMETER_PATTERN = /^when\s/;
const ON_PARAMETER_PATTERN = /^on\s/;
function isConnectedDeferLoopBlock(name) {
  return name === 'placeholder' || name === 'loading' || name === 'error';
}
function createDeferredBlock(ast, connectedBlocks, visitor, bindingParser) {
  const errors = [];
  const {
    placeholder,
    loading,
    error
  } = parseConnectedBlocks(connectedBlocks, errors, visitor);
  const {
    triggers,
    prefetchTriggers,
    hydrateTriggers
  } = parsePrimaryTriggers(ast, bindingParser, errors);
  let lastEndSourceSpan = ast.endSourceSpan;
  let endOfLastSourceSpan = ast.sourceSpan.end;
  if (connectedBlocks.length > 0) {
    const lastConnectedBlock = connectedBlocks[connectedBlocks.length - 1];
    lastEndSourceSpan = lastConnectedBlock.endSourceSpan;
    endOfLastSourceSpan = lastConnectedBlock.sourceSpan.end;
  }
  const sourceSpanWithConnectedBlocks = new ParseSourceSpan(ast.sourceSpan.start, endOfLastSourceSpan);
  const node = new DeferredBlock(visitAll(visitor, ast.children, ast.children), triggers, prefetchTriggers, hydrateTriggers, placeholder, loading, error, ast.nameSpan, sourceSpanWithConnectedBlocks, ast.sourceSpan, ast.startSourceSpan, lastEndSourceSpan, ast.i18n);
  return {
    node,
    errors
  };
}
function parseConnectedBlocks(connectedBlocks, errors, visitor) {
  let placeholder = null;
  let loading = null;
  let error = null;
  for (const block of connectedBlocks) {
    try {
      if (!isConnectedDeferLoopBlock(block.name)) {
        errors.push(new ParseError(block.startSourceSpan, `Unrecognized block "@${block.name}"`));
        break;
      }
      switch (block.name) {
        case 'placeholder':
          if (placeholder !== null) {
            errors.push(new ParseError(block.startSourceSpan, `@defer block can only have one @placeholder block`));
          } else {
            placeholder = parsePlaceholderBlock(block, visitor);
          }
          break;
        case 'loading':
          if (loading !== null) {
            errors.push(new ParseError(block.startSourceSpan, `@defer block can only have one @loading block`));
          } else {
            loading = parseLoadingBlock(block, visitor);
          }
          break;
        case 'error':
          if (error !== null) {
            errors.push(new ParseError(block.startSourceSpan, `@defer block can only have one @error block`));
          } else {
            error = parseErrorBlock(block, visitor);
          }
          break;
      }
    } catch (e) {
      errors.push(new ParseError(block.startSourceSpan, e.message));
    }
  }
  return {
    placeholder,
    loading,
    error
  };
}
function parsePlaceholderBlock(ast, visitor) {
  let minimumTime = null;
  for (const param of ast.parameters) {
    if (MINIMUM_PARAMETER_PATTERN.test(param.expression)) {
      if (minimumTime != null) {
        throw new Error(`@placeholder block can only have one "minimum" parameter`);
      }
      const parsedTime = parseDeferredTime(param.expression.slice(getTriggerParametersStart(param.expression)));
      if (parsedTime === null) {
        throw new Error(`Could not parse time value of parameter "minimum"`);
      }
      minimumTime = parsedTime;
    } else {
      throw new Error(`Unrecognized parameter in @placeholder block: "${param.expression}"`);
    }
  }
  return new DeferredBlockPlaceholder(visitAll(visitor, ast.children, ast.children), minimumTime, ast.nameSpan, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan, ast.i18n);
}
function parseLoadingBlock(ast, visitor) {
  let afterTime = null;
  let minimumTime = null;
  for (const param of ast.parameters) {
    if (AFTER_PARAMETER_PATTERN.test(param.expression)) {
      if (afterTime != null) {
        throw new Error(`@loading block can only have one "after" parameter`);
      }
      const parsedTime = parseDeferredTime(param.expression.slice(getTriggerParametersStart(param.expression)));
      if (parsedTime === null) {
        throw new Error(`Could not parse time value of parameter "after"`);
      }
      afterTime = parsedTime;
    } else if (MINIMUM_PARAMETER_PATTERN.test(param.expression)) {
      if (minimumTime != null) {
        throw new Error(`@loading block can only have one "minimum" parameter`);
      }
      const parsedTime = parseDeferredTime(param.expression.slice(getTriggerParametersStart(param.expression)));
      if (parsedTime === null) {
        throw new Error(`Could not parse time value of parameter "minimum"`);
      }
      minimumTime = parsedTime;
    } else {
      throw new Error(`Unrecognized parameter in @loading block: "${param.expression}"`);
    }
  }
  return new DeferredBlockLoading(visitAll(visitor, ast.children, ast.children), afterTime, minimumTime, ast.nameSpan, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan, ast.i18n);
}
function parseErrorBlock(ast, visitor) {
  if (ast.parameters.length > 0) {
    throw new Error(`@error block cannot have parameters`);
  }
  return new DeferredBlockError(visitAll(visitor, ast.children, ast.children), ast.nameSpan, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan, ast.i18n);
}
function parsePrimaryTriggers(ast, bindingParser, errors, placeholder) {
  const triggers = {};
  const prefetchTriggers = {};
  const hydrateTriggers = {};
  for (const param of ast.parameters) {
    if (WHEN_PARAMETER_PATTERN.test(param.expression)) {
      parseWhenTrigger(param, bindingParser, triggers, errors);
    } else if (ON_PARAMETER_PATTERN.test(param.expression)) {
      parseOnTrigger(param, bindingParser, triggers, errors);
    } else if (PREFETCH_WHEN_PATTERN.test(param.expression)) {
      parseWhenTrigger(param, bindingParser, prefetchTriggers, errors);
    } else if (PREFETCH_ON_PATTERN.test(param.expression)) {
      parseOnTrigger(param, bindingParser, prefetchTriggers, errors);
    } else if (HYDRATE_WHEN_PATTERN.test(param.expression)) {
      parseWhenTrigger(param, bindingParser, hydrateTriggers, errors);
    } else if (HYDRATE_ON_PATTERN.test(param.expression)) {
      parseOnTrigger(param, bindingParser, hydrateTriggers, errors);
    } else if (HYDRATE_NEVER_PATTERN.test(param.expression)) {
      parseNeverTrigger(param, hydrateTriggers, errors);
    } else {
      errors.push(new ParseError(param.sourceSpan, 'Unrecognized trigger'));
    }
  }
  if (hydrateTriggers.never && Object.keys(hydrateTriggers).length > 1) {
    errors.push(new ParseError(ast.startSourceSpan, 'Cannot specify additional `hydrate` triggers if `hydrate never` is present'));
  }
  return {
    triggers,
    prefetchTriggers,
    hydrateTriggers
  };
}

const BIND_NAME_REGEXP = /^(?:(bind-)|(let-)|(ref-|#)|(on-)|(bindon-)|(@))(.*)$/;
const KW_BIND_IDX = 1;
const KW_LET_IDX = 2;
const KW_REF_IDX = 3;
const KW_ON_IDX = 4;
const KW_BINDON_IDX = 5;
const KW_AT_IDX = 6;
const IDENT_KW_IDX = 7;
const BINDING_DELIMS = {
  BANANA_BOX: {
    start: '[(',
    end: ')]'
  },
  PROPERTY: {
    start: '[',
    end: ']'
  },
  EVENT: {
    start: '(',
    end: ')'
  }
};
const TEMPLATE_ATTR_PREFIX = '*';
const UNSUPPORTED_SELECTORLESS_TAGS = new Set(['link', 'style', 'script', 'ng-template', 'ng-container', 'ng-content']);
const UNSUPPORTED_SELECTORLESS_DIRECTIVE_ATTRS = new Set(['ngProjectAs', 'ngNonBindable']);
function htmlAstToRender3Ast(htmlNodes, bindingParser, options) {
  const transformer = new HtmlAstToIvyAst(bindingParser, options);
  const ivyNodes = visitAll(transformer, htmlNodes, htmlNodes);
  const allErrors = bindingParser.errors.concat(transformer.errors);
  const result = {
    nodes: ivyNodes,
    errors: allErrors,
    styleUrls: transformer.styleUrls,
    styles: transformer.styles,
    ngContentSelectors: transformer.ngContentSelectors
  };
  if (options.collectCommentNodes) {
    result.commentNodes = transformer.commentNodes;
  }
  return result;
}
class HtmlAstToIvyAst {
  bindingParser;
  options;
  errors = [];
  styles = [];
  styleUrls = [];
  ngContentSelectors = [];
  commentNodes = [];
  inI18nBlock = false;
  processedNodes = new Set();
  constructor(bindingParser, options) {
    this.bindingParser = bindingParser;
    this.options = options;
  }
  visitElement(element) {
    const isI18nRootElement = isI18nRootNode(element.i18n);
    if (isI18nRootElement) {
      if (this.inI18nBlock) {
        this.reportError('Cannot mark an element as translatable inside of a translatable section. Please remove the nested i18n marker.', element.sourceSpan);
      }
      this.inI18nBlock = true;
    }
    const preparsedElement = preparseElement(element);
    if (preparsedElement.type === PreparsedElementType.SCRIPT) {
      return null;
    } else if (preparsedElement.type === PreparsedElementType.STYLE) {
      const contents = textContents(element);
      if (contents !== null) {
        this.styles.push(contents);
      }
      return null;
    } else if (preparsedElement.type === PreparsedElementType.STYLESHEET && isStyleUrlResolvable(preparsedElement.hrefAttr)) {
      this.styleUrls.push(preparsedElement.hrefAttr);
      return null;
    }
    const isTemplateElement = isNgTemplate(element.name);
    const {
      attributes,
      boundEvents,
      references,
      variables,
      templateVariables,
      elementHasInlineTemplate,
      parsedProperties,
      templateParsedProperties,
      i18nAttrsMeta
    } = this.prepareAttributes(element.attrs, isTemplateElement);
    const directives = this.extractDirectives(element);
    let children;
    if (preparsedElement.nonBindable) {
      children = visitAll(NON_BINDABLE_VISITOR, element.children).flat(Infinity);
    } else {
      children = visitAll(this, element.children, element.children);
    }
    let parsedElement;
    if (preparsedElement.type === PreparsedElementType.NG_CONTENT) {
      const selector = preparsedElement.selectAttr;
      const attrs = element.attrs.map(attr => this.visitAttribute(attr));
      parsedElement = new Content(selector, attrs, children, element.isSelfClosing, element.sourceSpan, element.startSourceSpan, element.endSourceSpan, element.i18n);
      this.ngContentSelectors.push(selector);
    } else if (isTemplateElement) {
      const attrs = this.categorizePropertyAttributes(element.name, parsedProperties, i18nAttrsMeta);
      parsedElement = new Template(element.name, attributes, attrs.bound, boundEvents, directives, [], children, references, variables, element.isSelfClosing, element.sourceSpan, element.startSourceSpan, element.endSourceSpan, element.i18n);
    } else {
      const attrs = this.categorizePropertyAttributes(element.name, parsedProperties, i18nAttrsMeta);
      if (element.name === 'ng-container') {
        for (const bound of attrs.bound) {
          if (bound.type === BindingType.Attribute) {
            this.reportError(`Attribute bindings are not supported on ng-container. Use property bindings instead.`, bound.sourceSpan);
          }
        }
      }
      parsedElement = new Element$1(element.name, attributes, attrs.bound, boundEvents, directives, children, references, element.isSelfClosing, element.sourceSpan, element.startSourceSpan, element.endSourceSpan, element.isVoid, element.i18n);
    }
    if (this.options.collectCommentNodes) {
      element.comments.forEach(comment => {
        this.commentNodes.push(new Comment$1(comment.value || '', comment.sourceSpan));
      });
    }
    if (elementHasInlineTemplate) {
      parsedElement = this.wrapInTemplate(parsedElement, templateParsedProperties, templateVariables, i18nAttrsMeta, isTemplateElement, isI18nRootElement);
    }
    if (isI18nRootElement) {
      this.inI18nBlock = false;
    }
    return parsedElement;
  }
  visitAttribute(attribute) {
    return new TextAttribute(attribute.name, attribute.value, attribute.sourceSpan, attribute.keySpan, attribute.valueSpan, attribute.i18n);
  }
  visitText(text) {
    return this.processedNodes.has(text) ? null : this._visitTextWithInterpolation(text.value, text.sourceSpan, text.tokens, text.i18n);
  }
  visitExpansion(expansion) {
    if (!expansion.i18n) {
      return null;
    }
    if (!isI18nRootNode(expansion.i18n)) {
      throw new Error(`Invalid type "${expansion.i18n.constructor}" for "i18n" property of ${expansion.sourceSpan.toString()}. Expected a "Message"`);
    }
    const message = expansion.i18n;
    const vars = {};
    const placeholders = {};
    Object.keys(message.placeholders).forEach(key => {
      const value = message.placeholders[key];
      if (key.startsWith(I18N_ICU_VAR_PREFIX)) {
        const formattedKey = key.trim();
        const ast = this.bindingParser.parseInterpolationExpression(value.text, value.sourceSpan);
        vars[formattedKey] = new BoundText(ast, value.sourceSpan);
      } else {
        placeholders[key] = this._visitTextWithInterpolation(value.text, value.sourceSpan, null);
      }
    });
    return new Icu$1(vars, placeholders, expansion.sourceSpan, message);
  }
  visitExpansionCase(expansionCase) {
    return null;
  }
  visitComment(comment) {
    if (this.options.collectCommentNodes) {
      this.commentNodes.push(new Comment$1(comment.value || '', comment.sourceSpan));
    }
    return null;
  }
  visitStartTagComment(comment) {
    if (this.options.collectCommentNodes) {
      this.commentNodes.push(new Comment$1(comment.value || '', comment.sourceSpan));
    }
    return null;
  }
  visitLetDeclaration(decl, context) {
    const value = this.bindingParser.parseBinding(decl.value, false, decl.valueSpan, decl.valueSpan.start.offset);
    if (value.errors.length === 0 && value.ast instanceof EmptyExpr$1) {
      this.reportError('@let declaration value cannot be empty', decl.valueSpan);
    }
    return new LetDeclaration$1(decl.name, value, decl.sourceSpan, decl.nameSpan, decl.valueSpan);
  }
  visitComponent(component) {
    const isI18nRootElement = isI18nRootNode(component.i18n);
    if (isI18nRootElement) {
      if (this.inI18nBlock) {
        this.reportError('Cannot mark a component as translatable inside of a translatable section. Please remove the nested i18n marker.', component.sourceSpan);
      }
      this.inI18nBlock = true;
    }
    if (component.tagName !== null && UNSUPPORTED_SELECTORLESS_TAGS.has(component.tagName)) {
      this.reportError(`Tag name "${component.tagName}" cannot be used as a component tag`, component.startSourceSpan);
      return null;
    }
    const {
      attributes,
      boundEvents,
      references,
      templateVariables,
      elementHasInlineTemplate,
      parsedProperties,
      templateParsedProperties,
      i18nAttrsMeta
    } = this.prepareAttributes(component.attrs, false);
    this.validateSelectorlessReferences(references);
    const directives = this.extractDirectives(component);
    let children;
    if (component.attrs.find(attr => attr.name === 'ngNonBindable')) {
      children = visitAll(NON_BINDABLE_VISITOR, component.children).flat(Infinity);
    } else {
      children = visitAll(this, component.children, component.children);
    }
    const attrs = this.categorizePropertyAttributes(component.tagName, parsedProperties, i18nAttrsMeta);
    let node = new Component$1(component.componentName, component.tagName, component.fullName, attributes, attrs.bound, boundEvents, directives, children, references, component.isSelfClosing, component.sourceSpan, component.startSourceSpan, component.endSourceSpan, component.i18n);
    if (this.options.collectCommentNodes) {
      component.comments.forEach(comment => {
        this.commentNodes.push(new Comment$1(comment.value || '', comment.sourceSpan));
      });
    }
    if (elementHasInlineTemplate) {
      node = this.wrapInTemplate(node, templateParsedProperties, templateVariables, i18nAttrsMeta, false, isI18nRootElement);
    }
    if (isI18nRootElement) {
      this.inI18nBlock = false;
    }
    return node;
  }
  visitDirective() {
    return null;
  }
  visitBlockParameter() {
    return null;
  }
  visitBlock(block, context) {
    const index = Array.isArray(context) ? context.indexOf(block) : -1;
    if (index === -1) {
      throw new Error('Visitor invoked incorrectly. Expecting visitBlock to be invoked siblings array as its context');
    }
    if (this.processedNodes.has(block)) {
      return null;
    }
    let result = null;
    switch (block.name) {
      case 'defer':
        result = createDeferredBlock(block, this.findConnectedBlocks(index, context, isConnectedDeferLoopBlock), this, this.bindingParser);
        break;
      case 'switch':
        result = createSwitchBlock(block, this, this.bindingParser);
        break;
      case 'content':
        result = createContentBlock(block, this);
        break;
      case 'for':
        result = createForLoop(block, this.findConnectedBlocks(index, context, isConnectedForLoopBlock), this, this.bindingParser);
        break;
      case 'if':
        result = createIfBlock(block, this.findConnectedBlocks(index, context, isConnectedIfLoopBlock), this, this.bindingParser);
        break;
      default:
        let errorMessage;
        if (isConnectedDeferLoopBlock(block.name)) {
          errorMessage = `@${block.name} block can only be used after an @defer block.`;
          this.processedNodes.add(block);
        } else if (isConnectedForLoopBlock(block.name)) {
          errorMessage = `@${block.name} block can only be used after an @for block.`;
          this.processedNodes.add(block);
        } else if (isConnectedIfLoopBlock(block.name)) {
          errorMessage = `@${block.name} block can only be used after an @if or @else if block.`;
          this.processedNodes.add(block);
        } else {
          errorMessage = `Unrecognized block @${block.name}.`;
        }
        result = {
          node: new UnknownBlock(block.name, block.sourceSpan, block.nameSpan),
          errors: [new ParseError(block.sourceSpan, errorMessage)]
        };
        break;
    }
    this.errors.push(...result.errors);
    return result.node;
  }
  findConnectedBlocks(primaryBlockIndex, siblings, predicate) {
    const relatedBlocks = [];
    for (let i = primaryBlockIndex + 1; i < siblings.length; i++) {
      const node = siblings[i];
      if (node instanceof Comment) {
        continue;
      }
      if (node instanceof Text && node.value.trim().length === 0) {
        this.processedNodes.add(node);
        continue;
      }
      if (!(node instanceof Block) || !predicate(node.name)) {
        break;
      }
      relatedBlocks.push(node);
      this.processedNodes.add(node);
    }
    return relatedBlocks;
  }
  categorizePropertyAttributes(elementName, properties, i18nPropsMeta) {
    const bound = [];
    const literal = [];
    properties.forEach(prop => {
      const i18n = i18nPropsMeta[prop.name];
      if (prop.isLiteral) {
        literal.push(new TextAttribute(prop.name, prop.expression.source || '', prop.sourceSpan, prop.keySpan, prop.valueSpan, i18n));
      } else {
        const isAttrOn = prop.name.toLowerCase().startsWith('attr.on');
        const bep = this.bindingParser.createBoundElementProperty(elementName, prop, !isAttrOn, false);
        bound.push(BoundAttribute.fromBoundElementProperty(bep, i18n));
      }
    });
    return {
      bound,
      literal
    };
  }
  prepareAttributes(attrs, isTemplateElement) {
    const parsedProperties = [];
    const boundEvents = [];
    const variables = [];
    const references = [];
    const attributes = [];
    const i18nAttrsMeta = {};
    const templateParsedProperties = [];
    const templateVariables = [];
    let elementHasInlineTemplate = false;
    for (const attribute of attrs) {
      let hasBinding = false;
      let isTemplateBinding = false;
      if (attribute.i18n) {
        i18nAttrsMeta[attribute.name] = attribute.i18n;
      }
      if (attribute.name.startsWith(TEMPLATE_ATTR_PREFIX)) {
        if (elementHasInlineTemplate) {
          this.reportError(`Can't have multiple template bindings on one element. Use only one attribute prefixed with *`, attribute.sourceSpan);
        }
        isTemplateBinding = true;
        elementHasInlineTemplate = true;
        const templateValue = attribute.value;
        const templateKey = attribute.name.substring(TEMPLATE_ATTR_PREFIX.length);
        const parsedVariables = [];
        const absoluteValueOffset = attribute.valueSpan ? attribute.valueSpan.fullStart.offset : attribute.sourceSpan.fullStart.offset + attribute.name.length;
        this.bindingParser.parseInlineTemplateBinding(templateKey, templateValue, attribute.sourceSpan, absoluteValueOffset, [], templateParsedProperties, parsedVariables, true);
        templateVariables.push(...parsedVariables.map(v => new Variable(v.name, v.value, v.sourceSpan, v.keySpan, v.valueSpan)));
      } else {
        hasBinding = this.parseAttribute(isTemplateElement, attribute, [], parsedProperties, boundEvents, variables, references);
      }
      if (!hasBinding && !isTemplateBinding) {
        attributes.push(this.visitAttribute(attribute));
      }
    }
    return {
      attributes,
      boundEvents,
      references,
      variables,
      templateVariables,
      elementHasInlineTemplate,
      parsedProperties,
      templateParsedProperties,
      i18nAttrsMeta
    };
  }
  parseAttribute(isTemplateElement, attribute, matchableAttributes, parsedProperties, boundEvents, variables, references) {
    const name = attribute.name;
    const value = attribute.value;
    const srcSpan = attribute.sourceSpan;
    const absoluteOffset = attribute.valueSpan ? attribute.valueSpan.fullStart.offset : srcSpan.fullStart.offset;
    function createKeySpan(srcSpan, prefix, identifier) {
      const keySpanStart = srcSpan.start.moveBy(prefix.length);
      const keySpanEnd = keySpanStart.moveBy(identifier.length);
      return new ParseSourceSpan(keySpanStart, keySpanEnd, keySpanStart, identifier);
    }
    const bindParts = name.match(BIND_NAME_REGEXP);
    if (bindParts) {
      if (bindParts[KW_BIND_IDX] != null) {
        const identifier = bindParts[IDENT_KW_IDX];
        const keySpan = createKeySpan(srcSpan, bindParts[KW_BIND_IDX], identifier);
        this.bindingParser.parsePropertyBinding(identifier, value, false, false, srcSpan, absoluteOffset, attribute.valueSpan, matchableAttributes, parsedProperties, keySpan);
      } else if (bindParts[KW_LET_IDX]) {
        if (isTemplateElement) {
          const identifier = bindParts[IDENT_KW_IDX];
          const keySpan = createKeySpan(srcSpan, bindParts[KW_LET_IDX], identifier);
          this.parseVariable(identifier, value, srcSpan, keySpan, attribute.valueSpan, variables);
        } else {
          this.reportError(`"let-" is only supported on ng-template elements.`, srcSpan);
        }
      } else if (bindParts[KW_REF_IDX]) {
        const identifier = bindParts[IDENT_KW_IDX];
        const keySpan = createKeySpan(srcSpan, bindParts[KW_REF_IDX], identifier);
        this.parseReference(identifier, value, srcSpan, keySpan, attribute.valueSpan, references);
      } else if (bindParts[KW_ON_IDX]) {
        const events = [];
        const identifier = bindParts[IDENT_KW_IDX];
        const keySpan = createKeySpan(srcSpan, bindParts[KW_ON_IDX], identifier);
        this.bindingParser.parseEvent(identifier, value, false, srcSpan, attribute.valueSpan || srcSpan, matchableAttributes, events, keySpan);
        addEvents(events, boundEvents);
      } else if (bindParts[KW_BINDON_IDX]) {
        const identifier = bindParts[IDENT_KW_IDX];
        const keySpan = createKeySpan(srcSpan, bindParts[KW_BINDON_IDX], identifier);
        this.bindingParser.parsePropertyBinding(identifier, value, false, true, srcSpan, absoluteOffset, attribute.valueSpan, matchableAttributes, parsedProperties, keySpan);
        this.parseAssignmentEvent(identifier, value, srcSpan, attribute.valueSpan, matchableAttributes, boundEvents, keySpan, absoluteOffset);
      } else if (bindParts[KW_AT_IDX]) {
        const keySpan = createKeySpan(srcSpan, '', name);
        this.bindingParser.parseLiteralAttr(name, value, srcSpan, absoluteOffset, attribute.valueSpan, matchableAttributes, parsedProperties, keySpan);
      }
      return true;
    }
    let delims = null;
    if (name.startsWith(BINDING_DELIMS.BANANA_BOX.start)) {
      delims = BINDING_DELIMS.BANANA_BOX;
    } else if (name.startsWith(BINDING_DELIMS.PROPERTY.start)) {
      delims = BINDING_DELIMS.PROPERTY;
    } else if (name.startsWith(BINDING_DELIMS.EVENT.start)) {
      delims = BINDING_DELIMS.EVENT;
    }
    if (delims !== null && name.endsWith(delims.end) && name.length > delims.start.length + delims.end.length) {
      const identifier = name.substring(delims.start.length, name.length - delims.end.length);
      const keySpan = createKeySpan(srcSpan, delims.start, identifier);
      if (delims.start === BINDING_DELIMS.BANANA_BOX.start) {
        this.bindingParser.parsePropertyBinding(identifier, value, false, true, srcSpan, absoluteOffset, attribute.valueSpan, matchableAttributes, parsedProperties, keySpan);
        this.parseAssignmentEvent(identifier, value, srcSpan, attribute.valueSpan, matchableAttributes, boundEvents, keySpan, absoluteOffset);
      } else if (delims.start === BINDING_DELIMS.PROPERTY.start) {
        this.bindingParser.parsePropertyBinding(identifier, value, false, false, srcSpan, absoluteOffset, attribute.valueSpan, matchableAttributes, parsedProperties, keySpan);
      } else {
        const events = [];
        this.bindingParser.parseEvent(identifier, value, false, srcSpan, attribute.valueSpan || srcSpan, matchableAttributes, events, keySpan);
        addEvents(events, boundEvents);
      }
      return true;
    }
    const keySpan = createKeySpan(srcSpan, '', name);
    const hasBinding = this.bindingParser.parsePropertyInterpolation(name, value, srcSpan, attribute.valueSpan, matchableAttributes, parsedProperties, keySpan, attribute.valueTokens ?? null);
    return hasBinding;
  }
  extractDirectives(node) {
    const elementName = node instanceof Component ? node.tagName : node.name;
    const directives = [];
    const seenDirectives = new Set();
    for (const directive of node.directives) {
      let invalid = false;
      for (const attr of directive.attrs) {
        if (attr.name.startsWith(TEMPLATE_ATTR_PREFIX)) {
          invalid = true;
          this.reportError(`Shorthand template syntax "${attr.name}" is not supported inside a directive context`, attr.sourceSpan);
        } else if (UNSUPPORTED_SELECTORLESS_DIRECTIVE_ATTRS.has(attr.name)) {
          invalid = true;
          this.reportError(`Attribute "${attr.name}" is not supported in a directive context`, attr.sourceSpan);
        }
      }
      if (!invalid && seenDirectives.has(directive.name)) {
        invalid = true;
        this.reportError(`Cannot apply directive "${directive.name}" multiple times on the same element`, directive.sourceSpan);
      }
      if (invalid) {
        continue;
      }
      const {
        attributes,
        parsedProperties,
        boundEvents,
        references,
        i18nAttrsMeta
      } = this.prepareAttributes(directive.attrs, false);
      this.validateSelectorlessReferences(references);
      const {
        bound: inputs
      } = this.categorizePropertyAttributes(elementName, parsedProperties, i18nAttrsMeta);
      for (const input of inputs) {
        if (input.type !== BindingType.Property && input.type !== BindingType.TwoWay) {
          invalid = true;
          this.reportError('Binding is not supported in a directive context', input.sourceSpan);
        }
      }
      if (invalid) {
        continue;
      }
      seenDirectives.add(directive.name);
      directives.push(new Directive$1(directive.name, attributes, inputs, boundEvents, references, directive.sourceSpan, directive.startSourceSpan, directive.endSourceSpan, undefined));
    }
    return directives;
  }
  filterAnimationAttributes(attributes) {
    return attributes.filter(a => !a.name.startsWith('animate.'));
  }
  filterAnimationInputs(attributes) {
    return attributes.filter(a => a.type !== BindingType.Animation);
  }
  wrapInTemplate(node, templateProperties, templateVariables, i18nAttrsMeta, isTemplateElement, isI18nRootElement) {
    const attrs = this.categorizePropertyAttributes('ng-template', templateProperties, i18nAttrsMeta);
    const templateAttrs = [];
    attrs.literal.forEach(attr => templateAttrs.push(attr));
    attrs.bound.forEach(attr => templateAttrs.push(attr));
    const hoistedAttrs = {
      attributes: [],
      inputs: [],
      outputs: []
    };
    if (node instanceof Element$1 || node instanceof Component$1) {
      hoistedAttrs.attributes.push(...this.filterAnimationAttributes(node.attributes));
      hoistedAttrs.inputs.push(...this.filterAnimationInputs(node.inputs));
      hoistedAttrs.outputs.push(...node.outputs);
    }
    const i18n = isTemplateElement && isI18nRootElement ? undefined : node.i18n;
    let name;
    if (node instanceof Component$1) {
      name = node.tagName;
    } else if (node instanceof Template) {
      name = null;
    } else {
      name = node.name;
    }
    return new Template(name, hoistedAttrs.attributes, hoistedAttrs.inputs, hoistedAttrs.outputs, [], templateAttrs, [node], [], templateVariables, false, node.sourceSpan, node.startSourceSpan, node.endSourceSpan, i18n);
  }
  _visitTextWithInterpolation(value, sourceSpan, interpolatedTokens, i18n) {
    const valueNoNgsp = replaceNgsp(value);
    const expr = this.bindingParser.parseInterpolation(valueNoNgsp, sourceSpan, interpolatedTokens);
    return expr ? new BoundText(expr, sourceSpan, i18n) : new Text$3(valueNoNgsp, sourceSpan);
  }
  parseVariable(identifier, value, sourceSpan, keySpan, valueSpan, variables) {
    if (identifier.indexOf('-') > -1) {
      this.reportError(`"-" is not allowed in variable names`, sourceSpan);
    } else if (identifier.length === 0) {
      this.reportError(`Variable does not have a name`, sourceSpan);
    }
    variables.push(new Variable(identifier, value, sourceSpan, keySpan, valueSpan));
  }
  parseReference(identifier, value, sourceSpan, keySpan, valueSpan, references) {
    if (identifier.indexOf('-') > -1) {
      this.reportError(`"-" is not allowed in reference names`, sourceSpan);
    } else if (identifier.length === 0) {
      this.reportError(`Reference does not have a name`, sourceSpan);
    } else if (references.some(reference => reference.name === identifier)) {
      this.reportError(`Reference "#${identifier}" is defined more than once`, sourceSpan);
    }
    references.push(new Reference(identifier, value, sourceSpan, keySpan, valueSpan));
  }
  parseAssignmentEvent(name, expression, sourceSpan, valueSpan, targetMatchableAttrs, boundEvents, keySpan, absoluteOffset) {
    const events = [];
    this.bindingParser.parseEvent(`${name}Change`, expression, true, sourceSpan, valueSpan || sourceSpan, targetMatchableAttrs, events, keySpan);
    addEvents(events, boundEvents);
  }
  validateSelectorlessReferences(references) {
    if (references.length === 0) {
      return;
    }
    const seenNames = new Set();
    for (const ref of references) {
      if (ref.value.length > 0) {
        this.reportError('Cannot specify a value for a local reference in this context', ref.valueSpan || ref.sourceSpan);
      } else if (seenNames.has(ref.name)) {
        this.reportError('Duplicate reference names are not allowed', ref.sourceSpan);
      } else {
        seenNames.add(ref.name);
      }
    }
  }
  reportError(message, sourceSpan, level = ParseErrorLevel.ERROR) {
    this.errors.push(new ParseError(sourceSpan, message, level));
  }
}
class NonBindableVisitor {
  visitElement(ast) {
    const preparsedElement = preparseElement(ast);
    if (preparsedElement.type === PreparsedElementType.SCRIPT || preparsedElement.type === PreparsedElementType.STYLE || preparsedElement.type === PreparsedElementType.STYLESHEET) {
      return null;
    }
    const children = visitAll(this, ast.children, null);
    return new Element$1(ast.name, visitAll(this, ast.attrs), [], [], [], children, [], ast.isSelfClosing, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan, ast.isVoid);
  }
  visitComment(comment) {
    return null;
  }
  visitAttribute(attribute) {
    return new TextAttribute(attribute.name, attribute.value, attribute.sourceSpan, attribute.keySpan, attribute.valueSpan, attribute.i18n);
  }
  visitText(text) {
    return new Text$3(text.value, text.sourceSpan);
  }
  visitExpansion(expansion) {
    return null;
  }
  visitExpansionCase(expansionCase) {
    return null;
  }
  visitBlock(block, context) {
    const nodes = [new Text$3(block.startSourceSpan.toString(), block.startSourceSpan), ...visitAll(this, block.children)];
    if (block.endSourceSpan !== null) {
      nodes.push(new Text$3(block.endSourceSpan.toString(), block.endSourceSpan));
    }
    return nodes;
  }
  visitBlockParameter(parameter, context) {
    return null;
  }
  visitLetDeclaration(decl, context) {
    return new Text$3(`@let ${decl.name} = ${decl.value};`, decl.sourceSpan);
  }
  visitComponent(ast, context) {
    const children = visitAll(this, ast.children, null);
    return new Element$1(ast.fullName, visitAll(this, ast.attrs), [], [], [], children, [], ast.isSelfClosing, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan, false);
  }
  visitDirective(directive, context) {
    return null;
  }
}
const NON_BINDABLE_VISITOR = new NonBindableVisitor();
function addEvents(events, boundEvents) {
  boundEvents.push(...events.map(e => BoundEvent.fromParsedEvent(e)));
}
function textContents(node) {
  if (node.children.length !== 1 || !(node.children[0] instanceof Text)) {
    return null;
  } else {
    return node.children[0].value;
  }
}

const LEADING_TRIVIA_CHARS = [' ', '\n', '\r', '\t'];
function parseTemplate(template, templateUrl, options = {}) {
  const {
    preserveWhitespaces,
    enableI18nLegacyMessageIdFormat
  } = options;
  const selectorlessEnabled = options.enableSelectorless ?? false;
  const bindingParser = makeBindingParser(selectorlessEnabled);
  const htmlParser = new HtmlParser();
  const parseResult = htmlParser.parse(template, templateUrl, {
    leadingTriviaChars: LEADING_TRIVIA_CHARS,
    ...options,
    tokenizeExpansionForms: true,
    tokenizeBlocks: options.enableBlockSyntax ?? true,
    tokenizeLet: options.enableLetSyntax ?? true,
    selectorlessEnabled
  });
  if (!options.alwaysAttemptHtmlToR3AstConversion && parseResult.errors && parseResult.errors.length > 0) {
    const parsedTemplate = {
      preserveWhitespaces,
      errors: parseResult.errors,
      nodes: [],
      styleUrls: [],
      styles: [],
      ngContentSelectors: []
    };
    if (options.collectCommentNodes) {
      parsedTemplate.commentNodes = [];
    }
    return parsedTemplate;
  }
  let rootNodes = parseResult.rootNodes;
  const retainEmptyTokens = !(options.preserveSignificantWhitespace ?? true);
  const i18nMetaVisitor = new I18nMetaVisitor(!preserveWhitespaces, enableI18nLegacyMessageIdFormat, options.preserveSignificantWhitespace, retainEmptyTokens);
  const i18nMetaResult = i18nMetaVisitor.visitAllWithErrors(rootNodes);
  if (!options.alwaysAttemptHtmlToR3AstConversion && i18nMetaResult.errors && i18nMetaResult.errors.length > 0) {
    const parsedTemplate = {
      preserveWhitespaces,
      errors: i18nMetaResult.errors,
      nodes: [],
      styleUrls: [],
      styles: [],
      ngContentSelectors: []
    };
    if (options.collectCommentNodes) {
      parsedTemplate.commentNodes = [];
    }
    return parsedTemplate;
  }
  rootNodes = i18nMetaResult.rootNodes;
  if (!preserveWhitespaces) {
    rootNodes = visitAll(new WhitespaceVisitor(true, undefined, false), rootNodes);
    if (i18nMetaVisitor.hasI18nMeta) {
      rootNodes = visitAll(new I18nMetaVisitor(false, undefined, true, retainEmptyTokens), rootNodes);
    }
  }
  const {
    nodes,
    errors,
    styleUrls,
    styles,
    ngContentSelectors,
    commentNodes
  } = htmlAstToRender3Ast(rootNodes, bindingParser, {
    collectCommentNodes: !!options.collectCommentNodes
  });
  errors.push(...parseResult.errors, ...i18nMetaResult.errors);
  const parsedTemplate = {
    preserveWhitespaces,
    errors: errors.length > 0 ? errors : null,
    nodes,
    styleUrls,
    styles,
    ngContentSelectors
  };
  if (options.collectCommentNodes) {
    parsedTemplate.commentNodes = commentNodes;
  }
  return parsedTemplate;
}
const elementRegistry = new DomElementSchemaRegistry();
function makeBindingParser(selectorlessEnabled = false) {
  return new BindingParser(new Parser(new Lexer(), selectorlessEnabled), elementRegistry, []);
}

const COMPONENT_VARIABLE = '%COMP%';
const HOST_ATTR = `_nghost-${COMPONENT_VARIABLE}`;
const CONTENT_ATTR = `_ngcontent-${COMPONENT_VARIABLE}`;
function baseDirectiveFields(meta, constantPool, bindingParser) {
  const definitionMap = new DefinitionMap();
  const selectors = parseSelectorToR3Selector(meta.selector);
  definitionMap.set('type', meta.type.value);
  if (selectors.length > 0) {
    definitionMap.set('selectors', asLiteral(selectors));
  }
  if (meta.queries.length > 0) {
    definitionMap.set('contentQueries', createContentQueriesFunction(meta.queries, constantPool, meta.name));
  }
  if (meta.viewQueries.length) {
    definitionMap.set('viewQuery', createViewQueriesFunction(meta.viewQueries, constantPool, meta.name));
  }
  definitionMap.set('hostBindings', createHostBindingsFunction(meta.host, meta.typeSourceSpan, bindingParser, constantPool, meta.selector || '', meta.name, definitionMap, meta.legacyOptionalChaining));
  definitionMap.set('inputs', conditionallyCreateDirectiveBindingLiteral(meta.inputs, true));
  definitionMap.set('outputs', conditionallyCreateDirectiveBindingLiteral(meta.outputs));
  if (meta.exportAs !== null) {
    definitionMap.set('exportAs', literalArr(meta.exportAs.map(e => literal(e))));
  }
  if (meta.isStandalone === false) {
    definitionMap.set('standalone', literal(false));
  }
  if (meta.isSignal) {
    definitionMap.set('signals', literal(true));
  }
  return definitionMap;
}
function addFeatures(definitionMap, meta) {
  const features = [];
  const providers = meta.providers;
  const viewProviders = meta.viewProviders;
  if (providers || viewProviders) {
    const args = [providers || new LiteralArrayExpr([])];
    if (viewProviders) {
      args.push(viewProviders);
    }
    features.push(importExpr(Identifiers.ProvidersFeature).callFn(args));
  }
  if (meta.hostDirectives?.length) {
    features.push(importExpr(Identifiers.HostDirectivesFeature).callFn([createHostDirectivesFeatureArg(meta.hostDirectives)]));
  }
  if (meta.usesInheritance) {
    features.push(importExpr(Identifiers.InheritDefinitionFeature));
  }
  if (meta.lifecycle.usesOnChanges) {
    features.push(importExpr(Identifiers.NgOnChangesFeature));
  }
  if (meta.controlCreate !== null) {
    features.push(importExpr(Identifiers.ControlFeature).callFn([literal(meta.controlCreate.passThroughInput)]));
  }
  if ('externalStyles' in meta && meta.externalStyles?.length) {
    const externalStyleNodes = meta.externalStyles.map(externalStyle => literal(externalStyle));
    features.push(importExpr(Identifiers.ExternalStylesFeature).callFn([literalArr(externalStyleNodes)]));
  }
  if (features.length) {
    definitionMap.set('features', literalArr(features));
  }
}
function compileDirectiveFromMetadata(meta, constantPool, bindingParser) {
  const definitionMap = baseDirectiveFields(meta, constantPool, bindingParser);
  addFeatures(definitionMap, meta);
  const expression = importExpr(Identifiers.defineDirective).callFn([definitionMap.toLiteralMap()], undefined, true);
  const type = createDirectiveType(meta);
  return {
    expression,
    type,
    statements: []
  };
}
function compileComponentFromMetadata(meta, constantPool, bindingParser) {
  const definitionMap = baseDirectiveFields(meta, constantPool, bindingParser);
  addFeatures(definitionMap, meta);
  const templateTypeName = meta.name;
  let allDeferrableDepsFn = null;
  if (meta.defer.mode === 1 && meta.defer.dependenciesFn !== null) {
    const fnName = `${templateTypeName}_DeferFn`;
    constantPool.statements.push(new DeclareVarStmt(fnName, meta.defer.dependenciesFn, undefined, StmtModifier.Final));
    allDeferrableDepsFn = variable(fnName);
  }
  const compilationMode = meta.isStandalone && !meta.hasDirectiveDependencies ? TemplateCompilationMode.DomOnly : TemplateCompilationMode.Full;
  const tpl = ingestComponent(meta.name, meta.template.nodes, constantPool, compilationMode, meta.relativeContextFilePath, meta.i18nUseExternalIds, meta.defer, allDeferrableDepsFn, meta.relativeTemplatePath, meta.enableTemplateSourceLocations || ENABLE_TEMPLATE_SOURCE_LOCATIONS, meta.legacyOptionalChaining, meta.foreignImports);
  transform(tpl, CompilationJobKind.Tmpl);
  const templateFn = emitTemplateFn(tpl, constantPool);
  if (tpl.contentSelectors !== null) {
    definitionMap.set('ngContentSelectors', tpl.contentSelectors);
  }
  definitionMap.set('decls', literal(tpl.root.decls));
  definitionMap.set('vars', literal(tpl.root.vars));
  if (tpl.consts.length > 0) {
    if (tpl.constsInitializers.length > 0) {
      definitionMap.set('consts', arrowFn([], [...tpl.constsInitializers, new ReturnStatement(literalArr(tpl.consts))]));
    } else {
      definitionMap.set('consts', literalArr(tpl.consts));
    }
  }
  definitionMap.set('template', templateFn);
  if (meta.declarationListEmitMode !== 3 && meta.declarations.length > 0) {
    definitionMap.set('dependencies', compileDeclarationList(literalArr(meta.declarations.map(decl => decl.type)), meta.declarationListEmitMode));
  } else if (meta.declarationListEmitMode === 3) {
    const args = [meta.type.value];
    if (meta.rawImports) {
      args.push(meta.rawImports);
    }
    definitionMap.set('dependencies', importExpr(Identifiers.getComponentDepsFactory).callFn(args));
  }
  if (meta.encapsulation === null) {
    meta.encapsulation = ViewEncapsulation$1.Emulated;
  }
  let hasStyles = !!meta.externalStyles?.length;
  if (meta.styles && meta.styles.length) {
    const namespacedStyles = meta.styles.map(s => namespaceCssVariables(s));
    const styleValues = meta.encapsulation == ViewEncapsulation$1.Emulated ? compileStyles(namespacedStyles, CONTENT_ATTR, HOST_ATTR) : namespacedStyles;
    const styleNodes = styleValues.reduce((result, style) => {
      if (style.trim().length > 0) {
        result.push(constantPool.getConstLiteral(literal(style)));
      }
      return result;
    }, []);
    if (styleNodes.length > 0) {
      hasStyles = true;
      definitionMap.set('styles', literalArr(styleNodes));
    }
  }
  if (!hasStyles && meta.encapsulation === ViewEncapsulation$1.Emulated) {
    meta.encapsulation = ViewEncapsulation$1.None;
  }
  if (meta.encapsulation !== ViewEncapsulation$1.Emulated) {
    definitionMap.set('encapsulation', literal(meta.encapsulation));
  }
  if (meta.animations !== null) {
    definitionMap.set('data', literalMap([{
      key: 'animation',
      value: meta.animations,
      quoted: false
    }]));
  }
  if (meta.changeDetection !== null) {
    if (typeof meta.changeDetection === 'number' && meta.changeDetection !== ChangeDetectionStrategy.OnPush) {
      definitionMap.set('changeDetection', literal(meta.changeDetection));
    } else if (typeof meta.changeDetection === 'object') {
      definitionMap.set('changeDetection', meta.changeDetection);
    }
  }
  const expression = importExpr(Identifiers.defineComponent).callFn([definitionMap.toLiteralMap()], undefined, true);
  const type = createComponentType(meta);
  return {
    expression,
    type,
    statements: []
  };
}
function createComponentType(meta) {
  const typeParams = createBaseDirectiveTypeParams(meta);
  typeParams.push(stringArrayAsType(meta.template.ngContentSelectors));
  typeParams.push(expressionType(literal(meta.isStandalone)));
  typeParams.push(createHostDirectivesType(meta));
  if (meta.isSignal) {
    typeParams.push(expressionType(literal(meta.isSignal)));
  }
  return expressionType(importExpr(Identifiers.ComponentDeclaration, typeParams));
}
function compileDeclarationList(list, mode) {
  switch (mode) {
    case 0:
      return list;
    case 1:
      return arrowFn([], list);
    case 2:
      const resolvedList = list.prop('map').callFn([importExpr(Identifiers.resolveForwardRef)]);
      return arrowFn([], resolvedList);
    case 3:
      throw new Error(`Unsupported with an array of pre-resolved dependencies`);
  }
}
function stringAsType(str) {
  return expressionType(literal(str));
}
function stringMapAsLiteralExpression(map) {
  const mapValues = Object.keys(map).map(key => {
    const value = Array.isArray(map[key]) ? map[key][0] : map[key];
    return {
      key,
      value: literal(value),
      quoted: true
    };
  });
  return literalMap(mapValues);
}
function stringArrayAsType(arr) {
  return arr.length > 0 ? expressionType(literalArr(arr.map(value => literal(value)))) : NONE_TYPE;
}
function createBaseDirectiveTypeParams(meta) {
  const selectorForType = meta.selector !== null ? meta.selector.replace(/\n/g, '') : null;
  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))];
}
function getInputsTypeExpression(meta) {
  return literalMap(Object.keys(meta.inputs).map(key => {
    const value = meta.inputs[key];
    const values = [{
      key: 'alias',
      value: literal(value.bindingPropertyName),
      quoted: true
    }, {
      key: 'required',
      value: literal(value.required),
      quoted: true
    }];
    if (value.isSignal) {
      values.push({
        key: 'isSignal',
        value: literal(value.isSignal),
        quoted: true
      });
    }
    return {
      key,
      value: literalMap(values),
      quoted: true
    };
  }));
}
function createDirectiveType(meta) {
  const typeParams = createBaseDirectiveTypeParams(meta);
  typeParams.push(NONE_TYPE);
  typeParams.push(expressionType(literal(meta.isStandalone)));
  typeParams.push(createHostDirectivesType(meta));
  if (meta.isSignal) {
    typeParams.push(expressionType(literal(meta.isSignal)));
  }
  return expressionType(importExpr(Identifiers.DirectiveDeclaration, typeParams));
}
function createHostBindingsFunction(hostBindingsMetadata, typeSourceSpan, bindingParser, constantPool, selector, name, definitionMap, legacyOptionalChaining) {
  const bindings = bindingParser.createBoundHostProperties(hostBindingsMetadata.properties, typeSourceSpan);
  const eventBindings = bindingParser.createDirectiveHostEventAsts(hostBindingsMetadata.listeners, typeSourceSpan);
  if (hostBindingsMetadata.specialAttributes.styleAttr) {
    hostBindingsMetadata.attributes['style'] = literal(hostBindingsMetadata.specialAttributes.styleAttr);
  }
  if (hostBindingsMetadata.specialAttributes.classAttr) {
    hostBindingsMetadata.attributes['class'] = literal(hostBindingsMetadata.specialAttributes.classAttr);
  }
  const hostJob = ingestHostBinding({
    componentName: name,
    componentSelector: selector,
    properties: bindings,
    events: eventBindings,
    attributes: hostBindingsMetadata.attributes,
    legacyOptionalChaining: legacyOptionalChaining
  }, bindingParser, constantPool);
  transform(hostJob, CompilationJobKind.Host);
  definitionMap.set('hostAttrs', hostJob.root.attributes);
  const varCount = hostJob.root.vars;
  if (varCount !== null && varCount > 0) {
    definitionMap.set('hostVars', literal(varCount));
  }
  return emitHostBindingFunction(hostJob);
}
function parseHostBindings(host) {
  const attributes = {};
  const listeners = {};
  const properties = {};
  const specialAttributes = {};
  for (const key of Object.keys(host)) {
    const value = host[key];
    if (key.startsWith('(') && key.endsWith(')')) {
      if (typeof value !== 'string') {
        throw new Error(`Event binding must be string`);
      }
      listeners[key.slice(1, -1)] = value;
    } else if (key.startsWith('[') && key.endsWith(']')) {
      if (typeof value !== 'string') {
        throw new Error(`Property binding must be string`);
      }
      properties[key.slice(1, -1)] = value;
    } else {
      switch (key) {
        case 'class':
          if (typeof value !== 'string') {
            throw new Error(`Class binding must be string`);
          }
          specialAttributes.classAttr = value;
          break;
        case 'style':
          if (typeof value !== 'string') {
            throw new Error(`Style binding must be string`);
          }
          specialAttributes.styleAttr = value;
          break;
        default:
          if (typeof value === 'string') {
            attributes[key] = literal(value);
          } else {
            attributes[key] = value;
          }
      }
    }
  }
  return {
    attributes,
    listeners,
    properties,
    specialAttributes
  };
}
function verifyHostBindings(bindings, sourceSpan) {
  const bindingParser = makeBindingParser();
  bindingParser.createDirectiveHostEventAsts(bindings.listeners, sourceSpan);
  bindingParser.createBoundHostProperties(bindings.properties, sourceSpan);
  validateNoEventBindings(bindings, bindingParser, sourceSpan);
  return bindingParser.errors;
}
function validateNoEventBindings(bindings, bindingParser, sourceSpan) {
  for (const prop in bindings.properties) {
    const isAttr = prop.startsWith('attr.');
    const boundName = isAttr ? prop.slice(5) : prop;
    if (boundName.toLowerCase().startsWith('on')) {
      const errorType = isAttr ? 'attribute' : 'property';
      const suggestion = `(${boundName.slice(2)})=...`;
      let msg = `Binding to event ${errorType} '${boundName}' is disallowed for security reasons, please use ${suggestion}`;
      if (!isAttr) {
        msg += `\nIf '${prop}' is a directive input, make sure the directive is imported by the current module.`;
      }
      bindingParser.errors.push(new ParseError(sourceSpan, msg));
    }
  }
}
function compileStyles(styles, selector, hostSelector) {
  const shadowCss = new ShadowCss();
  return styles.map(style => {
    return shadowCss.shimCssText(style, selector, hostSelector);
  });
}
function encapsulateStyle(style, componentIdentifier) {
  const shadowCss = new ShadowCss();
  const selector = componentIdentifier ? CONTENT_ATTR.replace(COMPONENT_VARIABLE, componentIdentifier) : CONTENT_ATTR;
  const hostSelector = componentIdentifier ? HOST_ATTR.replace(COMPONENT_VARIABLE, componentIdentifier) : HOST_ATTR;
  return shadowCss.shimCssText(style, selector, hostSelector);
}
function createHostDirectivesType(meta) {
  if (!meta.hostDirectives?.length) {
    return NONE_TYPE;
  }
  return expressionType(literalArr(meta.hostDirectives.map(hostMeta => literalMap([{
    key: 'directive',
    value: typeofExpr(hostMeta.directive.type),
    quoted: false
  }, {
    key: 'inputs',
    value: stringMapAsLiteralExpression(hostMeta.inputs || {}),
    quoted: false
  }, {
    key: 'outputs',
    value: stringMapAsLiteralExpression(hostMeta.outputs || {}),
    quoted: false
  }]))));
}
function createHostDirectivesFeatureArg(hostDirectives) {
  const expressions = [];
  let hasForwardRef = false;
  for (const current of hostDirectives) {
    if (!current.inputs && !current.outputs) {
      expressions.push(current.directive.type);
    } else {
      const keys = [{
        key: 'directive',
        value: current.directive.type,
        quoted: false
      }];
      if (current.inputs) {
        const inputsLiteral = createHostDirectivesMappingArray(current.inputs);
        if (inputsLiteral) {
          keys.push({
            key: 'inputs',
            value: inputsLiteral,
            quoted: false
          });
        }
      }
      if (current.outputs) {
        const outputsLiteral = createHostDirectivesMappingArray(current.outputs);
        if (outputsLiteral) {
          keys.push({
            key: 'outputs',
            value: outputsLiteral,
            quoted: false
          });
        }
      }
      expressions.push(literalMap(keys));
    }
    if (current.isForwardReference) {
      hasForwardRef = true;
    }
  }
  return hasForwardRef ? new FunctionExpr([], [new ReturnStatement(literalArr(expressions))]) : literalArr(expressions);
}
function createHostDirectivesMappingArray(mapping) {
  const elements = [];
  for (const publicName in mapping) {
    if (Object.hasOwn(mapping, publicName)) {
      elements.push(literal(publicName), literal(mapping[publicName]));
    }
  }
  return elements.length > 0 ? literalArr(elements) : null;
}
function compileDeferResolverFunction(meta) {
  const depExpressions = [];
  if (meta.mode === 0) {
    for (const dep of meta.dependencies) {
      if (dep.isDeferrable) {
        const innerFn = arrowFn([new FnParam('m', DYNAMIC_TYPE)], variable('m').prop(dep.isDefaultImport ? 'default' : dep.symbolName));
        const importExpr = new DynamicImportExpr(dep.importPath).prop('then').callFn([innerFn], undefined, undefined, [tsIgnoreComment()]);
        depExpressions.push(importExpr);
      } else {
        depExpressions.push(dep.typeReference);
      }
    }
  } else {
    for (const {
      symbolName,
      importPath,
      isDefaultImport
    } of meta.dependencies) {
      const innerFn = arrowFn([new FnParam('m', DYNAMIC_TYPE)], variable('m').prop(isDefaultImport ? 'default' : symbolName));
      const importExpr = new DynamicImportExpr(importPath).prop('then').callFn([innerFn], undefined, undefined, [tsIgnoreComment()]);
      depExpressions.push(importExpr);
    }
  }
  return arrowFn([], literalArr(depExpressions));
}

class CombinedRecursiveAstVisitor extends RecursiveAstVisitor {
  visit(node) {
    if (node instanceof ASTWithSource) {
      this.visit(node.ast);
    } else {
      node.visit(this);
    }
  }
  visitElement(element) {
    this.visitAllTemplateNodes(element.attributes);
    this.visitAllTemplateNodes(element.inputs);
    this.visitAllTemplateNodes(element.outputs);
    this.visitAllTemplateNodes(element.directives);
    this.visitAllTemplateNodes(element.references);
    this.visitAllTemplateNodes(element.children);
  }
  visitTemplate(template) {
    this.visitAllTemplateNodes(template.attributes);
    this.visitAllTemplateNodes(template.inputs);
    this.visitAllTemplateNodes(template.outputs);
    this.visitAllTemplateNodes(template.directives);
    this.visitAllTemplateNodes(template.templateAttrs);
    this.visitAllTemplateNodes(template.variables);
    this.visitAllTemplateNodes(template.references);
    this.visitAllTemplateNodes(template.children);
  }
  visitContent(content) {
    this.visitAllTemplateNodes(content.children);
  }
  visitContentBlock(block) {
    this.visitAllTemplateNodes(block.children);
  }
  visitBoundAttribute(attribute) {
    this.visit(attribute.value);
  }
  visitBoundEvent(attribute) {
    this.visit(attribute.handler);
  }
  visitBoundText(text) {
    this.visit(text.value);
  }
  visitIcu(icu) {
    Object.keys(icu.vars).forEach(key => this.visit(icu.vars[key]));
    Object.keys(icu.placeholders).forEach(key => this.visit(icu.placeholders[key]));
  }
  visitDeferredBlock(deferred) {
    deferred.visitAll(this);
  }
  visitDeferredTrigger(trigger) {
    if (trigger instanceof BoundDeferredTrigger) {
      this.visit(trigger.value);
    } else if (trigger instanceof ViewportDeferredTrigger && trigger.options !== null) {
      this.visit(trigger.options);
    }
  }
  visitDeferredBlockPlaceholder(block) {
    this.visitAllTemplateNodes(block.children);
  }
  visitDeferredBlockError(block) {
    this.visitAllTemplateNodes(block.children);
  }
  visitDeferredBlockLoading(block) {
    this.visitAllTemplateNodes(block.children);
  }
  visitSwitchBlock(block) {
    this.visit(block.expression);
    this.visitAllTemplateNodes(block.groups);
    block.exhaustiveCheck?.visit(this);
  }
  visitSwitchBlockCase(block) {
    block.expression && this.visit(block.expression);
  }
  visitSwitchBlockCaseGroup(block) {
    this.visitAllTemplateNodes(block.cases);
    this.visitAllTemplateNodes(block.children);
  }
  visitSwitchExhaustiveCheck(block) {}
  visitForLoopBlock(block) {
    block.item.visit(this);
    this.visitAllTemplateNodes(block.contextVariables);
    this.visit(block.expression);
    this.visitAllTemplateNodes(block.children);
    block.empty?.visit(this);
  }
  visitForLoopBlockEmpty(block) {
    this.visitAllTemplateNodes(block.children);
  }
  visitIfBlock(block) {
    this.visitAllTemplateNodes(block.branches);
  }
  visitIfBlockBranch(block) {
    block.expression && this.visit(block.expression);
    block.expressionAlias?.visit(this);
    this.visitAllTemplateNodes(block.children);
  }
  visitLetDeclaration(decl) {
    this.visit(decl.value);
  }
  visitComponent(component) {
    this.visitAllTemplateNodes(component.attributes);
    this.visitAllTemplateNodes(component.inputs);
    this.visitAllTemplateNodes(component.outputs);
    this.visitAllTemplateNodes(component.directives);
    this.visitAllTemplateNodes(component.references);
    this.visitAllTemplateNodes(component.children);
  }
  visitDirective(directive) {
    this.visitAllTemplateNodes(directive.attributes);
    this.visitAllTemplateNodes(directive.inputs);
    this.visitAllTemplateNodes(directive.outputs);
    this.visitAllTemplateNodes(directive.references);
  }
  visitVariable(variable) {}
  visitReference(reference) {}
  visitTextAttribute(attribute) {}
  visitText(text) {}
  visitUnknownBlock(block) {}
  visitAllTemplateNodes(nodes) {
    for (const node of nodes) {
      this.visit(node);
    }
  }
}

var MatchSource;
(function (MatchSource) {
  MatchSource[MatchSource["Selector"] = 0] = "Selector";
  MatchSource[MatchSource["HostDirective"] = 1] = "HostDirective";
})(MatchSource || (MatchSource = {}));

class ClassPropertyMapping {
  forwardMap;
  reverseMap;
  constructor(forwardMap) {
    this.forwardMap = forwardMap;
    this.reverseMap = reverseMapFromForwardMap(forwardMap);
  }
  static empty() {
    return new ClassPropertyMapping(new Map());
  }
  static fromMappedObject(obj) {
    const forwardMap = new Map();
    for (const classPropertyName of Object.keys(obj)) {
      const value = obj[classPropertyName];
      let inputOrOutput;
      if (typeof value === 'string') {
        inputOrOutput = {
          classPropertyName,
          bindingPropertyName: value,
          isSignal: false
        };
      } else {
        inputOrOutput = value;
      }
      forwardMap.set(classPropertyName, inputOrOutput);
    }
    return new ClassPropertyMapping(forwardMap);
  }
  static merge(a, b) {
    const forwardMap = new Map(a.forwardMap.entries());
    for (const [classPropertyName, inputOrOutput] of b.forwardMap) {
      forwardMap.set(classPropertyName, inputOrOutput);
    }
    return new ClassPropertyMapping(forwardMap);
  }
  get classPropertyNames() {
    return Array.from(this.forwardMap.keys());
  }
  get propertyNames() {
    return Array.from(this.reverseMap.keys());
  }
  hasBindingPropertyName(propertyName) {
    return this.reverseMap.has(propertyName);
  }
  getByBindingPropertyName(propertyName) {
    return this.reverseMap.has(propertyName) ? this.reverseMap.get(propertyName) : null;
  }
  getByClassPropertyName(classPropertyName) {
    return this.forwardMap.has(classPropertyName) ? this.forwardMap.get(classPropertyName) : null;
  }
  toDirectMappedObject() {
    const obj = {};
    for (const [classPropertyName, inputOrOutput] of this.forwardMap) {
      obj[classPropertyName] = inputOrOutput.bindingPropertyName;
    }
    return obj;
  }
  toJointMappedObject(transform) {
    const obj = {};
    for (const [classPropertyName, inputOrOutput] of this.forwardMap) {
      obj[classPropertyName] = transform(inputOrOutput);
    }
    return obj;
  }
  *[Symbol.iterator]() {
    for (const inputOrOutput of this.forwardMap.values()) {
      yield inputOrOutput;
    }
  }
}
function reverseMapFromForwardMap(forwardMap) {
  const reverseMap = new Map();
  for (const [_, inputOrOutput] of forwardMap) {
    if (!reverseMap.has(inputOrOutput.bindingPropertyName)) {
      reverseMap.set(inputOrOutput.bindingPropertyName, []);
    }
    reverseMap.get(inputOrOutput.bindingPropertyName).push(inputOrOutput);
  }
  return reverseMap;
}

function diff(fullList, itemsToExclude) {
  const exclude = new Set(itemsToExclude);
  return fullList.filter(item => !exclude.has(item));
}
function findMatchingDirectivesAndPipes(template, directiveSelectors) {
  const matcher = new SelectorMatcher();
  for (const selector of directiveSelectors) {
    const fakeDirective = {
      selector,
      exportAs: null,
      inputs: {
        hasBindingPropertyName() {
          return false;
        }
      },
      outputs: {
        hasBindingPropertyName() {
          return false;
        }
      },
      matchSource: MatchSource.Selector
    };
    matcher.addSelectables(CssSelector.parse(selector), [fakeDirective]);
  }
  const parsedTemplate = parseTemplate(template, '');
  const binder = new R3TargetBinder(matcher);
  const bound = binder.bind({
    template: parsedTemplate.nodes
  });
  const eagerDirectiveSelectors = bound.getEagerlyUsedDirectives().map(dir => dir.selector);
  const allMatchedDirectiveSelectors = bound.getUsedDirectives().map(dir => dir.selector);
  const eagerPipes = bound.getEagerlyUsedPipes();
  return {
    directives: {
      regular: eagerDirectiveSelectors,
      deferCandidates: diff(allMatchedDirectiveSelectors, eagerDirectiveSelectors)
    },
    pipes: {
      regular: eagerPipes,
      deferCandidates: diff(bound.getUsedPipes(), eagerPipes)
    }
  };
}
class R3TargetBinder {
  directiveMatcher;
  foreignComponentMatcher;
  constructor(directiveMatcher, foreignComponentMatcher = null) {
    this.directiveMatcher = directiveMatcher;
    this.foreignComponentMatcher = foreignComponentMatcher;
  }
  bind(target) {
    if (!target.template && !target.host) {
      throw new Error('Empty bound targets are not supported');
    }
    const directives = new Map();
    const foreignComponents = new Map();
    const eagerDirectives = [];
    const missingDirectives = new Set();
    const bindings = new Map();
    const references = new Map();
    const scopedNodeEntities = new Map();
    const expressions = new Map();
    const symbols = new Map();
    const nestingLevel = new Map();
    const usedPipes = new Set();
    const eagerPipes = new Set();
    const deferBlocks = [];
    const conflictingHostDirectiveBindings = new Map();
    if (target.template) {
      const scope = Scope$1.apply(target.template);
      extractScopedNodeEntities(scope, scopedNodeEntities);
      DirectiveBinder.apply(target.template, this.directiveMatcher, this.foreignComponentMatcher, directives, foreignComponents, eagerDirectives, missingDirectives, bindings, references, conflictingHostDirectiveBindings);
      TemplateBinder.applyWithScope(target.template, scope, expressions, symbols, nestingLevel, usedPipes, eagerPipes, deferBlocks);
    }
    if (target.host) {
      directives.set(target.host.node, target.host.directives);
      TemplateBinder.applyWithScope(target.host.node, Scope$1.apply(target.host.node), expressions, symbols, nestingLevel, usedPipes, eagerPipes, deferBlocks);
    }
    return new R3BoundTarget(target, directives, foreignComponents, eagerDirectives, missingDirectives, bindings, references, expressions, symbols, nestingLevel, scopedNodeEntities, usedPipes, eagerPipes, deferBlocks, conflictingHostDirectiveBindings);
  }
}
let Scope$1 = class Scope {
  parentScope;
  rootNode;
  namedEntities = new Map();
  elementLikeInScope = new Set();
  childScopes = new Map();
  isDeferred;
  constructor(parentScope, rootNode) {
    this.parentScope = parentScope;
    this.rootNode = rootNode;
    this.isDeferred = parentScope !== null && parentScope.isDeferred ? true : rootNode instanceof DeferredBlock;
  }
  static newRootScope() {
    return new Scope(null, null);
  }
  static apply(template) {
    const scope = Scope.newRootScope();
    scope.ingest(template);
    return scope;
  }
  ingest(nodeOrNodes) {
    if (nodeOrNodes instanceof Template) {
      nodeOrNodes.variables.forEach(node => this.visitVariable(node));
      nodeOrNodes.children.forEach(node => node.visit(this));
    } else if (nodeOrNodes instanceof IfBlockBranch) {
      if (nodeOrNodes.expressionAlias !== null) {
        this.visitVariable(nodeOrNodes.expressionAlias);
      }
      nodeOrNodes.children.forEach(node => node.visit(this));
    } else if (nodeOrNodes instanceof ForLoopBlock) {
      this.visitVariable(nodeOrNodes.item);
      nodeOrNodes.contextVariables.forEach(v => this.visitVariable(v));
      nodeOrNodes.children.forEach(node => node.visit(this));
    } else if (nodeOrNodes instanceof SwitchBlockCaseGroup || nodeOrNodes instanceof ForLoopBlockEmpty || nodeOrNodes instanceof DeferredBlock || nodeOrNodes instanceof DeferredBlockError || nodeOrNodes instanceof DeferredBlockPlaceholder || nodeOrNodes instanceof DeferredBlockLoading || nodeOrNodes instanceof ContentBlock || nodeOrNodes instanceof Content) {
      nodeOrNodes.children.forEach(node => node.visit(this));
    } else if (!(nodeOrNodes instanceof HostElement)) {
      nodeOrNodes.forEach(node => node.visit(this));
    }
  }
  visitElement(element) {
    this.visitElementLike(element);
  }
  visitTemplate(template) {
    template.directives.forEach(node => node.visit(this));
    template.references.forEach(node => this.visitReference(node));
    this.ingestScopedNode(template);
  }
  visitVariable(variable) {
    this.maybeDeclare(variable);
  }
  visitReference(reference) {
    this.maybeDeclare(reference);
  }
  visitDeferredBlock(deferred) {
    this.ingestScopedNode(deferred);
    deferred.placeholder?.visit(this);
    deferred.loading?.visit(this);
    deferred.error?.visit(this);
  }
  visitDeferredBlockPlaceholder(block) {
    this.ingestScopedNode(block);
  }
  visitDeferredBlockError(block) {
    this.ingestScopedNode(block);
  }
  visitDeferredBlockLoading(block) {
    this.ingestScopedNode(block);
  }
  visitSwitchBlock(block) {
    block.groups.forEach(node => node.visit(this));
  }
  visitSwitchBlockCase(block) {}
  visitSwitchBlockCaseGroup(block) {
    this.ingestScopedNode(block);
  }
  visitSwitchExhaustiveCheck(block) {}
  visitForLoopBlock(block) {
    this.ingestScopedNode(block);
    block.empty?.visit(this);
  }
  visitForLoopBlockEmpty(block) {
    this.ingestScopedNode(block);
  }
  visitIfBlock(block) {
    block.branches.forEach(node => node.visit(this));
  }
  visitIfBlockBranch(block) {
    this.ingestScopedNode(block);
  }
  visitContent(content) {
    this.ingestScopedNode(content);
  }
  visitContentBlock(block) {
    this.ingestScopedNode(block);
  }
  visitLetDeclaration(decl) {
    this.maybeDeclare(decl);
  }
  visitComponent(component) {
    this.visitElementLike(component);
  }
  visitDirective(directive) {
    directive.references.forEach(current => this.visitReference(current));
  }
  visitBoundAttribute(attr) {}
  visitBoundEvent(event) {}
  visitBoundText(text) {}
  visitText(text) {}
  visitTextAttribute(attr) {}
  visitIcu(icu) {}
  visitDeferredTrigger(trigger) {}
  visitUnknownBlock(block) {}
  visitElementLike(node) {
    node.directives.forEach(current => current.visit(this));
    node.references.forEach(current => this.visitReference(current));
    node.children.forEach(current => current.visit(this));
    this.elementLikeInScope.add(node);
  }
  maybeDeclare(thing) {
    if (!this.namedEntities.has(thing.name)) {
      this.namedEntities.set(thing.name, thing);
    }
  }
  lookup(name) {
    if (this.namedEntities.has(name)) {
      return this.namedEntities.get(name);
    } else if (this.parentScope !== null) {
      return this.parentScope.lookup(name);
    } else {
      return null;
    }
  }
  getChildScope(node) {
    const res = this.childScopes.get(node);
    if (res === undefined) {
      throw new Error(`Assertion error: child scope for ${node} not found`);
    }
    return res;
  }
  ingestScopedNode(node) {
    const scope = new Scope(this, node);
    scope.ingest(node);
    this.childScopes.set(node, scope);
  }
};
class DirectiveBinder {
  directiveMatcher;
  foreignMatcher;
  directives;
  foreignComponents;
  eagerDirectives;
  missingDirectives;
  bindings;
  references;
  conflictingHostDirectiveBindings;
  isInDeferBlock = false;
  constructor(directiveMatcher, foreignMatcher, directives, foreignComponents, eagerDirectives, missingDirectives, bindings, references, conflictingHostDirectiveBindings) {
    this.directiveMatcher = directiveMatcher;
    this.foreignMatcher = foreignMatcher;
    this.directives = directives;
    this.foreignComponents = foreignComponents;
    this.eagerDirectives = eagerDirectives;
    this.missingDirectives = missingDirectives;
    this.bindings = bindings;
    this.references = references;
    this.conflictingHostDirectiveBindings = conflictingHostDirectiveBindings;
  }
  static apply(template, directiveMatcher, foreignMatcher, directives, foreignComponents, eagerDirectives, missingDirectives, bindings, references, conflictingHostDirectiveBindings) {
    const matcher = new DirectiveBinder(directiveMatcher, foreignMatcher, directives, foreignComponents, eagerDirectives, missingDirectives, bindings, references, conflictingHostDirectiveBindings);
    matcher.ingest(template);
  }
  ingest(template) {
    template.forEach(node => node.visit(this));
  }
  visitElement(element) {
    this.visitElementOrTemplate(element);
  }
  visitTemplate(template) {
    this.visitElementOrTemplate(template);
  }
  visitDeferredBlock(deferred) {
    const wasInDeferBlock = this.isInDeferBlock;
    this.isInDeferBlock = true;
    deferred.children.forEach(child => child.visit(this));
    this.isInDeferBlock = wasInDeferBlock;
    deferred.placeholder?.visit(this);
    deferred.loading?.visit(this);
    deferred.error?.visit(this);
  }
  visitDeferredBlockPlaceholder(block) {
    block.children.forEach(child => child.visit(this));
  }
  visitDeferredBlockError(block) {
    block.children.forEach(child => child.visit(this));
  }
  visitDeferredBlockLoading(block) {
    block.children.forEach(child => child.visit(this));
  }
  visitSwitchBlock(block) {
    block.groups.forEach(node => node.visit(this));
  }
  visitSwitchBlockCase(block) {}
  visitSwitchBlockCaseGroup(block) {
    block.children.forEach(node => node.visit(this));
  }
  visitSwitchExhaustiveCheck(block) {}
  visitForLoopBlock(block) {
    block.item.visit(this);
    block.contextVariables.forEach(v => v.visit(this));
    block.children.forEach(node => node.visit(this));
    block.empty?.visit(this);
  }
  visitForLoopBlockEmpty(block) {
    block.children.forEach(node => node.visit(this));
  }
  visitIfBlock(block) {
    block.branches.forEach(node => node.visit(this));
  }
  visitIfBlockBranch(block) {
    block.expressionAlias?.visit(this);
    block.children.forEach(node => node.visit(this));
  }
  visitContent(content) {
    content.children.forEach(child => child.visit(this));
  }
  visitContentBlock(block) {
    block.children.forEach(child => child.visit(this));
  }
  visitComponent(node) {
    if (this.directiveMatcher instanceof SelectorlessMatcher) {
      const componentMatches = this.directiveMatcher.match(node.componentName);
      if (componentMatches.length > 0) {
        this.trackSelectorlessMatchesAndDirectives(node, componentMatches);
      } else {
        this.missingDirectives.add(node.componentName);
      }
    }
    node.directives.forEach(directive => directive.visit(this));
    node.children.forEach(child => child.visit(this));
  }
  visitDirective(node) {
    if (this.directiveMatcher instanceof SelectorlessMatcher) {
      const directives = this.directiveMatcher.match(node.name);
      if (directives.length > 0) {
        this.trackSelectorlessMatchesAndDirectives(node, directives);
      } else {
        this.missingDirectives.add(node.name);
      }
    }
  }
  visitElementOrTemplate(node) {
    const matchedDirectives = [];
    if (this.directiveMatcher instanceof SelectorMatcher) {
      const cssSelector = createCssSelectorFromNode(node);
      this.directiveMatcher.match(cssSelector, (_, results) => matchedDirectives.push(...results));
      this.trackSelectorBasedBindingsAndDirectives(node, matchedDirectives);
    } else {
      node.references.forEach(ref => {
        if (ref.value.trim() === '') {
          this.references.set(ref, node);
        }
      });
    }
    if (this.foreignMatcher && node instanceof Element$1) {
      const foreignMatches = this.foreignMatcher.match(node.name);
      if (foreignMatches.length > 0) {
        if (matchedDirectives.length > 0) {
          throw new Error(`Conflict: Element '${node.name}' matches both an Angular directive and a foreign component.`);
        }
        this.foreignComponents.set(node, foreignMatches[0]);
      }
    }
    node.directives.forEach(directive => directive.visit(this));
    node.children.forEach(child => child.visit(this));
  }
  trackMatchedDirectives(node, matchedDirectives) {
    if (matchedDirectives.length > 0) {
      const directives = this.dedupeAndMergeDirectives(node, matchedDirectives);
      this.directives.set(node, directives);
      if (!this.isInDeferBlock) {
        this.eagerDirectives.push(...directives);
      }
    }
  }
  dedupeAndMergeDirectives(node, matches) {
    if (matches.length === 0 || matches.every(dir => dir.matchSource === MatchSource.Selector)) {
      return matches;
    }
    const selectorMatches = new Set();
    const hostDirectives = new Map();
    const mergedHostDirectives = new Map();
    for (const dir of matches) {
      if (dir.matchSource === MatchSource.Selector) {
        selectorMatches.add(dir.ref.key);
      } else {
        if (!hostDirectives.has(dir.ref.key)) {
          hostDirectives.set(dir.ref.key, []);
        }
        hostDirectives.get(dir.ref.key).push(dir);
      }
    }
    for (const [key, directives] of hostDirectives.entries()) {
      if (selectorMatches.has(key)) {
        continue;
      }
      if (directives.length === 1) {
        mergedHostDirectives.set(key, directives[0]);
        continue;
      }
      const inputs = {};
      const outputs = {};
      for (const dir of directives) {
        this.mergeMapping(node, dir, 'input', inputs, dir.inputs);
        this.mergeMapping(node, dir, 'output', outputs, dir.outputs);
      }
      mergedHostDirectives.set(key, {
        ...directives[0],
        inputs: ClassPropertyMapping.fromMappedObject(inputs),
        outputs: ClassPropertyMapping.fromMappedObject(outputs)
      });
    }
    return matches.reduce((result, dir) => {
      if (dir.matchSource === MatchSource.Selector) {
        result.push(dir);
      } else if (mergedHostDirectives.has(dir.ref.key)) {
        result.push(mergedHostDirectives.get(dir.ref.key));
        mergedHostDirectives.delete(dir.ref.key);
      }
      return result;
    }, []);
  }
  mergeMapping(node, directive, kind, accumulator, bindings) {
    for (const binding of bindings) {
      const existing = accumulator[binding.classPropertyName];
      if (!existing) {
        accumulator[binding.classPropertyName] = binding;
        continue;
      }
      if (existing.bindingPropertyName === binding.bindingPropertyName && existing.classPropertyName === binding.classPropertyName && existing.isSignal === binding.isSignal) {
        continue;
      }
      if (!this.conflictingHostDirectiveBindings.has(node)) {
        this.conflictingHostDirectiveBindings.set(node, []);
      }
      const conflictsForNode = this.conflictingHostDirectiveBindings.get(node);
      let conflict = conflictsForNode.find(current => current.directive.ref.key === directive.ref.key && current.kind === kind && current.classPropertyName === binding.classPropertyName);
      if (!conflict) {
        conflict = {
          directive,
          kind,
          classPropertyName: existing.classPropertyName,
          conflictingAliases: new Set([existing.bindingPropertyName])
        };
        conflictsForNode.push(conflict);
      }
      conflict.conflictingAliases.add(binding.bindingPropertyName);
    }
  }
  trackSelectorlessMatchesAndDirectives(node, directives) {
    if (directives.length === 0) {
      return;
    }
    this.trackMatchedDirectives(node, directives);
    const setBinding = (meta, attribute, ioType) => {
      if (meta[ioType].hasBindingPropertyName(attribute.name)) {
        this.bindings.set(attribute, meta);
      }
    };
    for (const directive of directives) {
      node.inputs.forEach(input => setBinding(directive, input, 'inputs'));
      node.attributes.forEach(attr => setBinding(directive, attr, 'inputs'));
      node.outputs.forEach(output => setBinding(directive, output, 'outputs'));
    }
    node.references.forEach(ref => this.references.set(ref, {
      directive: directives[0],
      node: node
    }));
  }
  trackSelectorBasedBindingsAndDirectives(node, directives) {
    this.trackMatchedDirectives(node, directives);
    node.references.forEach(ref => {
      let dirTarget = null;
      if (ref.value.trim() === '') {
        dirTarget = directives.find(dir => dir.isComponent) || null;
      } else {
        dirTarget = directives.find(dir => dir.exportAs !== null && dir.exportAs.some(value => value === ref.value)) || null;
        if (dirTarget === null) {
          return;
        }
      }
      if (dirTarget !== null) {
        this.references.set(ref, {
          directive: dirTarget,
          node
        });
      } else {
        this.references.set(ref, node);
      }
    });
    const setAttributeBinding = (attribute, ioType) => {
      const dir = directives.find(dir => dir[ioType].hasBindingPropertyName(attribute.name));
      const binding = dir !== undefined ? dir : node;
      this.bindings.set(attribute, binding);
    };
    node.inputs.forEach(input => setAttributeBinding(input, 'inputs'));
    node.attributes.forEach(attr => setAttributeBinding(attr, 'inputs'));
    if (node instanceof Template) {
      node.templateAttrs.forEach(attr => setAttributeBinding(attr, 'inputs'));
    }
    node.outputs.forEach(output => setAttributeBinding(output, 'outputs'));
  }
  visitVariable(variable) {}
  visitReference(reference) {}
  visitTextAttribute(attribute) {}
  visitBoundAttribute(attribute) {}
  visitBoundEvent(attribute) {}
  visitBoundAttributeOrEvent(node) {}
  visitText(text) {}
  visitBoundText(text) {}
  visitIcu(icu) {}
  visitDeferredTrigger(trigger) {}
  visitUnknownBlock(block) {}
  visitLetDeclaration(decl) {}
}
class TemplateBinder extends CombinedRecursiveAstVisitor {
  bindings;
  symbols;
  usedPipes;
  eagerPipes;
  deferBlocks;
  nestingLevel;
  scope;
  rootNode;
  level;
  visitNode = node => node.visit(this);
  constructor(bindings, symbols, usedPipes, eagerPipes, deferBlocks, nestingLevel, scope, rootNode, level) {
    super();
    this.bindings = bindings;
    this.symbols = symbols;
    this.usedPipes = usedPipes;
    this.eagerPipes = eagerPipes;
    this.deferBlocks = deferBlocks;
    this.nestingLevel = nestingLevel;
    this.scope = scope;
    this.rootNode = rootNode;
    this.level = level;
  }
  static applyWithScope(nodeOrNodes, scope, expressions, symbols, nestingLevel, usedPipes, eagerPipes, deferBlocks) {
    const template = nodeOrNodes instanceof Template ? nodeOrNodes : null;
    const binder = new TemplateBinder(expressions, symbols, usedPipes, eagerPipes, deferBlocks, nestingLevel, scope, template, 0);
    binder.ingest(nodeOrNodes);
  }
  ingest(nodeOrNodes) {
    if (nodeOrNodes instanceof Template) {
      nodeOrNodes.variables.forEach(this.visitNode);
      nodeOrNodes.children.forEach(this.visitNode);
      this.nestingLevel.set(nodeOrNodes, this.level);
    } else if (nodeOrNodes instanceof IfBlockBranch) {
      if (nodeOrNodes.expressionAlias !== null) {
        this.visitNode(nodeOrNodes.expressionAlias);
      }
      nodeOrNodes.children.forEach(this.visitNode);
      this.nestingLevel.set(nodeOrNodes, this.level);
    } else if (nodeOrNodes instanceof ForLoopBlock) {
      this.visitNode(nodeOrNodes.item);
      nodeOrNodes.contextVariables.forEach(v => this.visitNode(v));
      nodeOrNodes.trackBy?.visit(this);
      nodeOrNodes.children.forEach(this.visitNode);
      this.nestingLevel.set(nodeOrNodes, this.level);
    } else if (nodeOrNodes instanceof DeferredBlock) {
      if (this.scope.rootNode !== nodeOrNodes) {
        throw new Error(`Assertion error: resolved incorrect scope for deferred block ${nodeOrNodes}`);
      }
      this.deferBlocks.push([nodeOrNodes, this.scope]);
      nodeOrNodes.children.forEach(node => node.visit(this));
      this.nestingLevel.set(nodeOrNodes, this.level);
    } else if (nodeOrNodes instanceof SwitchBlockCaseGroup || nodeOrNodes instanceof ForLoopBlockEmpty || nodeOrNodes instanceof DeferredBlockError || nodeOrNodes instanceof DeferredBlockPlaceholder || nodeOrNodes instanceof DeferredBlockLoading || nodeOrNodes instanceof ContentBlock || nodeOrNodes instanceof Content) {
      nodeOrNodes.children.forEach(node => node.visit(this));
      this.nestingLevel.set(nodeOrNodes, this.level);
    } else if (nodeOrNodes instanceof HostElement) {
      this.nestingLevel.set(nodeOrNodes, 0);
    } else {
      nodeOrNodes.forEach(this.visitNode);
    }
  }
  visitTemplate(template) {
    template.inputs.forEach(this.visitNode);
    template.outputs.forEach(this.visitNode);
    template.directives.forEach(this.visitNode);
    template.templateAttrs.forEach(this.visitNode);
    template.references.forEach(this.visitNode);
    this.ingestScopedNode(template);
  }
  visitVariable(variable) {
    if (this.rootNode !== null) {
      this.symbols.set(variable, this.rootNode);
    }
  }
  visitReference(reference) {
    if (this.rootNode !== null) {
      this.symbols.set(reference, this.rootNode);
    }
  }
  visitDeferredBlock(deferred) {
    this.ingestScopedNode(deferred);
    deferred.triggers.when?.value.visit(this);
    deferred.prefetchTriggers.when?.value.visit(this);
    deferred.hydrateTriggers.when?.value.visit(this);
    deferred.hydrateTriggers.never?.visit(this);
    deferred.placeholder && this.visitNode(deferred.placeholder);
    deferred.loading && this.visitNode(deferred.loading);
    deferred.error && this.visitNode(deferred.error);
  }
  visitDeferredBlockPlaceholder(block) {
    this.ingestScopedNode(block);
  }
  visitDeferredBlockError(block) {
    this.ingestScopedNode(block);
  }
  visitDeferredBlockLoading(block) {
    this.ingestScopedNode(block);
  }
  visitSwitchBlockCase(block) {
    block.expression?.visit(this);
  }
  visitSwitchBlockCaseGroup(block) {
    block.cases.forEach(caseNode => caseNode.visit(this));
    this.ingestScopedNode(block);
  }
  visitSwitchExhaustiveCheck(block) {
    block.expression?.visit(this);
  }
  visitForLoopBlock(block) {
    block.expression.visit(this);
    this.ingestScopedNode(block);
    block.empty?.visit(this);
  }
  visitForLoopBlockEmpty(block) {
    this.ingestScopedNode(block);
  }
  visitIfBlockBranch(block) {
    block.expression?.visit(this);
    this.ingestScopedNode(block);
  }
  visitContent(content) {
    this.ingestScopedNode(content);
  }
  visitContentBlock(block) {
    this.ingestScopedNode(block);
  }
  visitLetDeclaration(decl) {
    super.visitLetDeclaration(decl);
    if (this.rootNode !== null) {
      this.symbols.set(decl, this.rootNode);
    }
  }
  visitPipe(ast, context) {
    this.usedPipes.add(ast.name);
    if (!this.scope.isDeferred) {
      this.eagerPipes.add(ast.name);
    }
    return super.visitPipe(ast, context);
  }
  visitPropertyRead(ast, context) {
    this.maybeMap(ast, ast.name);
    return super.visitPropertyRead(ast, context);
  }
  visitSafePropertyRead(ast, context) {
    this.maybeMap(ast, ast.name);
    return super.visitSafePropertyRead(ast, context);
  }
  ingestScopedNode(node) {
    const childScope = this.scope.getChildScope(node);
    const binder = new TemplateBinder(this.bindings, this.symbols, this.usedPipes, this.eagerPipes, this.deferBlocks, this.nestingLevel, childScope, node, this.level + 1);
    binder.ingest(node);
  }
  maybeMap(ast, name) {
    if (!(ast.receiver instanceof ImplicitReceiver)) {
      return;
    }
    const target = this.scope.lookup(name);
    if (target !== null) {
      this.bindings.set(ast, target);
    }
  }
}
class R3BoundTarget {
  target;
  directives;
  foreignComponents;
  eagerDirectives;
  missingDirectives;
  bindings;
  references;
  exprTargets;
  symbols;
  nestingLevel;
  scopedNodeEntities;
  usedPipes;
  eagerPipes;
  conflictingHostDirectiveBindings;
  deferredBlocks;
  deferredScopes;
  constructor(target, directives, foreignComponents, eagerDirectives, missingDirectives, bindings, references, exprTargets, symbols, nestingLevel, scopedNodeEntities, usedPipes, eagerPipes, rawDeferred, conflictingHostDirectiveBindings) {
    this.target = target;
    this.directives = directives;
    this.foreignComponents = foreignComponents;
    this.eagerDirectives = eagerDirectives;
    this.missingDirectives = missingDirectives;
    this.bindings = bindings;
    this.references = references;
    this.exprTargets = exprTargets;
    this.symbols = symbols;
    this.nestingLevel = nestingLevel;
    this.scopedNodeEntities = scopedNodeEntities;
    this.usedPipes = usedPipes;
    this.eagerPipes = eagerPipes;
    this.conflictingHostDirectiveBindings = conflictingHostDirectiveBindings;
    this.deferredBlocks = rawDeferred.map(current => current[0]);
    this.deferredScopes = new Map(rawDeferred);
  }
  getEntitiesInScope(node) {
    return this.scopedNodeEntities.get(node) ?? new Set();
  }
  getDirectivesOfNode(node) {
    return this.directives.get(node) || null;
  }
  getForeignComponent(element) {
    return this.foreignComponents.get(element) || null;
  }
  getReferenceTarget(ref) {
    return this.references.get(ref) || null;
  }
  getConsumerOfBinding(binding) {
    return this.bindings.get(binding) || null;
  }
  getExpressionTarget(expr) {
    return this.exprTargets.get(expr) || null;
  }
  getDefinitionNodeOfSymbol(symbol) {
    return this.symbols.get(symbol) || null;
  }
  getNestingLevel(node) {
    return this.nestingLevel.get(node) || 0;
  }
  getUsedDirectives() {
    const set = new Set();
    this.directives.forEach(dirs => dirs.forEach(dir => set.add(dir)));
    return Array.from(set.values());
  }
  getEagerlyUsedDirectives() {
    const set = new Set(this.eagerDirectives);
    return Array.from(set.values());
  }
  getUsedPipes() {
    return Array.from(this.usedPipes);
  }
  getEagerlyUsedPipes() {
    return Array.from(this.eagerPipes);
  }
  getDeferBlocks() {
    return this.deferredBlocks;
  }
  getDeferredTriggerTarget(block, trigger) {
    if (!(trigger instanceof InteractionDeferredTrigger) && !(trigger instanceof ViewportDeferredTrigger) && !(trigger instanceof HoverDeferredTrigger)) {
      return null;
    }
    const name = trigger.reference;
    if (name === null) {
      let target = null;
      if (block.placeholder !== null) {
        for (const child of block.placeholder.children) {
          if (child instanceof Comment$1) {
            continue;
          }
          if (target !== null) {
            return null;
          }
          if (child instanceof Element$1) {
            target = child;
          }
        }
      }
      return target;
    }
    const outsideRef = this.findEntityInScope(block, name);
    if (outsideRef instanceof Reference && this.getDefinitionNodeOfSymbol(outsideRef) !== block) {
      const target = this.getReferenceTarget(outsideRef);
      if (target !== null) {
        return this.referenceTargetToElement(target);
      }
    }
    if (block.placeholder !== null) {
      const refInPlaceholder = this.findEntityInScope(block.placeholder, name);
      const targetInPlaceholder = refInPlaceholder instanceof Reference ? this.getReferenceTarget(refInPlaceholder) : null;
      if (targetInPlaceholder !== null) {
        return this.referenceTargetToElement(targetInPlaceholder);
      }
    }
    return null;
  }
  isDeferred(element) {
    for (const block of this.deferredBlocks) {
      if (!this.deferredScopes.has(block)) {
        continue;
      }
      const stack = [this.deferredScopes.get(block)];
      while (stack.length > 0) {
        const current = stack.pop();
        if (current.elementLikeInScope.has(element)) {
          return true;
        }
        stack.push(...current.childScopes.values());
      }
    }
    return false;
  }
  referencedDirectiveExists(name) {
    return !this.missingDirectives.has(name);
  }
  getConflictingHostDirectiveBindings(node) {
    return this.conflictingHostDirectiveBindings.get(node) || null;
  }
  findEntityInScope(rootNode, name) {
    const entities = this.getEntitiesInScope(rootNode);
    for (const entity of entities) {
      if (entity.name === name) {
        return entity;
      }
    }
    return null;
  }
  referenceTargetToElement(target) {
    if (target instanceof Element$1) {
      return target;
    }
    if (target instanceof Template || target.node instanceof Component$1 || target.node instanceof Directive$1 || target.node instanceof HostElement) {
      return null;
    }
    return this.referenceTargetToElement(target.node);
  }
}
function extractScopedNodeEntities(rootScope, templateEntities) {
  const entityMap = new Map();
  function extractScopeEntities(scope) {
    if (entityMap.has(scope.rootNode)) {
      return entityMap.get(scope.rootNode);
    }
    const currentEntities = scope.namedEntities;
    let entities;
    if (scope.parentScope !== null) {
      entities = new Map([...extractScopeEntities(scope.parentScope), ...currentEntities]);
    } else {
      entities = new Map(currentEntities);
    }
    entityMap.set(scope.rootNode, entities);
    return entities;
  }
  const scopesToProcess = [rootScope];
  while (scopesToProcess.length > 0) {
    const scope = scopesToProcess.pop();
    for (const childScope of scope.childScopes.values()) {
      scopesToProcess.push(childScope);
    }
    extractScopeEntities(scope);
  }
  for (const [template, entities] of entityMap) {
    templateEntities.set(template, new Set(entities.values()));
  }
}

class ResourceLoader {}

function compileService(meta, resolveForwardRefs) {
  const def = new DefinitionMap();
  def.set('token', meta.type.value);
  def.set('factory', meta.factory === undefined ? delegateToFactory(meta.type.value, meta.type.value, resolveForwardRefs) : arrowFn([], meta.factory.callFn([])));
  if (meta.autoProvided === false) {
    def.set('autoProvided', literal(false));
  }
  const expression = importExpr(Identifiers.defineService).callFn([def.toLiteralMap()], undefined, true);
  return {
    expression,
    type: createInjectableType(),
    statements: []
  };
}

class CompilerFacadeImpl {
  jitEvaluator;
  FactoryTarget = FactoryTarget;
  ResourceLoader = ResourceLoader;
  elementSchemaRegistry = new DomElementSchemaRegistry();
  constructor(jitEvaluator = new JitEvaluator()) {
    this.jitEvaluator = jitEvaluator;
  }
  compilePipe(angularCoreEnv, sourceMapUrl, facade) {
    const metadata = {
      name: facade.name,
      type: wrapReference(facade.type),
      typeArgumentCount: 0,
      pipeName: facade.pipeName,
      pure: facade.pure,
      isStandalone: facade.isStandalone
    };
    const res = compilePipeFromMetadata(metadata);
    return this.jitExpression(res.expression, angularCoreEnv, sourceMapUrl, []);
  }
  compilePipeDeclaration(angularCoreEnv, sourceMapUrl, declaration) {
    const meta = convertDeclarePipeFacadeToMetadata(declaration);
    const res = compilePipeFromMetadata(meta);
    return this.jitExpression(res.expression, angularCoreEnv, sourceMapUrl, []);
  }
  compileInjectable(angularCoreEnv, sourceMapUrl, facade) {
    const {
      expression,
      statements
    } = compileInjectable({
      name: facade.name,
      type: wrapReference(facade.type),
      typeArgumentCount: facade.typeArgumentCount,
      providedIn: computeProvidedIn(facade.providedIn),
      useClass: convertToProviderExpression(facade, 'useClass'),
      useFactory: wrapExpression(facade, 'useFactory'),
      useValue: convertToProviderExpression(facade, 'useValue'),
      useExisting: convertToProviderExpression(facade, 'useExisting'),
      deps: facade.deps?.map(convertR3DependencyMetadata)
    }, true);
    return this.jitExpression(expression, angularCoreEnv, sourceMapUrl, statements);
  }
  compileInjectableDeclaration(angularCoreEnv, sourceMapUrl, facade) {
    const {
      expression,
      statements
    } = compileInjectable({
      name: facade.type.name,
      type: wrapReference(facade.type),
      typeArgumentCount: 0,
      providedIn: computeProvidedIn(facade.providedIn),
      useClass: convertToProviderExpression(facade, 'useClass'),
      useFactory: wrapExpression(facade, 'useFactory'),
      useValue: convertToProviderExpression(facade, 'useValue'),
      useExisting: convertToProviderExpression(facade, 'useExisting'),
      deps: facade.deps?.map(convertR3DeclareDependencyMetadata)
    }, true);
    return this.jitExpression(expression, angularCoreEnv, sourceMapUrl, statements);
  }
  compileInjector(angularCoreEnv, sourceMapUrl, facade) {
    const meta = {
      type: wrapReference(facade.type),
      providers: facade.providers && facade.providers.length > 0 ? new WrappedNodeExpr(facade.providers) : null,
      imports: facade.imports.map(i => new WrappedNodeExpr(i))
    };
    const res = compileInjector(meta);
    return this.jitExpression(res.expression, angularCoreEnv, sourceMapUrl, []);
  }
  compileInjectorDeclaration(angularCoreEnv, sourceMapUrl, declaration) {
    const meta = convertDeclareInjectorFacadeToMetadata(declaration);
    const res = compileInjector(meta);
    return this.jitExpression(res.expression, angularCoreEnv, sourceMapUrl, []);
  }
  compileNgModule(angularCoreEnv, sourceMapUrl, facade) {
    const meta = {
      kind: R3NgModuleMetadataKind.Global,
      type: wrapReference(facade.type),
      bootstrap: facade.bootstrap.map(wrapReference),
      declarations: facade.declarations.map(wrapReference),
      publicDeclarationTypes: null,
      imports: facade.imports.map(wrapReference),
      includeImportTypes: true,
      exports: facade.exports.map(wrapReference),
      selectorScopeMode: R3SelectorScopeMode.Inline,
      containsForwardDecls: false,
      schemas: facade.schemas ? facade.schemas.map(wrapReference) : null,
      id: facade.id ? new WrappedNodeExpr(facade.id) : null
    };
    const res = compileNgModule(meta);
    return this.jitExpression(res.expression, angularCoreEnv, sourceMapUrl, []);
  }
  compileNgModuleDeclaration(angularCoreEnv, sourceMapUrl, declaration) {
    const expression = compileNgModuleDeclarationExpression(declaration);
    return this.jitExpression(expression, angularCoreEnv, sourceMapUrl, []);
  }
  compileDirective(angularCoreEnv, sourceMapUrl, facade) {
    const meta = convertDirectiveFacadeToMetadata(facade);
    return this.compileDirectiveFromMeta(angularCoreEnv, sourceMapUrl, meta);
  }
  compileDirectiveDeclaration(angularCoreEnv, sourceMapUrl, declaration) {
    const typeSourceSpan = this.createParseSourceSpan('Directive', declaration.type.name, sourceMapUrl);
    const meta = convertDeclareDirectiveFacadeToMetadata(declaration, typeSourceSpan);
    return this.compileDirectiveFromMeta(angularCoreEnv, sourceMapUrl, meta);
  }
  compileService(angularCoreEnv, sourceMapUrl, facade) {
    const {
      expression,
      statements
    } = compileService({
      type: wrapReference(facade.type),
      autoProvided: facade.autoProvided,
      factory: facade.factory ? wrapExpression(facade, 'factory') : undefined
    }, true);
    return this.jitExpression(expression, angularCoreEnv, sourceMapUrl, statements);
  }
  compileServiceDeclaration(angularCoreEnv, sourceMapUrl, facade) {
    const {
      expression,
      statements
    } = compileService({
      type: wrapReference(facade.type),
      autoProvided: facade.autoProvided,
      factory: facade.factory ? wrapExpression(facade, 'factory') : undefined
    }, true);
    return this.jitExpression(expression, angularCoreEnv, sourceMapUrl, statements);
  }
  compileDirectiveFromMeta(angularCoreEnv, sourceMapUrl, meta) {
    const constantPool = new ConstantPool();
    const bindingParser = makeBindingParser();
    const res = compileDirectiveFromMetadata(meta, constantPool, bindingParser);
    return this.jitExpression(res.expression, angularCoreEnv, sourceMapUrl, constantPool.statements);
  }
  compileComponent(angularCoreEnv, sourceMapUrl, facade) {
    const {
      template,
      defer
    } = parseJitTemplate(facade.template, facade.name, sourceMapUrl, facade.preserveWhitespaces, undefined);
    const meta = {
      ...facade,
      ...convertDirectiveFacadeToMetadata(facade),
      selector: facade.selector || this.elementSchemaRegistry.getDefaultComponentElementName(),
      template,
      declarations: facade.declarations.map(convertDeclarationFacadeToMetadata),
      declarationListEmitMode: 0,
      defer,
      styles: [...facade.styles, ...template.styles],
      encapsulation: facade.encapsulation,
      changeDetection: facade.changeDetection ?? null,
      animations: facade.animations != null ? new WrappedNodeExpr(facade.animations) : null,
      viewProviders: facade.viewProviders != null ? new WrappedNodeExpr(facade.viewProviders) : null,
      relativeContextFilePath: '',
      i18nUseExternalIds: true,
      relativeTemplatePath: null,
      foreignImports: null,
      enableTemplateSourceLocations: false
    };
    const jitExpressionSourceMap = `ng:///${facade.name}.js`;
    return this.compileComponentFromMeta(angularCoreEnv, jitExpressionSourceMap, meta);
  }
  compileComponentDeclaration(angularCoreEnv, sourceMapUrl, declaration) {
    const typeSourceSpan = this.createParseSourceSpan('Component', declaration.type.name, sourceMapUrl);
    const meta = convertDeclareComponentFacadeToMetadata(declaration, typeSourceSpan, sourceMapUrl);
    return this.compileComponentFromMeta(angularCoreEnv, sourceMapUrl, meta);
  }
  compileComponentFromMeta(angularCoreEnv, sourceMapUrl, meta) {
    const constantPool = new ConstantPool();
    const bindingParser = makeBindingParser();
    const res = compileComponentFromMetadata(meta, constantPool, bindingParser);
    return this.jitExpression(res.expression, angularCoreEnv, sourceMapUrl, constantPool.statements);
  }
  compileFactory(angularCoreEnv, sourceMapUrl, meta) {
    const factoryRes = compileFactoryFunction({
      name: meta.name,
      type: wrapReference(meta.type),
      typeArgumentCount: meta.typeArgumentCount,
      deps: convertR3DependencyMetadataArray(meta.deps),
      target: meta.target
    });
    return this.jitExpression(factoryRes.expression, angularCoreEnv, sourceMapUrl, factoryRes.statements);
  }
  compileFactoryDeclaration(angularCoreEnv, sourceMapUrl, meta) {
    const factoryRes = compileFactoryFunction({
      name: meta.type.name,
      type: wrapReference(meta.type),
      typeArgumentCount: 0,
      deps: Array.isArray(meta.deps) ? meta.deps.map(convertR3DeclareDependencyMetadata) : meta.deps,
      target: meta.target
    });
    return this.jitExpression(factoryRes.expression, angularCoreEnv, sourceMapUrl, factoryRes.statements);
  }
  createParseSourceSpan(kind, typeName, sourceUrl) {
    return r3JitTypeSourceSpan(kind, typeName, sourceUrl);
  }
  jitExpression(def, context, sourceUrl, preStatements) {
    const statements = [...preStatements, new DeclareVarStmt('$def', def, undefined, StmtModifier.Exported)];
    const res = this.jitEvaluator.evaluateStatements(sourceUrl, statements, new R3JitReflector(context), true);
    return res['$def'];
  }
}
function convertToR3QueryMetadata(facade) {
  return {
    ...facade,
    isSignal: facade.isSignal,
    predicate: convertQueryPredicate(facade.predicate),
    read: facade.read ? new WrappedNodeExpr(facade.read) : null,
    static: facade.static,
    emitDistinctChangesOnly: facade.emitDistinctChangesOnly
  };
}
function convertQueryDeclarationToMetadata(declaration) {
  return {
    propertyName: declaration.propertyName,
    first: declaration.first ?? false,
    predicate: convertQueryPredicate(declaration.predicate),
    descendants: declaration.descendants ?? false,
    read: declaration.read ? new WrappedNodeExpr(declaration.read) : null,
    static: declaration.static ?? false,
    emitDistinctChangesOnly: declaration.emitDistinctChangesOnly ?? true,
    isSignal: !!declaration.isSignal
  };
}
function convertQueryPredicate(predicate) {
  return Array.isArray(predicate) ? predicate : createMayBeForwardRefExpression(new WrappedNodeExpr(predicate), 1);
}
function convertDirectiveFacadeToMetadata(facade) {
  const inputsFromMetadata = parseInputsArray(facade.inputs || []);
  const outputsFromMetadata = parseMappingStringArray(facade.outputs || []);
  const propMetadata = facade.propMetadata;
  const inputsFromType = {};
  const outputsFromType = {};
  for (const field in propMetadata) {
    if (Object.hasOwn(propMetadata, field)) {
      propMetadata[field].forEach(ann => {
        if (isInput(ann)) {
          inputsFromType[field] = {
            bindingPropertyName: ann.alias || field,
            classPropertyName: field,
            required: ann.required || false,
            isSignal: !!ann.isSignal,
            transformFunction: ann.transform != null ? new WrappedNodeExpr(ann.transform) : null
          };
        } else if (isOutput(ann)) {
          outputsFromType[field] = ann.alias || field;
        }
      });
    }
  }
  const hostDirectives = facade.hostDirectives?.length ? facade.hostDirectives.map(hostDirective => {
    return typeof hostDirective === 'function' ? {
      directive: wrapReference(hostDirective),
      inputs: null,
      outputs: null,
      isForwardReference: false
    } : {
      directive: wrapReference(hostDirective.directive),
      isForwardReference: false,
      inputs: hostDirective.inputs ? parseMappingStringArray(hostDirective.inputs) : null,
      outputs: hostDirective.outputs ? parseMappingStringArray(hostDirective.outputs) : null
    };
  }) : null;
  return {
    ...facade,
    typeArgumentCount: 0,
    typeSourceSpan: facade.typeSourceSpan,
    type: wrapReference(facade.type),
    deps: null,
    host: {
      ...extractHostBindings(facade.propMetadata, facade.typeSourceSpan, facade.host)
    },
    inputs: {
      ...inputsFromMetadata,
      ...inputsFromType
    },
    outputs: {
      ...outputsFromMetadata,
      ...outputsFromType
    },
    queries: facade.queries.map(convertToR3QueryMetadata),
    providers: facade.providers != null ? new WrappedNodeExpr(facade.providers) : null,
    viewQueries: facade.viewQueries.map(convertToR3QueryMetadata),
    hostDirectives
  };
}
function convertDeclareDirectiveFacadeToMetadata(declaration, typeSourceSpan) {
  const hostDirectives = declaration.hostDirectives?.length ? declaration.hostDirectives.map(dir => ({
    directive: wrapReference(dir.directive),
    isForwardReference: false,
    inputs: dir.inputs ? getHostDirectiveBindingMapping(dir.inputs) : null,
    outputs: dir.outputs ? getHostDirectiveBindingMapping(dir.outputs) : null
  })) : null;
  return {
    name: declaration.type.name,
    type: wrapReference(declaration.type),
    typeSourceSpan,
    selector: declaration.selector ?? null,
    inputs: declaration.inputs ? inputsPartialMetadataToInputMetadata(declaration.inputs) : {},
    outputs: declaration.outputs ?? {},
    host: convertHostDeclarationToMetadata(declaration.host),
    queries: (declaration.queries ?? []).map(convertQueryDeclarationToMetadata),
    viewQueries: (declaration.viewQueries ?? []).map(convertQueryDeclarationToMetadata),
    providers: declaration.providers !== undefined ? new WrappedNodeExpr(declaration.providers) : null,
    exportAs: declaration.exportAs ?? null,
    usesInheritance: declaration.usesInheritance ?? false,
    controlCreate: declaration.controlCreate ?? null,
    lifecycle: {
      usesOnChanges: declaration.usesOnChanges ?? false
    },
    deps: null,
    typeArgumentCount: 0,
    isStandalone: declaration.isStandalone ?? getJitStandaloneDefaultForVersion(declaration.version),
    isSignal: declaration.isSignal ?? false,
    hostDirectives,
    legacyOptionalChaining: declaration.legacyOptionalChaining ?? LEGACY_OPTIONAL_CHAINING_DEFAULT
  };
}
function convertHostDeclarationToMetadata(host = {}) {
  return {
    attributes: convertOpaqueValuesToExpressions(host.attributes ?? {}),
    listeners: host.listeners ?? {},
    properties: host.properties ?? {},
    specialAttributes: {
      classAttr: host.classAttribute,
      styleAttr: host.styleAttribute
    }
  };
}
function getHostDirectiveBindingMapping(array) {
  let result = null;
  for (let i = 1; i < array.length; i += 2) {
    result = result || {};
    result[array[i - 1]] = array[i];
  }
  return result;
}
function convertOpaqueValuesToExpressions(obj) {
  const result = {};
  for (const key of Object.keys(obj)) {
    result[key] = new WrappedNodeExpr(obj[key]);
  }
  return result;
}
function convertDeclareComponentFacadeToMetadata(decl, typeSourceSpan, sourceMapUrl) {
  const {
    template,
    defer
  } = parseJitTemplate(decl.template, decl.type.name, sourceMapUrl, decl.preserveWhitespaces ?? false, decl.deferBlockDependencies);
  const declarations = [];
  if (decl.dependencies) {
    for (const innerDep of decl.dependencies) {
      switch (innerDep.kind) {
        case 'directive':
        case 'component':
          declarations.push(convertDirectiveDeclarationToMetadata(innerDep));
          break;
        case 'pipe':
          declarations.push(convertPipeDeclarationToMetadata(innerDep));
          break;
        case 'ngmodule':
          declarations.push(convertNgModuleDeclarationToMetadata(innerDep));
          break;
      }
    }
  } else if (decl.components || decl.directives || decl.pipes) {
    decl.components && declarations.push(...decl.components.map(dir => convertDirectiveDeclarationToMetadata(dir, true)));
    decl.directives && declarations.push(...decl.directives.map(dir => convertDirectiveDeclarationToMetadata(dir)));
    decl.pipes && declarations.push(...convertPipeMapToMetadata(decl.pipes));
  }
  const hasDirectiveDependencies = declarations.some(({
    kind
  }) => kind === R3TemplateDependencyKind.Directive || kind === R3TemplateDependencyKind.NgModule);
  return {
    ...convertDeclareDirectiveFacadeToMetadata(decl, typeSourceSpan),
    template,
    styles: decl.styles ?? [],
    declarations,
    viewProviders: decl.viewProviders !== undefined ? new WrappedNodeExpr(decl.viewProviders) : null,
    animations: decl.animations !== undefined ? new WrappedNodeExpr(decl.animations) : null,
    defer,
    changeDetection: decl.changeDetection ?? ChangeDetectionStrategy.OnPush,
    encapsulation: decl.encapsulation ?? ViewEncapsulation$1.Emulated,
    declarationListEmitMode: 2,
    relativeContextFilePath: '',
    i18nUseExternalIds: true,
    relativeTemplatePath: null,
    hasDirectiveDependencies,
    legacyOptionalChaining: decl.legacyOptionalChaining ?? LEGACY_OPTIONAL_CHAINING_DEFAULT,
    foreignImports: null,
    enableTemplateSourceLocations: false
  };
}
function convertDeclarationFacadeToMetadata(declaration) {
  return {
    ...declaration,
    type: new WrappedNodeExpr(declaration.type)
  };
}
function convertDirectiveDeclarationToMetadata(declaration, isComponent = null) {
  return {
    kind: R3TemplateDependencyKind.Directive,
    isComponent: isComponent || declaration.kind === 'component',
    selector: declaration.selector,
    type: new WrappedNodeExpr(declaration.type),
    inputs: declaration.inputs ?? [],
    outputs: declaration.outputs ?? [],
    exportAs: declaration.exportAs ?? null
  };
}
function convertPipeMapToMetadata(pipes) {
  if (!pipes) {
    return [];
  }
  return Object.keys(pipes).map(name => {
    return {
      kind: R3TemplateDependencyKind.Pipe,
      name,
      type: new WrappedNodeExpr(pipes[name])
    };
  });
}
function convertPipeDeclarationToMetadata(pipe) {
  return {
    kind: R3TemplateDependencyKind.Pipe,
    name: pipe.name,
    type: new WrappedNodeExpr(pipe.type)
  };
}
function convertNgModuleDeclarationToMetadata(ngModule) {
  return {
    kind: R3TemplateDependencyKind.NgModule,
    type: new WrappedNodeExpr(ngModule.type)
  };
}
function parseJitTemplate(template, typeName, sourceMapUrl, preserveWhitespaces, deferBlockDependencies) {
  const parsed = parseTemplate(template, sourceMapUrl, {
    preserveWhitespaces
  });
  if (parsed.errors !== null) {
    const errors = parsed.errors.map(err => err.toString()).join(', ');
    throw new Error(`Errors during JIT compilation of template for ${typeName}: ${errors}`);
  }
  const binder = new R3TargetBinder(null);
  const boundTarget = binder.bind({
    template: parsed.nodes
  });
  return {
    template: parsed,
    defer: createR3ComponentDeferMetadata(boundTarget, deferBlockDependencies)
  };
}
function convertToProviderExpression(obj, property) {
  if (Object.hasOwn(obj, property)) {
    return createMayBeForwardRefExpression(new WrappedNodeExpr(obj[property]), 0);
  } else {
    return undefined;
  }
}
function wrapExpression(obj, property) {
  if (Object.hasOwn(obj, property)) {
    return new WrappedNodeExpr(obj[property]);
  } else {
    return undefined;
  }
}
function computeProvidedIn(providedIn) {
  const expression = typeof providedIn === 'function' ? new WrappedNodeExpr(providedIn) : new LiteralExpr(providedIn ?? null);
  return createMayBeForwardRefExpression(expression, 0);
}
function convertR3DependencyMetadataArray(facades) {
  return facades == null ? null : facades.map(convertR3DependencyMetadata);
}
function convertR3DependencyMetadata(facade) {
  const isAttributeDep = facade.attribute != null;
  const rawToken = facade.token === null ? null : new WrappedNodeExpr(facade.token);
  const token = isAttributeDep ? new WrappedNodeExpr(facade.attribute) : rawToken;
  return createR3DependencyMetadata(token, isAttributeDep, facade.host, facade.optional, facade.self, facade.skipSelf);
}
function convertR3DeclareDependencyMetadata(facade) {
  const isAttributeDep = facade.attribute ?? false;
  const token = facade.token === null ? null : new WrappedNodeExpr(facade.token);
  return createR3DependencyMetadata(token, isAttributeDep, facade.host ?? false, facade.optional ?? false, facade.self ?? false, facade.skipSelf ?? false);
}
function createR3DependencyMetadata(token, isAttributeDep, host, optional, self, skipSelf) {
  const attributeNameType = isAttributeDep ? literal('unknown') : null;
  return {
    token,
    attributeNameType,
    host,
    optional,
    self,
    skipSelf
  };
}
function createR3ComponentDeferMetadata(boundTarget, deferBlockDependencies) {
  const deferredBlocks = boundTarget.getDeferBlocks();
  const blocks = new Map();
  for (let i = 0; i < deferredBlocks.length; i++) {
    const dependencyFn = deferBlockDependencies?.[i];
    blocks.set(deferredBlocks[i], dependencyFn ? new WrappedNodeExpr(dependencyFn) : null);
  }
  return {
    mode: 0,
    blocks
  };
}
function extractHostBindings(propMetadata, sourceSpan, host) {
  const bindings = parseHostBindings(host || {});
  for (const field in propMetadata) {
    if (Object.hasOwn(propMetadata, field)) {
      propMetadata[field].forEach(ann => {
        if (isHostBinding(ann)) {
          bindings.properties[ann.hostPropertyName || field] = getSafePropertyAccessString('this', field);
        } else if (isHostListener(ann)) {
          bindings.listeners[ann.eventName || field] = `${field}(${(ann.args || []).join(',')})`;
        }
      });
    }
  }
  const errors = verifyHostBindings(bindings, sourceSpan);
  if (errors.length) {
    throw new Error(errors.map(error => error.msg).join('\n'));
  }
  return bindings;
}
function isHostBinding(value) {
  return value.ngMetadataName === 'HostBinding';
}
function isHostListener(value) {
  return value.ngMetadataName === 'HostListener';
}
function isInput(value) {
  return value.ngMetadataName === 'Input';
}
function isOutput(value) {
  return value.ngMetadataName === 'Output';
}
function inputsPartialMetadataToInputMetadata(inputs) {
  return Object.keys(inputs).reduce((result, minifiedClassName) => {
    const value = inputs[minifiedClassName];
    if (typeof value === 'string' || Array.isArray(value)) {
      result[minifiedClassName] = parseLegacyInputPartialOutput(value);
    } else {
      result[minifiedClassName] = {
        bindingPropertyName: value.publicName,
        classPropertyName: minifiedClassName,
        transformFunction: value.transformFunction !== null ? new WrappedNodeExpr(value.transformFunction) : null,
        required: value.isRequired,
        isSignal: value.isSignal
      };
    }
    return result;
  }, {});
}
function parseLegacyInputPartialOutput(value) {
  if (typeof value === 'string') {
    return {
      bindingPropertyName: value,
      classPropertyName: value,
      transformFunction: null,
      required: false,
      isSignal: false
    };
  }
  return {
    bindingPropertyName: value[0],
    classPropertyName: value[1],
    transformFunction: value[2] ? new WrappedNodeExpr(value[2]) : null,
    required: false,
    isSignal: false
  };
}
function parseInputsArray(values) {
  return values.reduce((results, value) => {
    if (typeof value === 'string') {
      const [bindingPropertyName, classPropertyName] = parseMappingString(value);
      results[classPropertyName] = {
        bindingPropertyName,
        classPropertyName,
        required: false,
        isSignal: false,
        transformFunction: null
      };
    } else {
      results[value.name] = {
        bindingPropertyName: value.alias || value.name,
        classPropertyName: value.name,
        required: value.required || false,
        isSignal: false,
        transformFunction: value.transform != null ? new WrappedNodeExpr(value.transform) : null
      };
    }
    return results;
  }, {});
}
function parseMappingStringArray(values) {
  return values.reduce((results, value) => {
    const [alias, fieldName] = parseMappingString(value);
    results[fieldName] = alias;
    return results;
  }, {});
}
function parseMappingString(value) {
  const [fieldName, bindingPropertyName] = value.split(':', 2).map(str => str.trim());
  return [bindingPropertyName ?? fieldName, fieldName];
}
function convertDeclarePipeFacadeToMetadata(declaration) {
  return {
    name: declaration.type.name,
    type: wrapReference(declaration.type),
    typeArgumentCount: 0,
    pipeName: declaration.name,
    deps: null,
    pure: declaration.pure ?? true,
    isStandalone: declaration.isStandalone ?? getJitStandaloneDefaultForVersion(declaration.version)
  };
}
function convertDeclareInjectorFacadeToMetadata(declaration) {
  return {
    name: declaration.type.name,
    type: wrapReference(declaration.type),
    providers: declaration.providers !== undefined && declaration.providers.length > 0 ? new WrappedNodeExpr(declaration.providers) : null,
    imports: declaration.imports !== undefined ? declaration.imports.map(i => new WrappedNodeExpr(i)) : []
  };
}
function publishFacade(global) {
  const ng = global.ng || (global.ng = {});
  ng.ɵcompilerFacade = new CompilerFacadeImpl();
}

class CompilerConfig {
  defaultEncapsulation;
  preserveWhitespaces;
  strictInjectionParameters;
  constructor({
    defaultEncapsulation = ViewEncapsulation$1.Emulated,
    preserveWhitespaces,
    strictInjectionParameters
  } = {}) {
    this.defaultEncapsulation = defaultEncapsulation;
    this.preserveWhitespaces = preserveWhitespacesDefault(noUndefined(preserveWhitespaces));
    this.strictInjectionParameters = strictInjectionParameters === true;
  }
}
function preserveWhitespacesDefault(preserveWhitespacesOption, defaultSetting = false) {
  return preserveWhitespacesOption === null ? defaultSetting : preserveWhitespacesOption;
}

const _I18N_ATTR = 'i18n';
const _I18N_ATTR_PREFIX = 'i18n-';
const _I18N_COMMENT_PREFIX_REGEXP = /^i18n:?/;
const MEANING_SEPARATOR = '|';
const ID_SEPARATOR = '@@';
let i18nCommentsWarned = false;
function extractMessages(nodes, implicitTags, implicitAttrs, preserveSignificantWhitespace) {
  const visitor = new _Visitor(implicitTags, implicitAttrs, preserveSignificantWhitespace);
  return visitor.extract(nodes);
}
function mergeTranslations(nodes, translations, implicitTags, implicitAttrs) {
  const visitor = new _Visitor(implicitTags, implicitAttrs);
  return visitor.merge(nodes, translations);
}
class ExtractionResult {
  messages;
  errors;
  constructor(messages, errors) {
    this.messages = messages;
    this.errors = errors;
  }
}
var _VisitorMode;
(function (_VisitorMode) {
  _VisitorMode[_VisitorMode["Extract"] = 0] = "Extract";
  _VisitorMode[_VisitorMode["Merge"] = 1] = "Merge";
})(_VisitorMode || (_VisitorMode = {}));
class _Visitor {
  _implicitTags;
  _implicitAttrs;
  _preserveSignificantWhitespace;
  _depth;
  _inI18nNode;
  _inImplicitNode;
  _inI18nBlock;
  _blockMeaningAndDesc;
  _blockChildren;
  _blockStartDepth;
  _inIcu;
  _msgCountAtSectionStart;
  _errors;
  _mode;
  _messages;
  _translations;
  _createI18nMessage;
  constructor(_implicitTags, _implicitAttrs, _preserveSignificantWhitespace = true) {
    this._implicitTags = _implicitTags;
    this._implicitAttrs = _implicitAttrs;
    this._preserveSignificantWhitespace = _preserveSignificantWhitespace;
  }
  extract(nodes) {
    this._init(_VisitorMode.Extract);
    nodes.forEach(node => node.visit(this, null));
    if (this._inI18nBlock) {
      this._reportError(nodes[nodes.length - 1], 'Unclosed block');
    }
    return new ExtractionResult(this._messages, this._errors);
  }
  merge(nodes, translations) {
    this._init(_VisitorMode.Merge);
    this._translations = translations;
    const wrapper = new Element('wrapper', [], [], nodes, false, undefined, undefined, undefined, false);
    const translatedNode = wrapper.visit(this, null);
    if (this._inI18nBlock) {
      this._reportError(nodes[nodes.length - 1], 'Unclosed block');
    }
    return new ParseTreeResult(translatedNode.children, this._errors);
  }
  visitExpansionCase(icuCase, context) {
    const expression = visitAll(this, icuCase.expression, context);
    if (this._mode === _VisitorMode.Merge) {
      return new ExpansionCase(icuCase.value, expression, icuCase.sourceSpan, icuCase.valueSourceSpan, icuCase.expSourceSpan);
    }
  }
  visitExpansion(icu, context) {
    this._mayBeAddBlockChildren(icu);
    const wasInIcu = this._inIcu;
    if (!this._inIcu) {
      if (this._isInTranslatableSection) {
        this._addMessage([icu]);
      }
      this._inIcu = true;
    }
    const cases = visitAll(this, icu.cases, context);
    if (this._mode === _VisitorMode.Merge) {
      icu = new Expansion(icu.switchValue, icu.type, cases, icu.sourceSpan, icu.switchValueSourceSpan);
    }
    this._inIcu = wasInIcu;
    return icu;
  }
  visitComment(comment, context) {
    const isOpening = _isOpeningComment(comment);
    if (isOpening && this._isInTranslatableSection) {
      this._reportError(comment, 'Could not start a block inside a translatable section');
      return;
    }
    const isClosing = _isClosingComment(comment);
    if (isClosing && !this._inI18nBlock) {
      this._reportError(comment, 'Trying to close an unopened block');
      return;
    }
    if (!this._inI18nNode && !this._inIcu) {
      if (!this._inI18nBlock) {
        if (isOpening) {
          if (!i18nCommentsWarned && typeof console?.warn === 'function') {
            i18nCommentsWarned = true;
            const details = comment.sourceSpan.details ? `, ${comment.sourceSpan.details}` : '';
            console.warn(`I18n comments are deprecated, use an <ng-container> element instead (${comment.sourceSpan.start}${details})`);
          }
          this._inI18nBlock = true;
          this._blockStartDepth = this._depth;
          this._blockChildren = [];
          this._blockMeaningAndDesc = comment.value.replace(_I18N_COMMENT_PREFIX_REGEXP, '').trim();
          this._openTranslatableSection(comment);
        }
      } else {
        if (isClosing) {
          if (this._depth == this._blockStartDepth) {
            this._closeTranslatableSection(comment, this._blockChildren);
            this._inI18nBlock = false;
            const message = this._addMessage(this._blockChildren, this._blockMeaningAndDesc);
            const nodes = this._translateMessage(comment, message);
            return visitAll(this, nodes);
          } else {
            this._reportError(comment, 'I18N blocks should not cross element boundaries');
            return;
          }
        }
      }
    }
  }
  visitText(text, context) {
    if (this._isInTranslatableSection) {
      this._mayBeAddBlockChildren(text);
    }
    return text;
  }
  visitElement(el, context) {
    return this._visitElementLike(el, context);
  }
  visitAttribute(attribute, context) {
    throw new Error('unreachable code');
  }
  visitBlock(block, context) {
    visitAll(this, block.children, context);
  }
  visitBlockParameter(parameter, context) {}
  visitLetDeclaration(decl, context) {}
  visitComponent(component, context) {
    return this._visitElementLike(component, context);
  }
  visitDirective(directive, context) {
    throw new Error('unreachable code');
  }
  _init(mode) {
    this._mode = mode;
    this._inI18nBlock = false;
    this._inI18nNode = false;
    this._depth = 0;
    this._inIcu = false;
    this._msgCountAtSectionStart = undefined;
    this._errors = [];
    this._messages = [];
    this._inImplicitNode = false;
    this._createI18nMessage = createI18nMessageFactory(!this._preserveSignificantWhitespace, this._preserveSignificantWhitespace);
  }
  _visitElementLike(node, context) {
    this._mayBeAddBlockChildren(node);
    this._depth++;
    const wasInI18nNode = this._inI18nNode;
    const wasInImplicitNode = this._inImplicitNode;
    let childNodes = [];
    let translatedChildNodes = undefined;
    const nodeName = node instanceof Component ? node.tagName : node.name;
    const i18nAttr = _getI18nAttr(node);
    const i18nMeta = i18nAttr ? i18nAttr.value : '';
    const isImplicit = this._implicitTags.some(tag => nodeName === tag) && !this._inIcu && !this._isInTranslatableSection;
    const isTopLevelImplicit = !wasInImplicitNode && isImplicit;
    this._inImplicitNode = wasInImplicitNode || isImplicit;
    if (!this._isInTranslatableSection && !this._inIcu) {
      if (i18nAttr || isTopLevelImplicit) {
        this._inI18nNode = true;
        const message = this._addMessage(node.children, i18nMeta);
        translatedChildNodes = this._translateMessage(node, message);
      }
      if (this._mode == _VisitorMode.Extract) {
        const isTranslatable = i18nAttr || isTopLevelImplicit;
        if (isTranslatable) this._openTranslatableSection(node);
        visitAll(this, node.children);
        if (isTranslatable) this._closeTranslatableSection(node, node.children);
      }
    } else {
      if (i18nAttr || isTopLevelImplicit) {
        this._reportError(node, 'Could not mark an element as translatable inside a translatable section');
      }
      if (this._mode == _VisitorMode.Extract) {
        visitAll(this, node.children);
      }
    }
    if (this._mode === _VisitorMode.Merge) {
      const visitNodes = translatedChildNodes || node.children;
      visitNodes.forEach(child => {
        const visited = child.visit(this, context);
        if (visited && !this._isInTranslatableSection) {
          childNodes = childNodes.concat(visited);
        }
      });
    }
    this._visitAttributesOf(node);
    this._depth--;
    this._inI18nNode = wasInI18nNode;
    this._inImplicitNode = wasInImplicitNode;
    if (this._mode === _VisitorMode.Merge) {
      if (node instanceof Element) {
        return new Element(node.name, this._translateAttributes(node), this._translateDirectives(node), childNodes, node.isSelfClosing, node.sourceSpan, node.startSourceSpan, node.endSourceSpan, node.isVoid);
      } else {
        return new Component(node.componentName, node.tagName, node.fullName, this._translateAttributes(node), this._translateDirectives(node), childNodes, node.isSelfClosing, node.sourceSpan, node.startSourceSpan, node.endSourceSpan);
      }
    }
    return null;
  }
  _visitAttributesOf(el) {
    const explicitAttrNameToValue = {};
    const implicitAttrNames = this._implicitAttrs[el instanceof Component ? el.tagName || '' : el.name] || [];
    el.attrs.filter(attr => attr instanceof Attribute && attr.name.startsWith(_I18N_ATTR_PREFIX)).forEach(attr => {
      explicitAttrNameToValue[attr.name.slice(_I18N_ATTR_PREFIX.length)] = attr.value;
    });
    el.attrs.forEach(attr => {
      if (attr.name in explicitAttrNameToValue) {
        this._addMessage([attr], explicitAttrNameToValue[attr.name]);
      } else if (implicitAttrNames.some(name => attr.name === name)) {
        this._addMessage([attr]);
      }
    });
  }
  _addMessage(ast, msgMeta) {
    if (ast.length == 0 || this._isEmptyAttributeValue(ast) || this._isPlaceholderOnlyAttributeValue(ast) || this._isPlaceholderOnlyMessage(ast)) {
      return null;
    }
    const {
      meaning,
      description,
      id
    } = _parseMessageMeta(msgMeta);
    const message = this._createI18nMessage(ast, meaning, description, id);
    this._messages.push(message);
    return message;
  }
  _isEmptyAttributeValue(ast) {
    if (!isAttrNode(ast)) return false;
    const node = ast[0];
    return node.value.trim() === '';
  }
  _isPlaceholderOnlyAttributeValue(ast) {
    if (!isAttrNode(ast)) return false;
    const tokens = ast[0].valueTokens ?? [];
    const interpolations = tokens.filter(token => token.type === 18);
    const plainText = tokens.filter(token => token.type === 17).map(token => token.parts[0].trim()).join('');
    return interpolations.length === 1 && plainText === '';
  }
  _isPlaceholderOnlyMessage(ast) {
    if (!isTextNode(ast)) return false;
    const tokens = ast[0].tokens;
    const interpolations = tokens.filter(token => token.type === 8);
    const plainText = tokens.filter(token => token.type === 5).map(token => token.parts[0].trim()).join('');
    return interpolations.length === 1 && plainText === '';
  }
  _translateMessage(el, message) {
    if (message && this._mode === _VisitorMode.Merge) {
      const nodes = this._translations.get(message);
      if (nodes) {
        return nodes;
      }
      this._reportError(el, `Translation unavailable for message id="${this._translations.digest(message)}"`);
    }
    return [];
  }
  _translateAttributes(node) {
    const i18nParsedMessageMeta = {};
    const translatedAttributes = [];
    node.attrs.forEach(attr => {
      if (attr.name.startsWith(_I18N_ATTR_PREFIX)) {
        i18nParsedMessageMeta[attr.name.slice(_I18N_ATTR_PREFIX.length)] = _parseMessageMeta(attr.value);
      }
    });
    node.attrs.forEach(attr => {
      if (attr.name === _I18N_ATTR || attr.name.startsWith(_I18N_ATTR_PREFIX)) {
        return;
      }
      if (attr.value && attr.value != '' && Object.hasOwn(i18nParsedMessageMeta, attr.name)) {
        const {
          meaning,
          description,
          id
        } = i18nParsedMessageMeta[attr.name];
        const message = this._createI18nMessage([attr], meaning, description, id);
        const nodes = this._translations.get(message);
        if (nodes) {
          if (nodes.length == 0) {
            translatedAttributes.push(new Attribute(attr.name, '', attr.sourceSpan, undefined, undefined, undefined, undefined));
          } else if (nodes[0] instanceof Text) {
            const value = nodes[0].value;
            translatedAttributes.push(new Attribute(attr.name, value, attr.sourceSpan, undefined, undefined, undefined, undefined));
          } else {
            this._reportError(node, `Unexpected translation for attribute "${attr.name}" (id="${id || this._translations.digest(message)}")`);
          }
        } else {
          this._reportError(node, `Translation unavailable for attribute "${attr.name}" (id="${id || this._translations.digest(message)}")`);
        }
      } else {
        translatedAttributes.push(attr);
      }
    });
    return translatedAttributes;
  }
  _translateDirectives(node) {
    return node.directives.map(dir => new Directive(dir.name, this._translateAttributes(dir), dir.sourceSpan, dir.startSourceSpan, dir.endSourceSpan));
  }
  _mayBeAddBlockChildren(node) {
    if (this._inI18nBlock && !this._inIcu && this._depth == this._blockStartDepth) {
      this._blockChildren.push(node);
    }
  }
  _openTranslatableSection(node) {
    if (this._isInTranslatableSection) {
      this._reportError(node, 'Unexpected section start');
    } else {
      this._msgCountAtSectionStart = this._messages.length;
    }
  }
  get _isInTranslatableSection() {
    return this._msgCountAtSectionStart !== void 0;
  }
  _closeTranslatableSection(node, directChildren) {
    if (!this._isInTranslatableSection) {
      this._reportError(node, 'Unexpected section end');
      return;
    }
    const startIndex = this._msgCountAtSectionStart;
    const significantChildren = directChildren.reduce((count, node) => count + (node instanceof Comment ? 0 : 1), 0);
    if (significantChildren == 1) {
      for (let i = this._messages.length - 1; i >= startIndex; i--) {
        const ast = this._messages[i].nodes;
        if (!(ast.length == 1 && ast[0] instanceof Text$2)) {
          this._messages.splice(i, 1);
          break;
        }
      }
    }
    this._msgCountAtSectionStart = undefined;
  }
  _reportError(node, msg) {
    this._errors.push(new ParseError(node.sourceSpan, msg));
  }
}
function _isOpeningComment(n) {
  return !!(n instanceof Comment && n.value && n.value.startsWith('i18n'));
}
function _isClosingComment(n) {
  return !!(n instanceof Comment && n.value && n.value === '/i18n');
}
function _getI18nAttr(p) {
  return p.attrs.find(attr => attr instanceof Attribute && attr.name === _I18N_ATTR) || null;
}
function _parseMessageMeta(i18n) {
  if (!i18n) return {
    meaning: '',
    description: '',
    id: ''
  };
  const idIndex = i18n.indexOf(ID_SEPARATOR);
  const descIndex = i18n.indexOf(MEANING_SEPARATOR);
  const [meaningAndDesc, id] = idIndex > -1 ? [i18n.slice(0, idIndex), i18n.slice(idIndex + 2)] : [i18n, ''];
  const [meaning, description] = descIndex > -1 ? [meaningAndDesc.slice(0, descIndex), meaningAndDesc.slice(descIndex + 1)] : ['', meaningAndDesc];
  return {
    meaning,
    description,
    id: id.trim()
  };
}
function isTextNode(ast) {
  return ast.length === 1 && ast[0] instanceof Text;
}
function isAttrNode(ast) {
  return ast.length === 1 && ast[0] instanceof Attribute;
}

class XmlTagDefinition {
  closedByParent = false;
  implicitNamespacePrefix = null;
  isVoid = false;
  ignoreFirstLf = false;
  canSelfClose = true;
  preventNamespaceInheritance = false;
  requireExtraParent(currentParent) {
    return false;
  }
  isClosedByChild(name) {
    return false;
  }
  getContentType() {
    return TagContentType.PARSABLE_DATA;
  }
}
const _TAG_DEFINITION = new XmlTagDefinition();
function getXmlTagDefinition(tagName) {
  return _TAG_DEFINITION;
}

class XmlParser extends Parser$1 {
  constructor() {
    super(getXmlTagDefinition);
  }
  parse(source, url, options = {}) {
    return super.parse(source, url, {
      ...options,
      tokenizeBlocks: false,
      tokenizeLet: false,
      selectorlessEnabled: false
    });
  }
}

const _VERSION$1 = '1.2';
const _XMLNS$1 = 'urn:oasis:names:tc:xliff:document:1.2';
const _DEFAULT_SOURCE_LANG$1 = 'en';
const _PLACEHOLDER_TAG$2 = 'x';
const _MARKER_TAG$1 = 'mrk';
const _FILE_TAG = 'file';
const _SOURCE_TAG$1 = 'source';
const _SEGMENT_SOURCE_TAG = 'seg-source';
const _ALT_TRANS_TAG = 'alt-trans';
const _TARGET_TAG$1 = 'target';
const _UNIT_TAG$1 = 'trans-unit';
const _CONTEXT_GROUP_TAG = 'context-group';
const _CONTEXT_TAG = 'context';
class Xliff extends Serializer {
  write(messages, locale) {
    const visitor = new _WriteVisitor$1();
    const transUnits = [];
    messages.forEach(message => {
      let contextTags = [];
      message.sources.forEach(source => {
        let contextGroupTag = new Tag(_CONTEXT_GROUP_TAG, {
          purpose: 'location'
        });
        contextGroupTag.children.push(new CR(10), new Tag(_CONTEXT_TAG, {
          'context-type': 'sourcefile'
        }, [new Text$1(source.filePath)]), new CR(10), new Tag(_CONTEXT_TAG, {
          'context-type': 'linenumber'
        }, [new Text$1(`${source.startLine}`)]), new CR(8));
        contextTags.push(new CR(8), contextGroupTag);
      });
      const transUnit = new Tag(_UNIT_TAG$1, {
        id: message.id,
        datatype: 'html'
      });
      transUnit.children.push(new CR(8), new Tag(_SOURCE_TAG$1, {}, visitor.serialize(message.nodes)), ...contextTags);
      if (message.description) {
        transUnit.children.push(new CR(8), new Tag('note', {
          priority: '1',
          from: 'description'
        }, [new Text$1(message.description)]));
      }
      if (message.meaning) {
        transUnit.children.push(new CR(8), new Tag('note', {
          priority: '1',
          from: 'meaning'
        }, [new Text$1(message.meaning)]));
      }
      transUnit.children.push(new CR(6));
      transUnits.push(new CR(6), transUnit);
    });
    const body = new Tag('body', {}, [...transUnits, new CR(4)]);
    const file = new Tag('file', {
      'source-language': locale || _DEFAULT_SOURCE_LANG$1,
      datatype: 'plaintext',
      original: 'ng2.template'
    }, [new CR(4), body, new CR(2)]);
    const xliff = new Tag('xliff', {
      version: _VERSION$1,
      xmlns: _XMLNS$1
    }, [new CR(2), file, new CR()]);
    return serialize$1([new Declaration({
      version: '1.0',
      encoding: 'UTF-8'
    }), new CR(), xliff, new CR()]);
  }
  load(content, url) {
    const xliffParser = new XliffParser();
    const {
      locale,
      msgIdToHtml,
      errors
    } = xliffParser.parse(content, url);
    const i18nNodesByMsgId = {};
    const converter = new XmlToI18n$2();
    Object.keys(msgIdToHtml).forEach(msgId => {
      const {
        i18nNodes,
        errors: e
      } = converter.convert(msgIdToHtml[msgId], url);
      errors.push(...e);
      i18nNodesByMsgId[msgId] = i18nNodes;
    });
    if (errors.length) {
      throw new Error(`xliff parse errors:\n${errors.join('\n')}`);
    }
    return {
      locale: locale,
      i18nNodesByMsgId
    };
  }
  digest(message) {
    return digest$1(message);
  }
}
let _WriteVisitor$1 = class _WriteVisitor {
  visitText(text, context) {
    return [new Text$1(text.value)];
  }
  visitContainer(container, context) {
    const nodes = [];
    container.children.forEach(node => nodes.push(...node.visit(this)));
    return nodes;
  }
  visitIcu(icu, context) {
    const nodes = [new Text$1(`{${icu.expressionPlaceholder}, ${icu.type}, `)];
    Object.keys(icu.cases).forEach(c => {
      nodes.push(new Text$1(`${c} {`), ...icu.cases[c].visit(this), new Text$1(`} `));
    });
    nodes.push(new Text$1(`}`));
    return nodes;
  }
  visitTagPlaceholder(ph, context) {
    const ctype = getCtypeForTag(ph.tag);
    if (ph.isVoid) {
      return [new Tag(_PLACEHOLDER_TAG$2, {
        id: ph.startName,
        ctype,
        'equiv-text': `<${ph.tag}/>`
      })];
    }
    const startTagPh = new Tag(_PLACEHOLDER_TAG$2, {
      id: ph.startName,
      ctype,
      'equiv-text': `<${ph.tag}>`
    });
    const closeTagPh = new Tag(_PLACEHOLDER_TAG$2, {
      id: ph.closeName,
      ctype,
      'equiv-text': `</${ph.tag}>`
    });
    return [startTagPh, ...this.serialize(ph.children), closeTagPh];
  }
  visitPlaceholder(ph, context) {
    return [new Tag(_PLACEHOLDER_TAG$2, {
      id: ph.name,
      'equiv-text': `{{${ph.value}}}`
    })];
  }
  visitBlockPlaceholder(ph, context) {
    const ctype = `x-${ph.name.toLowerCase().replace(/[^a-z0-9]/g, '-')}`;
    const startTagPh = new Tag(_PLACEHOLDER_TAG$2, {
      id: ph.startName,
      ctype,
      'equiv-text': `@${ph.name}`
    });
    const closeTagPh = new Tag(_PLACEHOLDER_TAG$2, {
      id: ph.closeName,
      ctype,
      'equiv-text': `}`
    });
    return [startTagPh, ...this.serialize(ph.children), closeTagPh];
  }
  visitIcuPlaceholder(ph, context) {
    const equivText = `{${ph.value.expression}, ${ph.value.type}, ${Object.keys(ph.value.cases).map(value => value + ' {...}').join(' ')}}`;
    return [new Tag(_PLACEHOLDER_TAG$2, {
      id: ph.name,
      'equiv-text': equivText
    })];
  }
  serialize(nodes) {
    return [].concat(...nodes.map(node => node.visit(this)));
  }
};
class XliffParser {
  _unitMlString;
  _errors;
  _msgIdToHtml;
  _locale = null;
  parse(xliff, url) {
    this._unitMlString = null;
    this._msgIdToHtml = {};
    const xml = new XmlParser().parse(xliff, url);
    this._errors = xml.errors;
    visitAll(this, xml.rootNodes, null);
    return {
      msgIdToHtml: this._msgIdToHtml,
      errors: this._errors,
      locale: this._locale
    };
  }
  visitElement(element, context) {
    switch (element.name) {
      case _UNIT_TAG$1:
        this._unitMlString = null;
        const idAttr = element.attrs.find(attr => attr.name === 'id');
        if (!idAttr) {
          this._addError(element, `<${_UNIT_TAG$1}> misses the "id" attribute`);
        } else {
          const id = idAttr.value;
          if (Object.hasOwn(this._msgIdToHtml, id)) {
            this._addError(element, `Duplicated translations for msg ${id}`);
          } else {
            visitAll(this, element.children, null);
            if (typeof this._unitMlString === 'string') {
              this._msgIdToHtml[id] = this._unitMlString;
            } else {
              this._addError(element, `Message ${id} misses a translation`);
            }
          }
        }
        break;
      case _SOURCE_TAG$1:
      case _SEGMENT_SOURCE_TAG:
      case _ALT_TRANS_TAG:
        break;
      case _TARGET_TAG$1:
        const innerTextStart = element.startSourceSpan.end.offset;
        const innerTextEnd = element.endSourceSpan.start.offset;
        const content = element.startSourceSpan.start.file.content;
        const innerText = content.slice(innerTextStart, innerTextEnd);
        this._unitMlString = innerText;
        break;
      case _FILE_TAG:
        const localeAttr = element.attrs.find(attr => attr.name === 'target-language');
        if (localeAttr) {
          this._locale = localeAttr.value;
        }
        visitAll(this, element.children, null);
        break;
      default:
        visitAll(this, element.children, null);
    }
  }
  visitAttribute(attribute, context) {}
  visitText(text, context) {}
  visitComment(comment, context) {}
  visitExpansion(expansion, context) {}
  visitExpansionCase(expansionCase, context) {}
  visitBlock(block, context) {}
  visitBlockParameter(parameter, context) {}
  visitLetDeclaration(decl, context) {}
  visitComponent(component, context) {}
  visitDirective(directive, context) {}
  _addError(node, message) {
    this._errors.push(new ParseError(node.sourceSpan, message));
  }
}
let XmlToI18n$2 = class XmlToI18n {
  _errors;
  convert(message, url) {
    const xmlIcu = new XmlParser().parse(message, url, {
      tokenizeExpansionForms: true
    });
    this._errors = xmlIcu.errors;
    const i18nNodes = this._errors.length > 0 || xmlIcu.rootNodes.length == 0 ? [] : [].concat(...visitAll(this, xmlIcu.rootNodes));
    return {
      i18nNodes: i18nNodes,
      errors: this._errors
    };
  }
  visitText(text, context) {
    return new Text$2(text.value, text.sourceSpan);
  }
  visitElement(el, context) {
    if (el.name === _PLACEHOLDER_TAG$2) {
      const nameAttr = el.attrs.find(attr => attr.name === 'id');
      if (nameAttr) {
        return new Placeholder('', nameAttr.value, el.sourceSpan);
      }
      this._addError(el, `<${_PLACEHOLDER_TAG$2}> misses the "id" attribute`);
      return null;
    }
    if (el.name === _MARKER_TAG$1) {
      return [].concat(...visitAll(this, el.children));
    }
    this._addError(el, `Unexpected tag`);
    return null;
  }
  visitExpansion(icu, context) {
    const caseMap = {};
    visitAll(this, icu.cases).forEach(c => {
      caseMap[c.value] = new Container(c.nodes, icu.sourceSpan);
    });
    return new Icu(icu.switchValue, icu.type, caseMap, icu.sourceSpan);
  }
  visitExpansionCase(icuCase, context) {
    return {
      value: icuCase.value,
      nodes: visitAll(this, icuCase.expression)
    };
  }
  visitComment(comment, context) {}
  visitAttribute(attribute, context) {}
  visitBlock(block, context) {}
  visitBlockParameter(parameter, context) {}
  visitLetDeclaration(decl, context) {}
  visitComponent(component, context) {
    this._addError(component, 'Unexpected node');
  }
  visitDirective(directive, context) {
    this._addError(directive, 'Unexpected node');
  }
  _addError(node, message) {
    this._errors.push(new ParseError(node.sourceSpan, message));
  }
};
function getCtypeForTag(tag) {
  switch (tag.toLowerCase()) {
    case 'br':
      return 'lb';
    case 'img':
      return 'image';
    default:
      return `x-${tag}`;
  }
}

const _VERSION = '2.0';
const _XMLNS = 'urn:oasis:names:tc:xliff:document:2.0';
const _DEFAULT_SOURCE_LANG = 'en';
const _PLACEHOLDER_TAG$1 = 'ph';
const _PLACEHOLDER_SPANNING_TAG = 'pc';
const _MARKER_TAG = 'mrk';
const _XLIFF_TAG = 'xliff';
const _SOURCE_TAG = 'source';
const _TARGET_TAG = 'target';
const _UNIT_TAG = 'unit';
class Xliff2 extends Serializer {
  write(messages, locale) {
    const visitor = new _WriteVisitor();
    const units = [];
    messages.forEach(message => {
      const unit = new Tag(_UNIT_TAG, {
        id: message.id
      });
      const notes = new Tag('notes');
      if (message.description || message.meaning) {
        if (message.description) {
          notes.children.push(new CR(8), new Tag('note', {
            category: 'description'
          }, [new Text$1(message.description)]));
        }
        if (message.meaning) {
          notes.children.push(new CR(8), new Tag('note', {
            category: 'meaning'
          }, [new Text$1(message.meaning)]));
        }
      }
      message.sources.forEach(source => {
        notes.children.push(new CR(8), new Tag('note', {
          category: 'location'
        }, [new Text$1(`${source.filePath}:${source.startLine}${source.endLine !== source.startLine ? ',' + source.endLine : ''}`)]));
      });
      notes.children.push(new CR(6));
      unit.children.push(new CR(6), notes);
      const segment = new Tag('segment');
      segment.children.push(new CR(8), new Tag(_SOURCE_TAG, {}, visitor.serialize(message.nodes)), new CR(6));
      unit.children.push(new CR(6), segment, new CR(4));
      units.push(new CR(4), unit);
    });
    const file = new Tag('file', {
      'original': 'ng.template',
      id: 'ngi18n'
    }, [...units, new CR(2)]);
    const xliff = new Tag(_XLIFF_TAG, {
      version: _VERSION,
      xmlns: _XMLNS,
      srcLang: locale || _DEFAULT_SOURCE_LANG
    }, [new CR(2), file, new CR()]);
    return serialize$1([new Declaration({
      version: '1.0',
      encoding: 'UTF-8'
    }), new CR(), xliff, new CR()]);
  }
  load(content, url) {
    const xliff2Parser = new Xliff2Parser();
    const {
      locale,
      msgIdToHtml,
      errors
    } = xliff2Parser.parse(content, url);
    const i18nNodesByMsgId = {};
    const converter = new XmlToI18n$1();
    Object.keys(msgIdToHtml).forEach(msgId => {
      const {
        i18nNodes,
        errors: e
      } = converter.convert(msgIdToHtml[msgId], url);
      errors.push(...e);
      i18nNodesByMsgId[msgId] = i18nNodes;
    });
    if (errors.length) {
      throw new Error(`xliff2 parse errors:\n${errors.join('\n')}`);
    }
    return {
      locale: locale,
      i18nNodesByMsgId
    };
  }
  digest(message) {
    return decimalDigest(message);
  }
}
class _WriteVisitor {
  _nextPlaceholderId = 0;
  visitText(text, context) {
    return [new Text$1(text.value)];
  }
  visitContainer(container, context) {
    const nodes = [];
    container.children.forEach(node => nodes.push(...node.visit(this)));
    return nodes;
  }
  visitIcu(icu, context) {
    const nodes = [new Text$1(`{${icu.expressionPlaceholder}, ${icu.type}, `)];
    Object.keys(icu.cases).forEach(c => {
      nodes.push(new Text$1(`${c} {`), ...icu.cases[c].visit(this), new Text$1(`} `));
    });
    nodes.push(new Text$1(`}`));
    return nodes;
  }
  visitTagPlaceholder(ph, context) {
    const type = getTypeForTag(ph.tag);
    if (ph.isVoid) {
      const tagPh = new Tag(_PLACEHOLDER_TAG$1, {
        id: (this._nextPlaceholderId++).toString(),
        equiv: ph.startName,
        type: type,
        disp: `<${ph.tag}/>`
      });
      return [tagPh];
    }
    const tagPc = new Tag(_PLACEHOLDER_SPANNING_TAG, {
      id: (this._nextPlaceholderId++).toString(),
      equivStart: ph.startName,
      equivEnd: ph.closeName,
      type: type,
      dispStart: `<${ph.tag}>`,
      dispEnd: `</${ph.tag}>`
    });
    const nodes = [].concat(...ph.children.map(node => node.visit(this)));
    if (nodes.length) {
      nodes.forEach(node => tagPc.children.push(node));
    } else {
      tagPc.children.push(new Text$1(''));
    }
    return [tagPc];
  }
  visitPlaceholder(ph, context) {
    const idStr = (this._nextPlaceholderId++).toString();
    return [new Tag(_PLACEHOLDER_TAG$1, {
      id: idStr,
      equiv: ph.name,
      disp: `{{${ph.value}}}`
    })];
  }
  visitBlockPlaceholder(ph, context) {
    const tagPc = new Tag(_PLACEHOLDER_SPANNING_TAG, {
      id: (this._nextPlaceholderId++).toString(),
      equivStart: ph.startName,
      equivEnd: ph.closeName,
      type: 'other',
      dispStart: `@${ph.name}`,
      dispEnd: `}`
    });
    const nodes = [].concat(...ph.children.map(node => node.visit(this)));
    if (nodes.length) {
      nodes.forEach(node => tagPc.children.push(node));
    } else {
      tagPc.children.push(new Text$1(''));
    }
    return [tagPc];
  }
  visitIcuPlaceholder(ph, context) {
    const cases = Object.keys(ph.value.cases).map(value => value + ' {...}').join(' ');
    const idStr = (this._nextPlaceholderId++).toString();
    return [new Tag(_PLACEHOLDER_TAG$1, {
      id: idStr,
      equiv: ph.name,
      disp: `{${ph.value.expression}, ${ph.value.type}, ${cases}}`
    })];
  }
  serialize(nodes) {
    this._nextPlaceholderId = 0;
    return [].concat(...nodes.map(node => node.visit(this)));
  }
}
class Xliff2Parser {
  _unitMlString;
  _errors;
  _msgIdToHtml;
  _locale = null;
  parse(xliff, url) {
    this._unitMlString = null;
    this._msgIdToHtml = {};
    const xml = new XmlParser().parse(xliff, url);
    this._errors = xml.errors;
    visitAll(this, xml.rootNodes, null);
    return {
      msgIdToHtml: this._msgIdToHtml,
      errors: this._errors,
      locale: this._locale
    };
  }
  visitElement(element, context) {
    switch (element.name) {
      case _UNIT_TAG:
        this._unitMlString = null;
        const idAttr = element.attrs.find(attr => attr.name === 'id');
        if (!idAttr) {
          this._addError(element, `<${_UNIT_TAG}> misses the "id" attribute`);
        } else {
          const id = idAttr.value;
          if (Object.hasOwn(this._msgIdToHtml, id)) {
            this._addError(element, `Duplicated translations for msg ${id}`);
          } else {
            visitAll(this, element.children, null);
            if (typeof this._unitMlString === 'string') {
              this._msgIdToHtml[id] = this._unitMlString;
            } else {
              this._addError(element, `Message ${id} misses a translation`);
            }
          }
        }
        break;
      case _SOURCE_TAG:
        break;
      case _TARGET_TAG:
        const innerTextStart = element.startSourceSpan.end.offset;
        const innerTextEnd = element.endSourceSpan.start.offset;
        const content = element.startSourceSpan.start.file.content;
        const innerText = content.slice(innerTextStart, innerTextEnd);
        this._unitMlString = innerText;
        break;
      case _XLIFF_TAG:
        const localeAttr = element.attrs.find(attr => attr.name === 'trgLang');
        if (localeAttr) {
          this._locale = localeAttr.value;
        }
        const versionAttr = element.attrs.find(attr => attr.name === 'version');
        if (versionAttr) {
          const version = versionAttr.value;
          if (version !== '2.0') {
            this._addError(element, `The XLIFF file version ${version} is not compatible with XLIFF 2.0 serializer`);
          } else {
            visitAll(this, element.children, null);
          }
        }
        break;
      default:
        visitAll(this, element.children, null);
    }
  }
  visitAttribute(attribute, context) {}
  visitText(text, context) {}
  visitComment(comment, context) {}
  visitExpansion(expansion, context) {}
  visitExpansionCase(expansionCase, context) {}
  visitBlock(block, context) {}
  visitBlockParameter(parameter, context) {}
  visitLetDeclaration(decl, context) {}
  visitComponent(component, context) {}
  visitDirective(directive, context) {}
  _addError(node, message) {
    this._errors.push(new ParseError(node.sourceSpan, message));
  }
}
let XmlToI18n$1 = class XmlToI18n {
  _errors;
  convert(message, url) {
    const xmlIcu = new XmlParser().parse(message, url, {
      tokenizeExpansionForms: true
    });
    this._errors = xmlIcu.errors;
    const i18nNodes = this._errors.length > 0 || xmlIcu.rootNodes.length == 0 ? [] : [].concat(...visitAll(this, xmlIcu.rootNodes));
    return {
      i18nNodes,
      errors: this._errors
    };
  }
  visitText(text, context) {
    return new Text$2(text.value, text.sourceSpan);
  }
  visitElement(el, context) {
    switch (el.name) {
      case _PLACEHOLDER_TAG$1:
        const nameAttr = el.attrs.find(attr => attr.name === 'equiv');
        if (nameAttr) {
          return [new Placeholder('', nameAttr.value, el.sourceSpan)];
        }
        this._addError(el, `<${_PLACEHOLDER_TAG$1}> misses the "equiv" attribute`);
        break;
      case _PLACEHOLDER_SPANNING_TAG:
        const startAttr = el.attrs.find(attr => attr.name === 'equivStart');
        const endAttr = el.attrs.find(attr => attr.name === 'equivEnd');
        if (!startAttr) {
          this._addError(el, `<${_PLACEHOLDER_TAG$1}> misses the "equivStart" attribute`);
        } else if (!endAttr) {
          this._addError(el, `<${_PLACEHOLDER_TAG$1}> misses the "equivEnd" attribute`);
        } else {
          const startId = startAttr.value;
          const endId = endAttr.value;
          const nodes = [];
          return nodes.concat(new Placeholder('', startId, el.sourceSpan), ...el.children.map(node => node.visit(this, null)), new Placeholder('', endId, el.sourceSpan));
        }
        break;
      case _MARKER_TAG:
        return [].concat(...visitAll(this, el.children));
      default:
        this._addError(el, `Unexpected tag`);
    }
    return null;
  }
  visitExpansion(icu, context) {
    const caseMap = {};
    visitAll(this, icu.cases).forEach(c => {
      caseMap[c.value] = new Container(c.nodes, icu.sourceSpan);
    });
    return new Icu(icu.switchValue, icu.type, caseMap, icu.sourceSpan);
  }
  visitExpansionCase(icuCase, context) {
    return {
      value: icuCase.value,
      nodes: [].concat(...visitAll(this, icuCase.expression))
    };
  }
  visitComment(comment, context) {}
  visitAttribute(attribute, context) {}
  visitBlock(block, context) {}
  visitBlockParameter(parameter, context) {}
  visitLetDeclaration(decl, context) {}
  visitComponent(component, context) {
    this._addError(component, 'Unexpected node');
  }
  visitDirective(directive, context) {
    this._addError(directive, 'Unexpected node');
  }
  _addError(node, message) {
    this._errors.push(new ParseError(node.sourceSpan, message));
  }
};
function getTypeForTag(tag) {
  switch (tag.toLowerCase()) {
    case 'br':
    case 'b':
    case 'i':
    case 'u':
      return 'fmt';
    case 'img':
      return 'image';
    case 'a':
      return 'link';
    default:
      return 'other';
  }
}

const _TRANSLATIONS_TAG = 'translationbundle';
const _TRANSLATION_TAG = 'translation';
const _PLACEHOLDER_TAG = 'ph';
class Xtb extends Serializer {
  write(messages, locale) {
    throw new Error('Unsupported');
  }
  load(content, url) {
    const xtbParser = new XtbParser();
    const {
      locale,
      msgIdToHtml,
      errors
    } = xtbParser.parse(content, url);
    const i18nNodesByMsgId = {};
    const converter = new XmlToI18n();
    Object.keys(msgIdToHtml).forEach(msgId => {
      const valueFn = function () {
        const {
          i18nNodes,
          errors
        } = converter.convert(msgIdToHtml[msgId], url);
        if (errors.length) {
          throw new Error(`xtb parse errors:\n${errors.join('\n')}`);
        }
        return i18nNodes;
      };
      createLazyProperty(i18nNodesByMsgId, msgId, valueFn);
    });
    if (errors.length) {
      throw new Error(`xtb parse errors:\n${errors.join('\n')}`);
    }
    return {
      locale: locale,
      i18nNodesByMsgId
    };
  }
  digest(message) {
    return digest(message);
  }
  createNameMapper(message) {
    return new SimplePlaceholderMapper(message, toPublicName);
  }
}
function createLazyProperty(messages, id, valueFn) {
  Object.defineProperty(messages, id, {
    configurable: true,
    enumerable: true,
    get: function () {
      const value = valueFn();
      Object.defineProperty(messages, id, {
        enumerable: true,
        value
      });
      return value;
    },
    set: _ => {
      throw new Error('Could not overwrite an XTB translation');
    }
  });
}
class XtbParser {
  _bundleDepth;
  _errors;
  _msgIdToHtml;
  _locale = null;
  parse(xtb, url) {
    this._bundleDepth = 0;
    this._msgIdToHtml = {};
    const xml = new XmlParser().parse(xtb, url);
    this._errors = xml.errors;
    visitAll(this, xml.rootNodes);
    return {
      msgIdToHtml: this._msgIdToHtml,
      errors: this._errors,
      locale: this._locale
    };
  }
  visitElement(element, context) {
    switch (element.name) {
      case _TRANSLATIONS_TAG:
        this._bundleDepth++;
        if (this._bundleDepth > 1) {
          this._addError(element, `<${_TRANSLATIONS_TAG}> elements can not be nested`);
        }
        const langAttr = element.attrs.find(attr => attr.name === 'lang');
        if (langAttr) {
          this._locale = langAttr.value;
        }
        visitAll(this, element.children, null);
        this._bundleDepth--;
        break;
      case _TRANSLATION_TAG:
        const idAttr = element.attrs.find(attr => attr.name === 'id');
        if (!idAttr) {
          this._addError(element, `<${_TRANSLATION_TAG}> misses the "id" attribute`);
        } else {
          const id = idAttr.value;
          if (Object.hasOwn(this._msgIdToHtml, id)) {
            this._addError(element, `Duplicated translations for msg ${id}`);
          } else {
            const innerTextStart = element.startSourceSpan.end.offset;
            const innerTextEnd = element.endSourceSpan.start.offset;
            const content = element.startSourceSpan.start.file.content;
            const innerText = content.slice(innerTextStart, innerTextEnd);
            this._msgIdToHtml[id] = innerText;
          }
        }
        break;
      default:
        this._addError(element, 'Unexpected tag');
    }
  }
  visitAttribute(attribute, context) {}
  visitText(text, context) {}
  visitComment(comment, context) {}
  visitExpansion(expansion, context) {}
  visitExpansionCase(expansionCase, context) {}
  visitBlock(block, context) {}
  visitBlockParameter(block, context) {}
  visitLetDeclaration(decl, context) {}
  visitComponent(component, context) {
    this._addError(component, 'Unexpected node');
  }
  visitDirective(directive, context) {
    this._addError(directive, 'Unexpected node');
  }
  _addError(node, message) {
    this._errors.push(new ParseError(node.sourceSpan, message));
  }
}
class XmlToI18n {
  _errors;
  convert(message, url) {
    const xmlIcu = new XmlParser().parse(message, url, {
      tokenizeExpansionForms: true
    });
    this._errors = xmlIcu.errors;
    const i18nNodes = this._errors.length > 0 || xmlIcu.rootNodes.length == 0 ? [] : visitAll(this, xmlIcu.rootNodes);
    return {
      i18nNodes,
      errors: this._errors
    };
  }
  visitText(text, context) {
    return new Text$2(text.value, text.sourceSpan);
  }
  visitExpansion(icu, context) {
    const caseMap = {};
    visitAll(this, icu.cases).forEach(c => {
      caseMap[c.value] = new Container(c.nodes, icu.sourceSpan);
    });
    return new Icu(icu.switchValue, icu.type, caseMap, icu.sourceSpan);
  }
  visitExpansionCase(icuCase, context) {
    return {
      value: icuCase.value,
      nodes: visitAll(this, icuCase.expression)
    };
  }
  visitElement(el, context) {
    if (el.name === _PLACEHOLDER_TAG) {
      const nameAttr = el.attrs.find(attr => attr.name === 'name');
      if (nameAttr) {
        return new Placeholder('', nameAttr.value, el.sourceSpan);
      }
      this._addError(el, `<${_PLACEHOLDER_TAG}> misses the "name" attribute`);
    } else {
      this._addError(el, `Unexpected tag`);
    }
    return null;
  }
  visitComment(comment, context) {}
  visitAttribute(attribute, context) {}
  visitBlock(block, context) {}
  visitBlockParameter(block, context) {}
  visitLetDeclaration(decl, context) {}
  visitComponent(component, context) {
    this._addError(component, 'Unexpected node');
  }
  visitDirective(directive, context) {
    this._addError(directive, 'Unexpected node');
  }
  _addError(node, message) {
    this._errors.push(new ParseError(node.sourceSpan, message));
  }
}

class TranslationBundle {
  _i18nNodesByMsgId;
  digest;
  mapperFactory;
  _i18nToHtml;
  constructor(_i18nNodesByMsgId = {}, locale, digest, mapperFactory, missingTranslationStrategy = MissingTranslationStrategy.Warning, console) {
    this._i18nNodesByMsgId = _i18nNodesByMsgId;
    this.digest = digest;
    this.mapperFactory = mapperFactory;
    this._i18nToHtml = new I18nToHtmlVisitor(_i18nNodesByMsgId, locale, digest, mapperFactory, missingTranslationStrategy, console);
  }
  static load(content, url, serializer, missingTranslationStrategy, console) {
    const {
      locale,
      i18nNodesByMsgId
    } = serializer.load(content, url);
    const digestFn = m => serializer.digest(m);
    const mapperFactory = m => serializer.createNameMapper(m);
    return new TranslationBundle(i18nNodesByMsgId, locale, digestFn, mapperFactory, missingTranslationStrategy, console);
  }
  get(srcMsg) {
    const html = this._i18nToHtml.convert(srcMsg);
    if (html.errors.length) {
      throw new Error(html.errors.join('\n'));
    }
    return html.nodes;
  }
  has(srcMsg) {
    return this.digest(srcMsg) in this._i18nNodesByMsgId;
  }
}
class I18nToHtmlVisitor {
  _i18nNodesByMsgId;
  _locale;
  _digest;
  _mapperFactory;
  _missingTranslationStrategy;
  _console;
  _srcMsg;
  _errors = [];
  _contextStack = [];
  _mapper;
  constructor(_i18nNodesByMsgId = {}, _locale, _digest, _mapperFactory, _missingTranslationStrategy, _console) {
    this._i18nNodesByMsgId = _i18nNodesByMsgId;
    this._locale = _locale;
    this._digest = _digest;
    this._mapperFactory = _mapperFactory;
    this._missingTranslationStrategy = _missingTranslationStrategy;
    this._console = _console;
  }
  convert(srcMsg) {
    this._contextStack.length = 0;
    this._errors.length = 0;
    const text = this._convertToText(srcMsg);
    const url = srcMsg.nodes[0].sourceSpan.start.file.url;
    const html = new HtmlParser().parse(text, url, {
      tokenizeExpansionForms: true
    });
    return {
      nodes: html.rootNodes,
      errors: [...this._errors, ...html.errors]
    };
  }
  visitText(text, context) {
    return escapeXml(text.value);
  }
  visitContainer(container, context) {
    return container.children.map(n => n.visit(this)).join('');
  }
  visitIcu(icu, context) {
    const cases = Object.keys(icu.cases).map(k => `${k} {${icu.cases[k].visit(this)}}`);
    const exp = Object.hasOwn(this._srcMsg.placeholders, icu.expression) ? this._srcMsg.placeholders[icu.expression].text : icu.expression;
    return `{${exp}, ${icu.type}, ${cases.join(' ')}}`;
  }
  visitPlaceholder(ph, context) {
    const phName = this._mapper(ph.name);
    if (Object.hasOwn(this._srcMsg.placeholders, phName)) {
      return this._srcMsg.placeholders[phName].text;
    }
    if (Object.hasOwn(this._srcMsg.placeholderToMessage, phName)) {
      return this._convertToText(this._srcMsg.placeholderToMessage[phName]);
    }
    this._addError(ph, `Unknown placeholder "${ph.name}"`);
    return '';
  }
  visitTagPlaceholder(ph, context) {
    const tag = `${ph.tag}`;
    const attrs = Object.keys(ph.attrs).map(name => `${name}="${ph.attrs[name]}"`).join(' ');
    if (ph.isVoid) {
      return `<${tag} ${attrs}/>`;
    }
    const children = ph.children.map(c => c.visit(this)).join('');
    return `<${tag} ${attrs}>${children}</${tag}>`;
  }
  visitIcuPlaceholder(ph, context) {
    return this._convertToText(this._srcMsg.placeholderToMessage[ph.name]);
  }
  visitBlockPlaceholder(ph, context) {
    const params = ph.parameters.length === 0 ? '' : ` (${ph.parameters.join('; ')})`;
    const children = ph.children.map(c => c.visit(this)).join('');
    return `@${ph.name}${params} {${children}}`;
  }
  _convertToText(srcMsg) {
    const id = this._digest(srcMsg);
    const mapper = this._mapperFactory ? this._mapperFactory(srcMsg) : null;
    let nodes;
    this._contextStack.push({
      msg: this._srcMsg,
      mapper: this._mapper
    });
    this._srcMsg = srcMsg;
    if (Object.hasOwn(this._i18nNodesByMsgId, id)) {
      nodes = this._i18nNodesByMsgId[id];
      this._mapper = name => mapper ? mapper.toInternalName(name) : name;
    } else {
      if (this._missingTranslationStrategy === MissingTranslationStrategy.Error) {
        const ctx = this._locale ? ` for locale "${this._locale}"` : '';
        this._addError(srcMsg.nodes[0], `Missing translation for message "${id}"${ctx}`);
      } else if (this._console && this._missingTranslationStrategy === MissingTranslationStrategy.Warning) {
        const ctx = this._locale ? ` for locale "${this._locale}"` : '';
        this._console.warn(`Missing translation for message "${id}"${ctx}`);
      }
      nodes = srcMsg.nodes;
      this._mapper = name => name;
    }
    const text = nodes.map(node => node.visit(this)).join('');
    const context = this._contextStack.pop();
    this._srcMsg = context.msg;
    this._mapper = context.mapper;
    return text;
  }
  _addError(el, msg) {
    this._errors.push(new ParseError(el.sourceSpan, msg));
  }
}

class I18NHtmlParser {
  _htmlParser;
  getTagDefinition;
  _translationBundle;
  constructor(_htmlParser, translations, translationsFormat, missingTranslation = MissingTranslationStrategy.Warning, console) {
    this._htmlParser = _htmlParser;
    if (translations) {
      const serializer = createSerializer(translationsFormat);
      this._translationBundle = TranslationBundle.load(translations, 'i18n', serializer, missingTranslation, console);
    } else {
      this._translationBundle = new TranslationBundle({}, null, digest$1, undefined, missingTranslation, console);
    }
  }
  parse(source, url, options = {}) {
    const parseResult = this._htmlParser.parse(source, url, {
      ...options
    });
    if (parseResult.errors.length) {
      return new ParseTreeResult(parseResult.rootNodes, parseResult.errors);
    }
    return mergeTranslations(parseResult.rootNodes, this._translationBundle, [], {});
  }
}
function createSerializer(format) {
  format = (format || 'xlf').toLowerCase();
  switch (format) {
    case 'xmb':
      return new Xmb();
    case 'xtb':
      return new Xtb();
    case 'xliff2':
    case 'xlf2':
      return new Xliff2();
    case 'xliff':
    case 'xlf':
    default:
      return new Xliff();
  }
}

class MessageBundle {
  _htmlParser;
  _implicitTags;
  _implicitAttrs;
  _locale;
  _preserveWhitespace;
  _messages = [];
  constructor(_htmlParser, _implicitTags, _implicitAttrs, _locale = null, _preserveWhitespace = true) {
    this._htmlParser = _htmlParser;
    this._implicitTags = _implicitTags;
    this._implicitAttrs = _implicitAttrs;
    this._locale = _locale;
    this._preserveWhitespace = _preserveWhitespace;
  }
  updateFromTemplate(source, url) {
    const htmlParserResult = this._htmlParser.parse(source, url, {
      tokenizeExpansionForms: true
    });
    if (htmlParserResult.errors.length) {
      return htmlParserResult.errors;
    }
    const rootNodes = this._preserveWhitespace ? htmlParserResult.rootNodes : visitAllWithSiblings(new WhitespaceVisitor(false), htmlParserResult.rootNodes);
    const i18nParserResult = extractMessages(rootNodes, this._implicitTags, this._implicitAttrs, this._preserveWhitespace);
    if (i18nParserResult.errors.length) {
      return i18nParserResult.errors;
    }
    this._messages.push(...i18nParserResult.messages);
    return [];
  }
  getMessages() {
    return this._messages;
  }
  write(serializer, filterSources) {
    const messages = {};
    const mapperVisitor = new MapPlaceholderNames();
    this._messages.forEach(message => {
      const id = serializer.digest(message);
      if (!Object.hasOwn(messages, id)) {
        messages[id] = message;
      } else {
        messages[id].sources.push(...message.sources);
      }
    });
    const msgList = Object.keys(messages).map(id => {
      const mapper = serializer.createNameMapper(messages[id]);
      const src = messages[id];
      const nodes = mapper ? mapperVisitor.convert(src.nodes, mapper) : src.nodes;
      let transformedMessage = new Message(nodes, {}, {}, src.meaning, src.description, id);
      transformedMessage.sources = src.sources;
      if (filterSources) {
        transformedMessage.sources.forEach(source => source.filePath = filterSources(source.filePath));
      }
      return transformedMessage;
    });
    return serializer.write(msgList, this._locale);
  }
}
class MapPlaceholderNames extends CloneVisitor {
  convert(nodes, mapper) {
    return mapper ? nodes.map(n => n.visit(this, mapper)) : nodes;
  }
  visitTagPlaceholder(ph, mapper) {
    const startName = mapper.toPublicName(ph.startName);
    const closeName = ph.closeName ? mapper.toPublicName(ph.closeName) : ph.closeName;
    const children = ph.children.map(n => n.visit(this, mapper));
    return new TagPlaceholder(ph.tag, ph.attrs, startName, closeName, children, ph.isVoid, ph.sourceSpan, ph.startSourceSpan, ph.endSourceSpan);
  }
  visitBlockPlaceholder(ph, mapper) {
    const startName = mapper.toPublicName(ph.startName);
    const closeName = ph.closeName ? mapper.toPublicName(ph.closeName) : ph.closeName;
    const children = ph.children.map(n => n.visit(this, mapper));
    return new BlockPlaceholder(ph.name, ph.parameters, startName, closeName, children, ph.sourceSpan, ph.startSourceSpan, ph.endSourceSpan);
  }
  visitPlaceholder(ph, mapper) {
    return new Placeholder(ph.value, mapper.toPublicName(ph.name), ph.sourceSpan);
  }
  visitIcuPlaceholder(ph, mapper) {
    return new IcuPlaceholder(ph.value, mapper.toPublicName(ph.name), ph.sourceSpan);
  }
}

function compileClassMetadata(metadata) {
  const fnCall = internalCompileClassMetadata(metadata);
  return arrowFn([], [devOnlyGuardedExpression(fnCall).toStmt()]).callFn([]);
}
function internalCompileClassMetadata(metadata) {
  return importExpr(Identifiers.setClassMetadata).callFn([metadata.type, metadata.decorators, metadata.ctorParameters ?? literal(null), metadata.propDecorators ?? literal(null)]);
}
function compileComponentClassMetadata(metadata, dependencies) {
  if (dependencies === null || dependencies.length === 0) {
    return compileClassMetadata(metadata);
  }
  return internalCompileSetClassMetadataAsync(metadata, dependencies.map(dep => new FnParam(dep.symbolName, DYNAMIC_TYPE)), compileComponentMetadataAsyncResolver(dependencies));
}
function compileOpaqueAsyncClassMetadata(metadata, deferResolver, deferredDependencyNames) {
  return internalCompileSetClassMetadataAsync(metadata, deferredDependencyNames.map(name => new FnParam(name, DYNAMIC_TYPE)), deferResolver);
}
function internalCompileSetClassMetadataAsync(metadata, wrapperParams, dependencyResolverFn) {
  const setClassMetadataCall = internalCompileClassMetadata(metadata);
  const setClassMetaWrapper = arrowFn(wrapperParams, [setClassMetadataCall.toStmt()]);
  const setClassMetaAsync = importExpr(Identifiers.setClassMetadataAsync).callFn([metadata.type, dependencyResolverFn, setClassMetaWrapper]);
  return arrowFn([], [devOnlyGuardedExpression(setClassMetaAsync).toStmt()]).callFn([]);
}
function compileComponentMetadataAsyncResolver(dependencies) {
  const dynamicImports = dependencies.map(({
    symbolName,
    importPath,
    isDefaultImport
  }) => {
    const innerFn = arrowFn([new FnParam('m', DYNAMIC_TYPE)], variable('m').prop(isDefaultImport ? 'default' : symbolName));
    return new DynamicImportExpr(importPath).prop('then').callFn([innerFn], undefined, undefined, [tsIgnoreComment()]);
  });
  return arrowFn([], literalArr(dynamicImports));
}

const MINIMUM_PARTIAL_LINKER_VERSION$6 = '12.0.0';
const MINIMUM_PARTIAL_LINKER_DEFER_SUPPORT_VERSION = '18.0.0';
function compileDeclareClassMetadata(metadata) {
  const definitionMap = new DefinitionMap();
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$6));
  definitionMap.set('version', literal('22.1.7'));
  definitionMap.set('ngImport', importExpr(Identifiers.core));
  definitionMap.set('type', metadata.type);
  definitionMap.set('decorators', metadata.decorators);
  definitionMap.set('ctorParameters', metadata.ctorParameters);
  definitionMap.set('propDecorators', metadata.propDecorators);
  return importExpr(Identifiers.declareClassMetadata).callFn([definitionMap.toLiteralMap()]);
}
function compileComponentDeclareClassMetadata(metadata, dependencies) {
  if (dependencies === null || dependencies.length === 0) {
    return compileDeclareClassMetadata(metadata);
  }
  const definitionMap = new DefinitionMap();
  const callbackReturnDefinitionMap = new DefinitionMap();
  callbackReturnDefinitionMap.set('decorators', metadata.decorators);
  callbackReturnDefinitionMap.set('ctorParameters', metadata.ctorParameters ?? literal(null));
  callbackReturnDefinitionMap.set('propDecorators', metadata.propDecorators ?? literal(null));
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_DEFER_SUPPORT_VERSION));
  definitionMap.set('version', literal('22.1.7'));
  definitionMap.set('ngImport', importExpr(Identifiers.core));
  definitionMap.set('type', metadata.type);
  definitionMap.set('resolveDeferredDeps', compileComponentMetadataAsyncResolver(dependencies));
  definitionMap.set('resolveMetadata', arrowFn(dependencies.map(dep => new FnParam(dep.symbolName, DYNAMIC_TYPE)), callbackReturnDefinitionMap.toLiteralMap()));
  return importExpr(Identifiers.declareClassMetadataAsync).callFn([definitionMap.toLiteralMap()]);
}

function toOptionalLiteralArray(values, mapper) {
  if (values === null || values.length === 0) {
    return null;
  }
  return literalArr(values.map(value => mapper(value)));
}
function toOptionalLiteralMap(object, mapper) {
  const entries = Object.keys(object).map(key => {
    const value = object[key];
    return {
      key,
      value: mapper(value),
      quoted: true
    };
  });
  if (entries.length > 0) {
    return literalMap(entries);
  } else {
    return null;
  }
}
function compileDependencies(deps) {
  if (deps === 'invalid') {
    return literal('invalid');
  } else if (deps === null) {
    return literal(null);
  } else {
    return literalArr(deps.map(compileDependency));
  }
}
function compileDependency(dep) {
  const depMeta = new DefinitionMap();
  depMeta.set('token', dep.token);
  if (dep.attributeNameType !== null) {
    depMeta.set('attribute', literal(true));
  }
  if (dep.host) {
    depMeta.set('host', literal(true));
  }
  if (dep.optional) {
    depMeta.set('optional', literal(true));
  }
  if (dep.self) {
    depMeta.set('self', literal(true));
  }
  if (dep.skipSelf) {
    depMeta.set('skipSelf', literal(true));
  }
  return depMeta.toLiteralMap();
}

function compileDeclareDirectiveFromMetadata(meta) {
  const definitionMap = createDirectiveDefinitionMap(meta);
  const expression = importExpr(Identifiers.declareDirective).callFn([definitionMap.toLiteralMap()]);
  const type = createDirectiveType(meta);
  return {
    expression,
    type,
    statements: []
  };
}
function createDirectiveDefinitionMap(meta) {
  const definitionMap = new DefinitionMap();
  const minVersion = getMinimumVersionForPartialOutput(meta);
  definitionMap.set('minVersion', literal(minVersion));
  definitionMap.set('version', literal('22.1.7'));
  definitionMap.set('type', meta.type.value);
  if (meta.isStandalone !== undefined) {
    definitionMap.set('isStandalone', literal(meta.isStandalone));
  }
  if (meta.isSignal) {
    definitionMap.set('isSignal', literal(meta.isSignal));
  }
  if (meta.selector !== null) {
    definitionMap.set('selector', literal(meta.selector));
  }
  definitionMap.set('inputs', needsNewInputPartialOutput(meta) ? createInputsPartialMetadata(meta.inputs) : legacyInputsPartialMetadata(meta.inputs));
  definitionMap.set('outputs', conditionallyCreateDirectiveBindingLiteral(meta.outputs));
  definitionMap.set('host', compileHostMetadata(meta.host));
  definitionMap.set('providers', meta.providers);
  if (meta.queries.length > 0) {
    definitionMap.set('queries', literalArr(meta.queries.map(compileQuery)));
  }
  if (meta.viewQueries.length > 0) {
    definitionMap.set('viewQueries', literalArr(meta.viewQueries.map(compileQuery)));
  }
  if (meta.exportAs !== null) {
    definitionMap.set('exportAs', asLiteral(meta.exportAs));
  }
  if (meta.usesInheritance) {
    definitionMap.set('usesInheritance', literal(true));
  }
  if (meta.lifecycle.usesOnChanges) {
    definitionMap.set('usesOnChanges', literal(true));
  }
  if (meta.controlCreate) {
    definitionMap.set('controlCreate', literalMap([{
      key: 'passThroughInput',
      value: literal(meta.controlCreate.passThroughInput),
      quoted: false
    }]));
  }
  if (meta.hostDirectives?.length) {
    definitionMap.set('hostDirectives', createHostDirectives(meta.hostDirectives));
  }
  definitionMap.set('ngImport', importExpr(Identifiers.core));
  return definitionMap;
}
function getMinimumVersionForPartialOutput(meta) {
  let minVersion = '14.0.0';
  const hasDecoratorTransformFunctions = Object.values(meta.inputs).some(input => input.transformFunction !== null);
  if (hasDecoratorTransformFunctions) {
    minVersion = '16.1.0';
  }
  if (needsNewInputPartialOutput(meta)) {
    minVersion = '17.1.0';
  }
  if (meta.queries.some(q => q.isSignal) || meta.viewQueries.some(q => q.isSignal)) {
    minVersion = '17.2.0';
  }
  return minVersion;
}
function needsNewInputPartialOutput(meta) {
  return Object.values(meta.inputs).some(input => input.isSignal);
}
function compileQuery(query) {
  const meta = new DefinitionMap();
  meta.set('propertyName', literal(query.propertyName));
  if (query.first) {
    meta.set('first', literal(true));
  }
  meta.set('predicate', Array.isArray(query.predicate) ? asLiteral(query.predicate) : convertFromMaybeForwardRefExpression(query.predicate));
  if (!query.emitDistinctChangesOnly) {
    meta.set('emitDistinctChangesOnly', literal(false));
  }
  if (query.descendants) {
    meta.set('descendants', literal(true));
  }
  meta.set('read', query.read);
  if (query.static) {
    meta.set('static', literal(true));
  }
  if (query.isSignal) {
    meta.set('isSignal', literal(true));
  }
  return meta.toLiteralMap();
}
function compileHostMetadata(meta) {
  const hostMetadata = new DefinitionMap();
  hostMetadata.set('attributes', toOptionalLiteralMap(meta.attributes, expression => expression));
  hostMetadata.set('listeners', toOptionalLiteralMap(meta.listeners, literal));
  hostMetadata.set('properties', toOptionalLiteralMap(meta.properties, literal));
  if (meta.specialAttributes.styleAttr) {
    hostMetadata.set('styleAttribute', literal(meta.specialAttributes.styleAttr));
  }
  if (meta.specialAttributes.classAttr) {
    hostMetadata.set('classAttribute', literal(meta.specialAttributes.classAttr));
  }
  if (hostMetadata.values.length > 0) {
    return hostMetadata.toLiteralMap();
  } else {
    return null;
  }
}
function createHostDirectives(hostDirectives) {
  const expressions = hostDirectives.map(current => {
    const keys = [{
      key: 'directive',
      value: current.isForwardReference ? generateForwardRef(current.directive.type) : current.directive.type,
      quoted: false
    }];
    const inputsLiteral = current.inputs ? createHostDirectivesMappingArray(current.inputs) : null;
    const outputsLiteral = current.outputs ? createHostDirectivesMappingArray(current.outputs) : null;
    if (inputsLiteral) {
      keys.push({
        key: 'inputs',
        value: inputsLiteral,
        quoted: false
      });
    }
    if (outputsLiteral) {
      keys.push({
        key: 'outputs',
        value: outputsLiteral,
        quoted: false
      });
    }
    return literalMap(keys);
  });
  return literalArr(expressions);
}
function createInputsPartialMetadata(inputs) {
  const keys = Object.getOwnPropertyNames(inputs);
  if (keys.length === 0) {
    return null;
  }
  return literalMap(keys.map(declaredName => {
    const value = inputs[declaredName];
    return {
      key: declaredName,
      quoted: isUnsafeObjectKey(declaredName),
      value: literalMap([{
        key: 'classPropertyName',
        quoted: false,
        value: asLiteral(value.classPropertyName)
      }, {
        key: 'publicName',
        quoted: false,
        value: asLiteral(value.bindingPropertyName)
      }, {
        key: 'isSignal',
        quoted: false,
        value: asLiteral(value.isSignal)
      }, {
        key: 'isRequired',
        quoted: false,
        value: asLiteral(value.required)
      }, {
        key: 'transformFunction',
        quoted: false,
        value: value.transformFunction ?? NULL_EXPR
      }])
    };
  }));
}
function legacyInputsPartialMetadata(inputs) {
  const keys = Object.getOwnPropertyNames(inputs);
  if (keys.length === 0) {
    return null;
  }
  return literalMap(keys.map(declaredName => {
    const value = inputs[declaredName];
    const publicName = value.bindingPropertyName;
    const differentDeclaringName = publicName !== declaredName;
    let result;
    if (differentDeclaringName || value.transformFunction !== null) {
      const values = [asLiteral(publicName), asLiteral(declaredName)];
      if (value.transformFunction !== null) {
        values.push(value.transformFunction);
      }
      result = literalArr(values);
    } else {
      result = asLiteral(publicName);
    }
    return {
      key: declaredName,
      quoted: isUnsafeObjectKey(declaredName),
      value: result
    };
  }));
}

function compileDeclareComponentFromMetadata(meta, template, additionalTemplateInfo) {
  const definitionMap = createComponentDefinitionMap(meta, template, additionalTemplateInfo);
  const expression = importExpr(Identifiers.declareComponent).callFn([definitionMap.toLiteralMap()]);
  const type = createComponentType(meta);
  return {
    expression,
    type,
    statements: []
  };
}
function createComponentDefinitionMap(meta, template, templateInfo) {
  const definitionMap = createDirectiveDefinitionMap(meta);
  const blockVisitor = new BlockPresenceVisitor();
  visitAll$1(blockVisitor, template.nodes);
  definitionMap.set('template', getTemplateExpression(template, templateInfo));
  if (templateInfo.isInline) {
    definitionMap.set('isInline', literal(true));
  }
  if (blockVisitor.hasBlocks) {
    definitionMap.set('minVersion', literal('17.0.0'));
  }
  definitionMap.set('styles', toOptionalLiteralArray(meta.styles, literal));
  definitionMap.set('dependencies', compileUsedDependenciesMetadata(meta));
  definitionMap.set('viewProviders', meta.viewProviders);
  definitionMap.set('animations', meta.animations);
  if (meta.changeDetection !== null) {
    if (typeof meta.changeDetection === 'object') {
      throw new Error('Impossible state! Change detection flag is not resolved!');
    }
    definitionMap.set('changeDetection', importExpr(Identifiers.ChangeDetectionStrategy).prop(ChangeDetectionStrategy[meta.changeDetection]));
  }
  if (meta.encapsulation !== ViewEncapsulation$1.Emulated) {
    definitionMap.set('encapsulation', importExpr(Identifiers.ViewEncapsulation).prop(ViewEncapsulation$1[meta.encapsulation]));
  }
  if (template.preserveWhitespaces === true) {
    definitionMap.set('preserveWhitespaces', literal(true));
  }
  if (meta.defer.mode === 0) {
    const resolvers = [];
    let hasResolvers = false;
    for (const deps of meta.defer.blocks.values()) {
      if (deps === null) {
        resolvers.push(literal(null));
      } else {
        resolvers.push(deps);
        hasResolvers = true;
      }
    }
    if (hasResolvers) {
      definitionMap.set('deferBlockDependencies', literalArr(resolvers));
    }
  } else {
    throw new Error('Unsupported defer function emit mode in partial compilation');
  }
  return definitionMap;
}
function getTemplateExpression(template, templateInfo) {
  if (templateInfo.inlineTemplateLiteralExpression !== null) {
    return templateInfo.inlineTemplateLiteralExpression;
  }
  if (templateInfo.isInline) {
    return literal(templateInfo.content, null, null);
  }
  const contents = templateInfo.content;
  const file = new ParseSourceFile(contents, templateInfo.sourceUrl);
  const start = new ParseLocation(file, 0, 0, 0);
  const end = computeEndLocation(file, contents);
  const span = new ParseSourceSpan(start, end);
  return literal(contents, null, span);
}
function computeEndLocation(file, contents) {
  const length = contents.length;
  let lineStart = 0;
  let lastLineStart = 0;
  let line = 0;
  do {
    lineStart = contents.indexOf('\n', lastLineStart);
    if (lineStart !== -1) {
      lastLineStart = lineStart + 1;
      line++;
    }
  } while (lineStart !== -1);
  return new ParseLocation(file, length, line, length - lastLineStart);
}
function compileUsedDependenciesMetadata(meta) {
  const wrapType = meta.declarationListEmitMode !== 0 ? generateForwardRef : expr => expr;
  if (meta.declarationListEmitMode === 3) {
    throw new Error(`Unsupported emit mode`);
  }
  return toOptionalLiteralArray(meta.declarations, decl => {
    switch (decl.kind) {
      case R3TemplateDependencyKind.Directive:
        const dirMeta = new DefinitionMap();
        dirMeta.set('kind', literal(decl.isComponent ? 'component' : 'directive'));
        dirMeta.set('type', wrapType(decl.type));
        dirMeta.set('selector', literal(decl.selector));
        dirMeta.set('inputs', toOptionalLiteralArray(decl.inputs, literal));
        dirMeta.set('outputs', toOptionalLiteralArray(decl.outputs, literal));
        dirMeta.set('exportAs', toOptionalLiteralArray(decl.exportAs, literal));
        return dirMeta.toLiteralMap();
      case R3TemplateDependencyKind.Pipe:
        const pipeMeta = new DefinitionMap();
        pipeMeta.set('kind', literal('pipe'));
        pipeMeta.set('type', wrapType(decl.type));
        pipeMeta.set('name', literal(decl.name));
        return pipeMeta.toLiteralMap();
      case R3TemplateDependencyKind.NgModule:
        const ngModuleMeta = new DefinitionMap();
        ngModuleMeta.set('kind', literal('ngmodule'));
        ngModuleMeta.set('type', wrapType(decl.type));
        return ngModuleMeta.toLiteralMap();
    }
  });
}
class BlockPresenceVisitor extends RecursiveVisitor$1 {
  hasBlocks = false;
  visitDeferredBlock() {
    this.hasBlocks = true;
  }
  visitDeferredBlockPlaceholder() {
    this.hasBlocks = true;
  }
  visitDeferredBlockLoading() {
    this.hasBlocks = true;
  }
  visitDeferredBlockError() {
    this.hasBlocks = true;
  }
  visitIfBlock() {
    this.hasBlocks = true;
  }
  visitIfBlockBranch() {
    this.hasBlocks = true;
  }
  visitForLoopBlock() {
    this.hasBlocks = true;
  }
  visitForLoopBlockEmpty() {
    this.hasBlocks = true;
  }
  visitSwitchBlock() {
    this.hasBlocks = true;
  }
  visitSwitchBlockCase() {
    this.hasBlocks = true;
  }
  visitSwitchBlockCaseGroup() {
    this.hasBlocks = true;
  }
}

const MINIMUM_PARTIAL_LINKER_VERSION$5 = '12.0.0';
function compileDeclareFactoryFunction(meta) {
  const definitionMap = new DefinitionMap();
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$5));
  definitionMap.set('version', literal('22.1.7'));
  definitionMap.set('ngImport', importExpr(Identifiers.core));
  definitionMap.set('type', meta.type.value);
  definitionMap.set('deps', compileDependencies(meta.deps));
  definitionMap.set('target', importExpr(Identifiers.FactoryTarget).prop(FactoryTarget[meta.target]));
  return {
    expression: importExpr(Identifiers.declareFactory).callFn([definitionMap.toLiteralMap()]),
    statements: [],
    type: createFactoryType(meta)
  };
}

const MINIMUM_PARTIAL_LINKER_VERSION$4 = '12.0.0';
function compileDeclareInjectableFromMetadata(meta) {
  const definitionMap = createInjectableDefinitionMap(meta);
  const expression = importExpr(Identifiers.declareInjectable).callFn([definitionMap.toLiteralMap()]);
  const type = createInjectableType();
  return {
    expression,
    type,
    statements: []
  };
}
function createInjectableDefinitionMap(meta) {
  const definitionMap = new DefinitionMap();
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$4));
  definitionMap.set('version', literal('22.1.7'));
  definitionMap.set('ngImport', importExpr(Identifiers.core));
  definitionMap.set('type', meta.type.value);
  if (meta.providedIn !== undefined) {
    const providedIn = convertFromMaybeForwardRefExpression(meta.providedIn);
    if (providedIn.value !== null) {
      definitionMap.set('providedIn', providedIn);
    }
  }
  if (meta.useClass !== undefined) {
    definitionMap.set('useClass', convertFromMaybeForwardRefExpression(meta.useClass));
  }
  if (meta.useExisting !== undefined) {
    definitionMap.set('useExisting', convertFromMaybeForwardRefExpression(meta.useExisting));
  }
  if (meta.useValue !== undefined) {
    definitionMap.set('useValue', convertFromMaybeForwardRefExpression(meta.useValue));
  }
  if (meta.useFactory !== undefined) {
    definitionMap.set('useFactory', meta.useFactory);
  }
  if (meta.deps !== undefined) {
    definitionMap.set('deps', literalArr(meta.deps.map(compileDependency)));
  }
  return definitionMap;
}

const MINIMUM_PARTIAL_LINKER_VERSION$3 = '22.0.0';
function compileDeclareServiceFromMetadata(meta) {
  const definitionMap = createServiceDefinitionMap(meta);
  const expression = importExpr(Identifiers.declareService).callFn([definitionMap.toLiteralMap()]);
  const type = createInjectableType();
  return {
    expression,
    type,
    statements: []
  };
}
function createServiceDefinitionMap(meta) {
  const definitionMap = new DefinitionMap();
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$3));
  definitionMap.set('version', literal('22.1.7'));
  definitionMap.set('ngImport', importExpr(Identifiers.core));
  definitionMap.set('type', meta.type.value);
  if (meta.autoProvided === false) {
    definitionMap.set('autoProvided', literal(false));
  }
  if (meta.factory !== undefined) {
    definitionMap.set('factory', meta.factory);
  }
  return definitionMap;
}

const MINIMUM_PARTIAL_LINKER_VERSION$2 = '12.0.0';
function compileDeclareInjectorFromMetadata(meta) {
  const definitionMap = createInjectorDefinitionMap(meta);
  const expression = importExpr(Identifiers.declareInjector).callFn([definitionMap.toLiteralMap()]);
  const type = createInjectorType(meta);
  return {
    expression,
    type,
    statements: []
  };
}
function createInjectorDefinitionMap(meta) {
  const definitionMap = new DefinitionMap();
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$2));
  definitionMap.set('version', literal('22.1.7'));
  definitionMap.set('ngImport', importExpr(Identifiers.core));
  definitionMap.set('type', meta.type.value);
  definitionMap.set('providers', meta.providers);
  if (meta.imports.length > 0) {
    definitionMap.set('imports', literalArr(meta.imports));
  }
  return definitionMap;
}

const MINIMUM_PARTIAL_LINKER_VERSION$1 = '14.0.0';
function compileDeclareNgModuleFromMetadata(meta) {
  const definitionMap = createNgModuleDefinitionMap(meta);
  const expression = importExpr(Identifiers.declareNgModule).callFn([definitionMap.toLiteralMap()]);
  const type = createNgModuleType(meta);
  return {
    expression,
    type,
    statements: []
  };
}
function createNgModuleDefinitionMap(meta) {
  const definitionMap = new DefinitionMap();
  if (meta.kind === R3NgModuleMetadataKind.Local) {
    throw new Error('Invalid path! Local compilation mode should not get into the partial compilation path');
  }
  if (meta.kind === R3NgModuleMetadataKind.Isolated) {
    throw new Error('Invalid path! Isolated compilation mode should not get into the partial compilation path');
  }
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$1));
  definitionMap.set('version', literal('22.1.7'));
  definitionMap.set('ngImport', importExpr(Identifiers.core));
  definitionMap.set('type', meta.type.value);
  if (meta.bootstrap.length > 0) {
    definitionMap.set('bootstrap', refsToArray(meta.bootstrap, meta.containsForwardDecls));
  }
  if (meta.declarations.length > 0) {
    definitionMap.set('declarations', refsToArray(meta.declarations, meta.containsForwardDecls));
  }
  if (meta.imports.length > 0) {
    definitionMap.set('imports', refsToArray(meta.imports, meta.containsForwardDecls));
  }
  if (meta.exports.length > 0) {
    definitionMap.set('exports', refsToArray(meta.exports, meta.containsForwardDecls));
  }
  if (meta.schemas !== null && meta.schemas.length > 0) {
    definitionMap.set('schemas', literalArr(meta.schemas.map(ref => ref.value)));
  }
  if (meta.id !== null) {
    definitionMap.set('id', meta.id);
  }
  return definitionMap;
}

const MINIMUM_PARTIAL_LINKER_VERSION = '14.0.0';
function compileDeclarePipeFromMetadata(meta) {
  const definitionMap = createPipeDefinitionMap(meta);
  const expression = importExpr(Identifiers.declarePipe).callFn([definitionMap.toLiteralMap()]);
  const type = createPipeType(meta);
  return {
    expression,
    type,
    statements: []
  };
}
function createPipeDefinitionMap(meta) {
  const definitionMap = new DefinitionMap();
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION));
  definitionMap.set('version', literal('22.1.7'));
  definitionMap.set('ngImport', importExpr(Identifiers.core));
  definitionMap.set('type', meta.type.value);
  if (meta.isStandalone !== undefined) {
    definitionMap.set('isStandalone', literal(meta.isStandalone));
  }
  definitionMap.set('name', literal(meta.pipeName ?? meta.name));
  if (meta.pure === false) {
    definitionMap.set('pure', literal(meta.pure));
  }
  return definitionMap;
}

function compileClassDebugInfo(debugInfo) {
  const debugInfoObject = {
    className: debugInfo.className
  };
  if (debugInfo.filePath) {
    debugInfoObject.filePath = debugInfo.filePath;
    debugInfoObject.lineNumber = debugInfo.lineNumber;
  }
  if (debugInfo.forbidOrphanRendering) {
    debugInfoObject.forbidOrphanRendering = literal(true);
  }
  const fnCall = importExpr(Identifiers.setClassDebugInfo).callFn([debugInfo.type, mapLiteral(debugInfoObject)]);
  const iife = arrowFn([], [devOnlyGuardedExpression(fnCall).toStmt()]);
  return iife.callFn([]);
}

function compileHmrInitializer(meta) {
  const moduleName = 'm';
  const dataName = 'd';
  const timestampName = 't';
  const idName = 'id';
  const importCallbackName = `${meta.className}_HmrLoad`;
  const namespaces = meta.namespaceDependencies.map(dep => {
    return new ExternalExpr({
      moduleName: dep.moduleName,
      name: null
    });
  });
  const defaultRead = variable(moduleName).prop('default');
  const replaceCall = importExpr(Identifiers.replaceMetadata).callFn([meta.type, defaultRead, literalArr(namespaces), literalArr(meta.localDependencies.map(l => l.runtimeRepresentation)), variable('import').prop('meta'), variable(idName)]);
  const replaceCallback = arrowFn([new FnParam(moduleName, DYNAMIC_TYPE)], defaultRead.and(replaceCall));
  const url = importExpr(Identifiers.getReplaceMetadataURL).callFn([variable(idName), variable(timestampName), variable('import').prop('meta').prop('url')]);
  const importCallback = new DeclareFunctionStmt(importCallbackName, [new FnParam(timestampName, DYNAMIC_TYPE)], [new DynamicImportExpr(url, null, '@vite-ignore').prop('then').callFn([replaceCallback]).toStmt()], null, StmtModifier.Final);
  const updateCallback = arrowFn([new FnParam(dataName, DYNAMIC_TYPE)], variable(dataName).prop('id').identical(variable(idName)).and(variable(importCallbackName).callFn([variable(dataName).prop('timestamp')])));
  const initialCall = variable(importCallbackName).callFn([variable('Date').prop('now').callFn([])]);
  const hotRead = variable('import').prop('meta').prop('hot');
  const hotListener = hotRead.clone().prop('on').callFn([literal('angular:component-update'), updateCallback]);
  return arrowFn([], [new DeclareVarStmt(idName, literal(encodeURIComponent(`${meta.filePath}@${meta.className}`)), null, StmtModifier.Final), importCallback, devOnlyGuardedExpression(initialCall).toStmt(), devOnlyGuardedExpression(hotRead.and(hotListener)).toStmt()]).callFn([]);
}
function compileHmrUpdateCallback(definitions, constantStatements, meta) {
  const namespaces = 'ɵɵnamespaces';
  const params = [meta.className, namespaces].map(name => new FnParam(name, DYNAMIC_TYPE));
  const body = [];
  for (const local of meta.localDependencies) {
    params.push(new FnParam(local.name, DYNAMIC_TYPE));
  }
  for (let i = 0; i < meta.namespaceDependencies.length; i++) {
    body.push(new DeclareVarStmt(meta.namespaceDependencies[i].assignedName, variable(namespaces).key(literal(i)), DYNAMIC_TYPE, StmtModifier.Final));
  }
  body.push(...constantStatements);
  for (const field of definitions) {
    if (field.initializer !== null) {
      body.push(variable(meta.className).prop(field.name).set(field.initializer).toStmt());
      for (const stmt of field.statements) {
        body.push(stmt);
      }
    }
  }
  return new DeclareFunctionStmt(`${meta.className}_UpdateMetadata`, params, body, null, StmtModifier.Final);
}

const VERSION = new Version('22.1.7');

const HOST_BINDING_GUARD_COMMENT_TEXT = 'hostBindingsBlockGuard';
function createHostElement(type, selector, nameSpan, hostObjectLiteralBindings, hostBindingDecorators, hostListenerDecorators) {
  const bindings = [];
  const listeners = [];
  let parser = null;
  for (const binding of hostObjectLiteralBindings) {
    parser ??= makeBindingParser();
    createNodeFromHostLiteralProperty(binding, parser, bindings, listeners);
  }
  for (const decorator of hostBindingDecorators) {
    createNodeFromBindingDecorator(decorator, bindings);
  }
  for (const decorator of hostListenerDecorators) {
    parser ??= makeBindingParser();
    createNodeFromListenerDecorator(decorator, parser, listeners);
  }
  if (bindings.length === 0 && listeners.length === 0) {
    return null;
  }
  const tagNames = [];
  if (selector !== null) {
    const parts = CssSelector.parse(selector);
    for (const part of parts) {
      if (part.element !== null) {
        tagNames.push(part.element);
      }
    }
  }
  if (tagNames.length === 0) {
    tagNames.push(`ng-${type}`);
  }
  return new HostElement(tagNames, bindings, listeners, nameSpan);
}
function createHostBindingsBlockGuard() {
  return `(true /*${HOST_BINDING_GUARD_COMMENT_TEXT}*/)`;
}
function createNodeFromHostLiteralProperty(binding, parser, bindings, listeners) {
  const {
    key,
    value,
    sourceSpan
  } = binding;
  if (key.kind !== 'string' || value.kind !== 'string') {
    return;
  }
  if (key.text.startsWith('[') && key.text.endsWith(']')) {
    const {
      attrName,
      type
    } = inferBoundAttribute(key.text.slice(1, -1));
    const ast = parser.parseBinding(value.text, true, value.sourceSpan, value.sourceSpan.start.offset);
    if (ast.errors.length > 0) {
      return;
    }
    fixupSpans(ast, value);
    bindings.push(new BoundAttribute(attrName, type, 0, ast, null, sourceSpan, key.sourceSpan, value.sourceSpan, undefined));
  } else if (key.text.startsWith('(') && key.text.endsWith(')')) {
    const events = [];
    parser.parseEvent(key.text.slice(1, -1), value.text, false, sourceSpan, value.sourceSpan, [], events, key.sourceSpan);
    if (events.length === 0 || events[0].handler.errors.length > 0) {
      return;
    }
    fixupSpans(events[0].handler, value);
    listeners.push(BoundEvent.fromParsedEvent(events[0]));
  }
}
function createNodeFromBindingDecorator(decorator, bindings) {
  const args = decorator.arguments;
  let nameNode;
  if (args.length === 0) {
    nameNode = decorator.memberName;
  } else if (args[0].kind === 'string') {
    nameNode = args[0];
  } else {
    return;
  }
  if (nameNode.kind !== 'string' && nameNode.kind !== 'identifier') {
    return;
  }
  const span = new ParseSpan(-1, -1);
  const propertyStart = decorator.memberSpan.start.offset;
  const receiver = new ThisReceiver(span, new AbsoluteSourceSpan(propertyStart, propertyStart));
  const nameSpan = new AbsoluteSourceSpan(nameNode.sourceSpan.start.offset, nameNode.sourceSpan.end.offset);
  const read = decorator.memberName.kind === 'string' ? new KeyedRead(span, nameSpan, receiver, new LiteralPrimitive(span, nameSpan, decorator.memberName.text)) : new PropertyRead(span, nameSpan, nameSpan, receiver, decorator.memberName.text);
  const {
    attrName,
    type
  } = inferBoundAttribute(nameNode.text);
  bindings.push(new BoundAttribute(attrName, type, 0, read, null, decorator.decoratorSpan, nameNode.sourceSpan, decorator.decoratorSpan, undefined));
}
function createNodeFromListenerDecorator(decorator, parser, listeners) {
  if (decorator.eventName === null || decorator.eventName.kind !== 'string') {
    return;
  }
  const dummySpan = new ParseSpan(-1, -1);
  const argNodes = [];
  const methodStart = decorator.memberSpan.start.offset;
  const methodReceiver = new ThisReceiver(dummySpan, new AbsoluteSourceSpan(methodStart, methodStart));
  const nameSpan = new AbsoluteSourceSpan(decorator.memberName.sourceSpan.start.offset, decorator.memberName.sourceSpan.end.offset);
  const receiver = decorator.memberName.kind === 'string' ? new KeyedRead(dummySpan, nameSpan, methodReceiver, new LiteralPrimitive(dummySpan, nameSpan, decorator.memberName.text)) : new PropertyRead(dummySpan, nameSpan, nameSpan, methodReceiver, decorator.memberName.text);
  for (const arg of decorator.arguments) {
    if (arg.kind === 'string') {
      const span = arg.sourceSpan;
      const ast = parser.parseBinding(arg.text, true, span, span.start.offset);
      fixupSpans(ast, arg);
      argNodes.push(ast);
    } else {
      const expressionSpan = new AbsoluteSourceSpan(arg.sourceSpan.start.offset, arg.sourceSpan.end.offset);
      const anyRead = new PropertyRead(dummySpan, expressionSpan, expressionSpan, new ImplicitReceiver(dummySpan, expressionSpan), '$any');
      const anyCall = new Call(dummySpan, expressionSpan, anyRead, [new LiteralPrimitive(dummySpan, expressionSpan, 0)], expressionSpan);
      argNodes.push(anyCall);
    }
  }
  const callNode = new Call(dummySpan, nameSpan, receiver, argNodes, dummySpan);
  const eventNameNode = decorator.eventName;
  let type;
  let eventName;
  let phase;
  let target;
  if (eventNameNode.text.startsWith('@')) {
    const parsedName = parser.parseLegacyAnimationEventName(eventNameNode.text);
    type = ParsedEventType.LegacyAnimation;
    eventName = parsedName.eventName;
    phase = parsedName.phase;
    target = null;
  } else {
    const parsedName = parser.parseEventListenerName(eventNameNode.text);
    type = parsedName.eventName.startsWith('animate.') ? ParsedEventType.Animation : ParsedEventType.Regular;
    eventName = parsedName.eventName;
    target = parsedName.target;
    phase = null;
  }
  listeners.push(new BoundEvent(eventName, type, callNode, target, phase, decorator.decoratorSpan, decorator.decoratorSpan, eventNameNode.sourceSpan));
}
function inferBoundAttribute(name) {
  const attrPrefix = 'attr.';
  const classPrefix = 'class.';
  const stylePrefix = 'style.';
  const animationPrefix = 'animate.';
  const legacyAnimationPrefix = '@';
  let attrName;
  let type;
  if (name.startsWith(attrPrefix)) {
    attrName = name.slice(attrPrefix.length);
    type = BindingType.Attribute;
  } else if (name.startsWith(classPrefix)) {
    attrName = name.slice(classPrefix.length);
    type = BindingType.Class;
  } else if (name.startsWith(stylePrefix)) {
    attrName = name.slice(stylePrefix.length);
    type = BindingType.Style;
  } else if (name.startsWith(animationPrefix)) {
    attrName = name;
    type = BindingType.Animation;
  } else if (name.startsWith(legacyAnimationPrefix)) {
    attrName = name.slice(legacyAnimationPrefix.length);
    type = BindingType.LegacyAnimation;
  } else {
    attrName = name;
    type = BindingType.Property;
  }
  return {
    attrName,
    type
  };
}
function fixupSpans(ast, node) {
  const escapeIndex = node.source.indexOf('\\', 1);
  if (escapeIndex > -1) {
    const start = node.sourceSpan.start.offset;
    const end = node.sourceSpan.end.offset;
    const newSpan = new ParseSpan(0, end - start);
    const newSourceSpan = new AbsoluteSourceSpan(start, end);
    ast.visit(new ReplaceSpanVisitor(escapeIndex, newSpan, newSourceSpan));
  }
}
class ReplaceSpanVisitor extends RecursiveAstVisitor {
  afterIndex;
  overrideSpan;
  overrideSourceSpan;
  constructor(afterIndex, overrideSpan, overrideSourceSpan) {
    super();
    this.afterIndex = afterIndex;
    this.overrideSpan = overrideSpan;
    this.overrideSourceSpan = overrideSourceSpan;
  }
  visit(ast) {
    if (ast.span.start >= this.afterIndex || ast.span.end >= this.afterIndex) {
      ast.span = this.overrideSpan;
      ast.sourceSpan = this.overrideSourceSpan;
      if (ast instanceof ASTWithName) {
        ast.nameSpan = this.overrideSourceSpan;
      }
      if (ast instanceof Call || ast instanceof SafeCall) {
        ast.argumentSpan = this.overrideSourceSpan;
      }
    }
    super.visit(ast);
  }
}

var CommentTriviaType;
(function (CommentTriviaType) {
  CommentTriviaType["DIAGNOSTIC"] = "D";
  CommentTriviaType["EXPRESSION_TYPE_IDENTIFIER"] = "T";
})(CommentTriviaType || (CommentTriviaType = {}));
var ExpressionIdentifier;
(function (ExpressionIdentifier) {
  ExpressionIdentifier["DIRECTIVE"] = "DIR";
  ExpressionIdentifier["HOST_DIRECTIVE"] = "HOSTDIR";
  ExpressionIdentifier["COMPONENT_COMPLETION"] = "COMPCOMP";
  ExpressionIdentifier["EVENT_PARAMETER"] = "EP";
  ExpressionIdentifier["VARIABLE_AS_EXPRESSION"] = "VAE";
})(ExpressionIdentifier || (ExpressionIdentifier = {}));

var OutOfBandDiagnosticCategory;
(function (OutOfBandDiagnosticCategory) {
  OutOfBandDiagnosticCategory[OutOfBandDiagnosticCategory["Error"] = 0] = "Error";
  OutOfBandDiagnosticCategory[OutOfBandDiagnosticCategory["Warning"] = 1] = "Warning";
})(OutOfBandDiagnosticCategory || (OutOfBandDiagnosticCategory = {}));

var TcbGenericContextBehavior;
(function (TcbGenericContextBehavior) {
  TcbGenericContextBehavior[TcbGenericContextBehavior["UseEmitter"] = 0] = "UseEmitter";
  TcbGenericContextBehavior[TcbGenericContextBehavior["CopyClassNodes"] = 1] = "CopyClassNodes";
  TcbGenericContextBehavior[TcbGenericContextBehavior["FallbackToAny"] = 2] = "FallbackToAny";
})(TcbGenericContextBehavior || (TcbGenericContextBehavior = {}));
class Context {
  env;
  domSchemaChecker;
  oobRecorder;
  id;
  boundTarget;
  pipes;
  schemas;
  hostIsStandalone;
  hostPreserveWhitespaces;
  nextId = 1;
  constructor(env, domSchemaChecker, oobRecorder, id, boundTarget, pipes, schemas, hostIsStandalone, hostPreserveWhitespaces) {
    this.env = env;
    this.domSchemaChecker = domSchemaChecker;
    this.oobRecorder = oobRecorder;
    this.id = id;
    this.boundTarget = boundTarget;
    this.pipes = pipes;
    this.schemas = schemas;
    this.hostIsStandalone = hostIsStandalone;
    this.hostPreserveWhitespaces = hostPreserveWhitespaces;
  }
  allocateId() {
    return `_t${this.nextId++}`;
  }
  getPipeByName(name) {
    if (this.pipes === null || !this.pipes.has(name)) {
      return null;
    }
    return this.pipes.get(name);
  }
}

class TcbExpr {
  source;
  spanComment = null;
  identifierComment = null;
  ignoreComment = null;
  constructor(source) {
    this.source = source;
  }
  static quoteAndEscape(value) {
    return JSON.stringify(value);
  }
  print(ignoreComments = false) {
    if (ignoreComments) {
      return this.source;
    }
    return this.source + this.formatComment(this.identifierComment) + this.formatComment(this.ignoreComment) + this.formatComment(this.spanComment);
  }
  addParseSpanInfo(span) {
    let start;
    let end;
    if (span instanceof AbsoluteSourceSpan) {
      start = span.start;
      end = span.end;
    } else {
      start = span.start.offset;
      end = span.end.offset;
    }
    this.spanComment = `${start},${end}`;
    return this;
  }
  markIgnoreDiagnostics() {
    this.ignoreComment = `${CommentTriviaType.DIAGNOSTIC}:ignore`;
    return this;
  }
  wrapForTypeChecker() {
    this.source = `(${this.print()})`;
    this.spanComment = this.identifierComment = this.ignoreComment = null;
    return this;
  }
  addExpressionIdentifier(identifier, id) {
    this.identifierComment = `${CommentTriviaType.EXPRESSION_TYPE_IDENTIFIER}:${identifier}${id !== undefined ? `:${id}` : ''}`;
    return this;
  }
  toString() {
    throw new Error('Assertion error: TcbExpr should not be converted to a string through concatenation. ' + 'Use the `print` method instead.');
  }
  formatComment(content) {
    return content === null || content.length === 0 ? '' : ` /*${content}*/`;
  }
}
function declareVariable(identifier, type) {
  type.addExpressionIdentifier(ExpressionIdentifier.VARIABLE_AS_EXPRESSION);
  return new TcbExpr(`var ${identifier.print()} = null! as ${type.print()}`);
}
function getStatementsBlock(expressions, singleLine = false) {
  let result = '';
  for (const expr of expressions) {
    result += `${expr.print()};${singleLine ? ' ' : '\n'}`;
  }
  return result;
}

class TcbOp {
  circularFallback() {
    return new TcbExpr('null!');
  }
}

function astToTcbExpr(ast, maybeResolve, config) {
  const translator = new TcbExprTranslator(maybeResolve, config);
  return translator.translate(ast);
}
class TcbExprTranslator {
  maybeResolve;
  config;
  constructor(maybeResolve, config) {
    this.maybeResolve = maybeResolve;
    this.config = config;
  }
  translate(ast) {
    if (ast instanceof ASTWithSource) {
      ast = ast.ast;
    }
    const resolved = this.maybeResolve(ast);
    if (resolved !== null) {
      return resolved;
    }
    return ast.visit(this);
  }
  visitUnary(ast) {
    const expr = this.translate(ast.expr);
    const node = new TcbExpr(`${ast.operator}${expr.print()}`);
    return node.wrapForTypeChecker().addParseSpanInfo(ast.sourceSpan);
  }
  visitBinary(ast) {
    const lhs = this.translate(ast.left);
    const rhs = this.translate(ast.right);
    lhs.wrapForTypeChecker();
    rhs.wrapForTypeChecker();
    const expression = `${lhs.print()} ${ast.operation} ${rhs.print()}`;
    const node = new TcbExpr(ast.operation === '??' || ast.operation === '**' ? `(${expression})` : expression);
    node.addParseSpanInfo(ast.sourceSpan);
    return node;
  }
  visitChain(ast) {
    const elements = ast.expressions.map(expr => this.translate(expr).print());
    const node = new TcbExpr(elements.join(', '));
    node.wrapForTypeChecker();
    node.addParseSpanInfo(ast.sourceSpan);
    return node;
  }
  visitConditional(ast) {
    const condExpr = this.translate(ast.condition);
    const trueExpr = this.translate(ast.trueExp);
    const falseExpr = this.translate(ast.falseExp).wrapForTypeChecker();
    const node = new TcbExpr(`(${condExpr.print()} ? ${trueExpr.print()} : ${falseExpr.print()})`).addParseSpanInfo(ast.sourceSpan);
    return node;
  }
  visitImplicitReceiver(ast) {
    throw new Error('Method not implemented.');
  }
  visitThisReceiver(ast) {
    throw new Error('Method not implemented.');
  }
  visitRegularExpressionLiteral(ast, context) {
    const node = new TcbExpr(`/${ast.body}/${ast.flags ?? ''}`);
    node.wrapForTypeChecker();
    return node;
  }
  visitInterpolation(ast) {
    const exprs = ast.expressions.map(e => {
      const node = this.translate(e);
      node.wrapForTypeChecker();
      return node.print();
    });
    return new TcbExpr(`"" + ${exprs.join(' + ')}`);
  }
  visitKeyedRead(ast) {
    const receiver = this.translate(ast.receiver);
    if (!this.isStrictSafeNavigationChain(ast.receiver)) {
      receiver.wrapForTypeChecker();
    }
    const key = this.translate(ast.key);
    return new TcbExpr(`${receiver.print()}[${key.print()}]`).addParseSpanInfo(ast.sourceSpan);
  }
  visitLiteralArray(ast) {
    const elements = ast.expressions.map(expr => this.translate(expr));
    let literal = `[${elements.map(el => el.print()).join(', ')}]`;
    if (!this.config.strictLiteralTypes) {
      literal = `(${literal} as any)`;
    }
    return new TcbExpr(literal).addParseSpanInfo(ast.sourceSpan);
  }
  visitLiteralMap(ast) {
    const properties = ast.keys.map((key, idx) => {
      const value = this.translate(ast.values[idx]);
      if (key.kind === 'property') {
        const keyNode = new TcbExpr(TcbExpr.quoteAndEscape(key.key));
        keyNode.addParseSpanInfo(key.sourceSpan);
        return `${keyNode.print()}: ${value.print()}`;
      } else {
        return `...${value.print()}`;
      }
    });
    let literal = `{ ${properties.join(', ')} }`;
    if (!this.config.strictLiteralTypes) {
      literal = `${literal} as any`;
    }
    const expression = new TcbExpr(literal).addParseSpanInfo(ast.sourceSpan);
    expression.wrapForTypeChecker();
    return expression;
  }
  visitLiteralPrimitive(ast) {
    let node;
    if (ast.value === undefined) {
      node = new TcbExpr('undefined');
    } else if (ast.value === null) {
      node = new TcbExpr('null');
    } else if (typeof ast.value === 'string') {
      node = new TcbExpr(TcbExpr.quoteAndEscape(ast.value));
    } else if (typeof ast.value === 'number') {
      if (Number.isNaN(ast.value)) {
        node = new TcbExpr('NaN');
      } else if (!Number.isFinite(ast.value)) {
        node = new TcbExpr(ast.value > 0 ? 'Infinity' : '-Infinity');
      } else {
        node = new TcbExpr(ast.value.toString());
      }
    } else if (typeof ast.value === 'boolean') {
      node = new TcbExpr(ast.value + '');
    } else {
      throw Error(`Unsupported AST value of type ${typeof ast.value}`);
    }
    node.addParseSpanInfo(ast.sourceSpan);
    return node;
  }
  visitNonNullAssert(ast) {
    const expr = this.translate(ast.expression).wrapForTypeChecker();
    return new TcbExpr(`${expr.print()}!`).addParseSpanInfo(ast.sourceSpan);
  }
  visitPipe(ast) {
    throw new Error('Method not implemented.');
  }
  visitPrefixNot(ast) {
    const expression = this.translate(ast.expression).wrapForTypeChecker();
    return new TcbExpr(`!${expression.print()}`).addParseSpanInfo(ast.sourceSpan);
  }
  visitTypeofExpression(ast) {
    const expression = this.translate(ast.expression).wrapForTypeChecker();
    return new TcbExpr(`typeof ${expression.print()}`).addParseSpanInfo(ast.sourceSpan);
  }
  visitVoidExpression(ast) {
    const expression = this.translate(ast.expression).wrapForTypeChecker();
    return new TcbExpr(`void ${expression.print()}`).addParseSpanInfo(ast.sourceSpan);
  }
  visitPropertyRead(ast) {
    const receiver = this.translate(ast.receiver);
    const isSafeChain = this.isStrictSafeNavigationChain(ast.receiver);
    if (!isSafeChain) {
      receiver.wrapForTypeChecker();
    }
    const node = new TcbExpr(`${receiver.print()}.${ast.name}`).addParseSpanInfo(ast.nameSpan);
    let result;
    if (isSafeChain) {
      result = new TcbExpr(node.print());
    } else {
      result = node.wrapForTypeChecker();
    }
    return result.addParseSpanInfo(ast.sourceSpan);
  }
  visitSafePropertyRead(ast) {
    let node;
    const receiver = this.translate(ast.receiver).wrapForTypeChecker();
    const name = new TcbExpr(ast.name).addParseSpanInfo(ast.nameSpan);
    if (this.config.strictSafeNavigationTypes) {
      node = new TcbExpr(`${receiver.print()}?.${name.print()}`);
    } else if (VeSafeLhsInferenceBugDetector.veWillInferAnyFor(ast)) {
      node = new TcbExpr(`(${receiver.print()} as any).${name.print()}`);
    } else {
      node = new TcbExpr(`(${receiver.print()}!.${name.print()} as any)`);
    }
    return node.addParseSpanInfo(ast.sourceSpan);
  }
  visitSafeKeyedRead(ast) {
    const receiver = this.translate(ast.receiver).wrapForTypeChecker();
    const key = this.translate(ast.key);
    let node;
    if (this.config.strictSafeNavigationTypes) {
      node = new TcbExpr(`${receiver.print()}?.[${key.print()}]`);
    } else if (VeSafeLhsInferenceBugDetector.veWillInferAnyFor(ast)) {
      node = new TcbExpr(`(${receiver.print()} as any)[${key.print()}]`);
    } else {
      const elementAccess = new TcbExpr(`${receiver.print()}![${key.print()}]`).addParseSpanInfo(ast.sourceSpan);
      node = new TcbExpr(`(${elementAccess.print()} as any)`);
    }
    return node.addParseSpanInfo(ast.sourceSpan);
  }
  visitCall(ast) {
    const args = ast.args.map(expr => this.translate(expr));
    const receiver = ast.receiver;
    let expr;
    if (receiver instanceof PropertyRead) {
      const resolved = this.maybeResolve(receiver);
      if (resolved !== null) {
        expr = resolved;
      } else {
        const propertyReceiver = this.translate(receiver.receiver);
        if (!this.isStrictSafeNavigationChain(receiver.receiver)) {
          propertyReceiver.wrapForTypeChecker();
        }
        expr = new TcbExpr(`${propertyReceiver.print()}.${receiver.name}`).addParseSpanInfo(receiver.nameSpan);
      }
    } else {
      expr = this.translate(receiver);
    }
    let node;
    if (ast.receiver instanceof SafePropertyRead || ast.receiver instanceof SafeKeyedRead) {
      node = this.convertToSafeCall(ast, expr, args);
    } else {
      node = new TcbExpr(`${expr.print()}(${args.map(arg => arg.print()).join(', ')})`);
    }
    return node.addParseSpanInfo(ast.sourceSpan);
  }
  visitSafeCall(ast) {
    const args = ast.args.map(expr => this.translate(expr));
    const expr = this.translate(ast.receiver).wrapForTypeChecker();
    return this.convertToSafeCall(ast, expr, args).addParseSpanInfo(ast.sourceSpan);
  }
  visitTemplateLiteral(ast) {
    const length = ast.elements.length;
    const head = ast.elements[0];
    let result;
    if (length === 1) {
      result = `\`${this.escapeTemplateLiteral(head.text)}\``;
    } else {
      let parts = [`\`${this.escapeTemplateLiteral(head.text)}`];
      const tailIndex = length - 1;
      for (let i = 1; i < tailIndex; i++) {
        const expr = this.translate(ast.expressions[i - 1]);
        parts.push(`\${${expr.print()}}${this.escapeTemplateLiteral(ast.elements[i].text)}`);
      }
      const resolvedExpression = this.translate(ast.expressions[tailIndex - 1]);
      parts.push(`\${${resolvedExpression.print()}}${this.escapeTemplateLiteral(ast.elements[tailIndex].text)}\``);
      result = parts.join('');
    }
    return new TcbExpr(result);
  }
  visitTemplateLiteralElement() {
    throw new Error('Method not implemented');
  }
  visitTaggedTemplateLiteral(ast) {
    const tag = this.translate(ast.tag);
    const template = this.visitTemplateLiteral(ast.template);
    return new TcbExpr(`${tag.print()}${template.print()}`);
  }
  visitParenthesizedExpression(ast) {
    const expr = this.translate(ast.expression);
    return new TcbExpr(`(${expr.print()})`);
  }
  visitSpreadElement(ast) {
    const expression = this.translate(ast.expression);
    expression.wrapForTypeChecker();
    const node = new TcbExpr(`...${expression.print()}`);
    node.addParseSpanInfo(ast.sourceSpan);
    return node;
  }
  visitEmptyExpr(ast) {
    const node = new TcbExpr('undefined');
    node.addParseSpanInfo(ast.sourceSpan);
    return node;
  }
  visitArrowFunction(ast) {
    const params = ast.parameters.map(param => new TcbExpr(param.name).markIgnoreDiagnostics().print()).join(', ');
    const body = astToTcbExpr(ast.body, innerAst => {
      if (!(innerAst instanceof PropertyRead) || innerAst.receiver instanceof ThisReceiver || !(innerAst.receiver instanceof ImplicitReceiver)) {
        return this.maybeResolve(innerAst);
      }
      const correspondingParam = ast.parameters.find(arg => arg.name === innerAst.name);
      if (correspondingParam) {
        const node = new TcbExpr(innerAst.name);
        node.addParseSpanInfo(innerAst.sourceSpan);
        return node;
      }
      return this.maybeResolve(innerAst);
    }, this.config);
    return new TcbExpr(`${ast.parameters.length === 1 ? params : `(${params})`} => ${body.print()}`);
  }
  convertToSafeCall(ast, exprNode, argNodes) {
    const expr = exprNode.print();
    const args = argNodes.map(node => node.print()).join(', ');
    if (this.config.strictSafeNavigationTypes) {
      return new TcbExpr(`${expr}?.(${args})`);
    }
    if (VeSafeLhsInferenceBugDetector.veWillInferAnyFor(ast)) {
      return new TcbExpr(`(${expr} as any)(${args})`);
    }
    return new TcbExpr(`(${expr}!(${args}) as any)`);
  }
  escapeTemplateLiteral(value) {
    return value.replace(/\\/g, '\\\\').replace(/`/g, '\\`').replace(/\${/g, '$\\{');
  }
  isStrictSafeNavigationChain(ast) {
    if (!this.config.strictSafeNavigationTypes) {
      return false;
    }
    let current = ast;
    while (current) {
      if (current instanceof SafePropertyRead || current instanceof SafeKeyedRead || current instanceof SafeCall) {
        return true;
      }
      if (current instanceof PropertyRead || current instanceof KeyedRead || current instanceof Call) {
        current = current.receiver;
      } else if (current instanceof NonNullAssert) {
        current = current.expression;
      } else {
        break;
      }
    }
    return false;
  }
}
class VeSafeLhsInferenceBugDetector {
  static SINGLETON = new VeSafeLhsInferenceBugDetector();
  static veWillInferAnyFor(ast) {
    const visitor = VeSafeLhsInferenceBugDetector.SINGLETON;
    return ast instanceof Call ? ast.visit(visitor) : ast.receiver.visit(visitor);
  }
  visitUnary(ast) {
    return ast.expr.visit(this);
  }
  visitBinary(ast) {
    return ast.left.visit(this) || ast.right.visit(this);
  }
  visitChain() {
    return false;
  }
  visitConditional(ast) {
    return ast.condition.visit(this) || ast.trueExp.visit(this) || ast.falseExp.visit(this);
  }
  visitCall() {
    return true;
  }
  visitSafeCall() {
    return false;
  }
  visitImplicitReceiver() {
    return false;
  }
  visitThisReceiver() {
    return false;
  }
  visitInterpolation(ast) {
    return ast.expressions.some(exp => exp.visit(this));
  }
  visitKeyedRead() {
    return false;
  }
  visitLiteralArray() {
    return true;
  }
  visitLiteralMap() {
    return true;
  }
  visitLiteralPrimitive() {
    return false;
  }
  visitPipe() {
    return true;
  }
  visitPrefixNot(ast) {
    return ast.expression.visit(this);
  }
  visitTypeofExpression(ast) {
    return ast.expression.visit(this);
  }
  visitVoidExpression(ast) {
    return ast.expression.visit(this);
  }
  visitNonNullAssert(ast) {
    return ast.expression.visit(this);
  }
  visitPropertyRead() {
    return false;
  }
  visitSafePropertyRead() {
    return false;
  }
  visitSafeKeyedRead() {
    return false;
  }
  visitTemplateLiteral() {
    return false;
  }
  visitTemplateLiteralElement() {
    return false;
  }
  visitTaggedTemplateLiteral() {
    return false;
  }
  visitParenthesizedExpression(ast) {
    return ast.expression.visit(this);
  }
  visitRegularExpressionLiteral() {
    return false;
  }
  visitSpreadElement(ast) {
    return ast.expression.visit(this);
  }
  visitArrowFunction(ast, context) {
    return false;
  }
}

function tcbExpression(ast, tcb, scope) {
  const translator = new TcbExpressionTranslator(tcb, scope);
  return translator.translate(ast);
}
function unwrapWritableSignal(expression, tcb) {
  const unwrapRef = tcb.env.referenceExternalSymbol(Identifiers.unwrapWritableSignal.moduleName, Identifiers.unwrapWritableSignal.name);
  return new TcbExpr(`${unwrapRef.print()}(${expression.print()})`);
}
class TcbExpressionOp extends TcbOp {
  tcb;
  scope;
  expression;
  constructor(tcb, scope, expression) {
    super();
    this.tcb = tcb;
    this.scope = scope;
    this.expression = expression;
  }
  get optional() {
    return false;
  }
  execute() {
    const expr = tcbExpression(this.expression, this.tcb, this.scope);
    this.scope.addStatement(expr);
    return null;
  }
}
class TcbConditionOp extends TcbOp {
  tcb;
  scope;
  expression;
  constructor(tcb, scope, expression) {
    super();
    this.tcb = tcb;
    this.scope = scope;
    this.expression = expression;
  }
  get optional() {
    return false;
  }
  execute() {
    const expr = tcbExpression(this.expression, this.tcb, this.scope);
    this.scope.addStatement(new TcbExpr(`if (${expr.print()}) {}`));
    return null;
  }
}
class TcbExpressionTranslator {
  tcb;
  scope;
  constructor(tcb, scope) {
    this.tcb = tcb;
    this.scope = scope;
  }
  translate(ast) {
    return astToTcbExpr(ast, ast => this.resolve(ast), this.tcb.env.config);
  }
  resolve(ast) {
    if (ast instanceof PropertyRead && ast.receiver instanceof ImplicitReceiver) {
      const target = this.tcb.boundTarget.getExpressionTarget(ast);
      const targetExpression = target === null ? null : this.getTargetNodeExpression(target, ast);
      if (target instanceof LetDeclaration$1 && !this.isValidLetDeclarationAccess(target, ast)) {
        this.tcb.oobRecorder.letUsedBeforeDefinition(this.tcb.id, ast, target);
        if (targetExpression !== null) {
          return new TcbExpr(`${targetExpression.print()} as any`);
        }
      }
      return targetExpression;
    } else if (ast instanceof Binary && Binary.isAssignmentOperation(ast.operation) && ast.left instanceof PropertyRead && (ast.left.receiver instanceof ImplicitReceiver || ast.left.receiver instanceof ThisReceiver)) {
      const read = ast.left;
      const target = this.tcb.boundTarget.getExpressionTarget(read);
      if (target === null) {
        return null;
      }
      const targetExpression = this.getTargetNodeExpression(target, read);
      const expr = this.translate(ast.right);
      const result = new TcbExpr(`(${targetExpression.print()} = ${expr.print()})`);
      result.addParseSpanInfo(read.sourceSpan);
      if (target instanceof LetDeclaration$1) {
        result.markIgnoreDiagnostics();
        this.tcb.oobRecorder.illegalWriteToLetDeclaration(this.tcb.id, read, target);
      }
      return result;
    } else if (ast instanceof ImplicitReceiver || ast instanceof ThisReceiver) {
      return new TcbExpr('this');
    } else if (ast instanceof BindingPipe) {
      const expr = this.translate(ast.exp);
      const pipeMeta = this.tcb.getPipeByName(ast.name);
      let pipe;
      if (pipeMeta === null) {
        this.tcb.oobRecorder.missingPipe(this.tcb.id, ast, this.tcb.hostIsStandalone);
        pipe = new TcbExpr('(0 as any)');
      } else if (pipeMeta.isExplicitlyDeferred && this.tcb.boundTarget.getEagerlyUsedPipes().includes(ast.name)) {
        this.tcb.oobRecorder.deferredPipeUsedEagerly(this.tcb.id, ast);
        pipe = new TcbExpr('(0 as any)');
      } else {
        pipe = this.tcb.env.pipeInst(pipeMeta);
      }
      const args = ast.args.map(arg => this.translate(arg).print());
      let methodAccess = new TcbExpr(`${pipe.print()}.transform`).addParseSpanInfo(ast.nameSpan);
      if (!this.tcb.env.config.checkTypeOfPipes) {
        methodAccess = new TcbExpr(`(${methodAccess.print()} as any)`);
      }
      const result = new TcbExpr(`${methodAccess.print()}(${[expr.print(), ...args].join(', ')})`);
      return result.addParseSpanInfo(ast.sourceSpan);
    } else if ((ast instanceof Call || ast instanceof SafeCall) && (ast.receiver instanceof PropertyRead || ast.receiver instanceof SafePropertyRead)) {
      if (ast.receiver.receiver instanceof ImplicitReceiver && ast.receiver.name === '$safeNavigationMigration' && ast.args.length === 1) {
        const expr = this.translate(ast.args[0]);
        const result = new TcbExpr(`(${expr.print()})`);
        result.addParseSpanInfo(ast.sourceSpan);
        return result;
      }
      if (ast.receiver.receiver instanceof ImplicitReceiver && ast.receiver.name === '$any' && ast.args.length === 1) {
        const expr = this.translate(ast.args[0]);
        const result = new TcbExpr(`(${expr.print()} as any)`);
        result.addParseSpanInfo(ast.sourceSpan);
        return result;
      }
      const target = this.tcb.boundTarget.getExpressionTarget(ast);
      if (target === null) {
        return null;
      }
      const method = this.getTargetNodeExpression(target, ast);
      method.addParseSpanInfo(ast.receiver.nameSpan).wrapForTypeChecker();
      const args = ast.args.map(arg => this.translate(arg).print());
      const node = new TcbExpr(`${method.print()}(${args.join(', ')})`);
      node.addParseSpanInfo(ast.sourceSpan);
      return node;
    } else {
      return null;
    }
  }
  getTargetNodeExpression(targetNode, expressionNode) {
    const expr = this.scope.resolve(targetNode);
    expr.addParseSpanInfo(expressionNode.sourceSpan);
    return expr;
  }
  isValidLetDeclarationAccess(target, ast) {
    const targetStart = target.sourceSpan.start.offset;
    const targetEnd = target.sourceSpan.end.offset;
    const astStart = ast.sourceSpan.start;
    return targetStart < astStart && astStart > targetEnd || !this.scope.isLocal(target);
  }
}

class TcbTemplateContextOp extends TcbOp {
  tcb;
  scope;
  constructor(tcb, scope) {
    super();
    this.tcb = tcb;
    this.scope = scope;
  }
  optional = true;
  execute() {
    const ctx = new TcbExpr(this.tcb.allocateId());
    this.scope.addStatement(declareVariable(ctx, new TcbExpr('any')));
    return ctx;
  }
}
class TcbTemplateBodyOp extends TcbOp {
  tcb;
  scope;
  template;
  constructor(tcb, scope, template) {
    super();
    this.tcb = tcb;
    this.scope = scope;
    this.template = template;
  }
  get optional() {
    return false;
  }
  execute() {
    let guard = null;
    const directiveGuards = [];
    this.addDirectiveGuards(directiveGuards, this.template, this.tcb.boundTarget.getDirectivesOfNode(this.template));
    for (const directive of this.template.directives) {
      this.addDirectiveGuards(directiveGuards, directive, this.tcb.boundTarget.getDirectivesOfNode(directive));
    }
    if (directiveGuards.length > 0) {
      guard = directiveGuards.reduce((expr, dirGuard) => new TcbExpr(`${expr.print()} && ${dirGuard.print()}`), directiveGuards.pop());
    }
    const tmplScope = this.scope.createChildScope(this.scope, this.template, this.template.children, guard);
    const statements = tmplScope.render();
    if (statements.length === 0) {
      return null;
    }
    let tmplBlock = `{\n${getStatementsBlock(statements)}}`;
    if (guard !== null) {
      tmplBlock = `if (${guard.print()}) ${tmplBlock}`;
    }
    this.scope.addStatement(new TcbExpr(tmplBlock));
    return null;
  }
  addDirectiveGuards(guards, hostNode, directives) {
    if (directives === null || directives.length === 0) {
      return;
    }
    const isTemplate = hostNode instanceof Template;
    for (const dir of directives) {
      const dirInstId = this.scope.resolve(hostNode, dir);
      const dirId = this.tcb.env.referenceTcbValue(dir.ref);
      dir.ngTemplateGuards.forEach(guard => {
        const boundInput = hostNode.inputs.find(i => i.name === guard.inputName) || (isTemplate ? hostNode.templateAttrs.find(input => {
          return input instanceof BoundAttribute && input.name === guard.inputName;
        }) : undefined);
        if (boundInput !== undefined) {
          const expr = tcbExpression(boundInput.value, this.tcb, this.scope);
          expr.markIgnoreDiagnostics();
          if (guard.type === 'binding') {
            guards.push(expr);
          } else {
            const guardInvoke = new TcbExpr(`${dirId.print()}.ngTemplateGuard_${guard.inputName}(${dirInstId.print()}, ${expr.print()})`);
            guardInvoke.addParseSpanInfo(boundInput.value.sourceSpan);
            guards.push(guardInvoke);
          }
        }
      });
      if (dir.hasNgTemplateContextGuard) {
        if (this.tcb.env.config.applyTemplateContextGuards) {
          const ctx = this.scope.resolve(hostNode);
          const guardInvoke = new TcbExpr(`${dirId.print()}.ngTemplateContextGuard(${dirInstId.print()}, ${ctx.print()})`);
          guardInvoke.markIgnoreDiagnostics();
          guardInvoke.addParseSpanInfo(hostNode.sourceSpan);
          guards.push(guardInvoke);
        }
      }
    }
  }
}

class TcbElementOp extends TcbOp {
  tcb;
  scope;
  element;
  constructor(tcb, scope, element) {
    super();
    this.tcb = tcb;
    this.scope = scope;
    this.element = element;
  }
  get optional() {
    return true;
  }
  execute() {
    const id = this.tcb.allocateId();
    const idNode = new TcbExpr(id);
    idNode.addParseSpanInfo(this.element.startSourceSpan || this.element.sourceSpan);
    const initializer = new TcbExpr(`document.createElement("${this.element.name}")`);
    initializer.addParseSpanInfo(this.element.startSourceSpan || this.element.sourceSpan);
    const stmt = new TcbExpr(`var ${idNode.print()} = ${initializer.print()}`);
    stmt.addParseSpanInfo(this.element.startSourceSpan || this.element.sourceSpan);
    this.scope.addStatement(stmt);
    return idNode;
  }
}

class TcbBlockImplicitVariableOp extends TcbOp {
  tcb;
  scope;
  type;
  variable;
  constructor(tcb, scope, type, variable) {
    super();
    this.tcb = tcb;
    this.scope = scope;
    this.type = type;
    this.variable = variable;
  }
  optional = true;
  execute() {
    const id = new TcbExpr(this.tcb.allocateId());
    id.addParseSpanInfo(this.variable.keySpan);
    const variable = declareVariable(id, this.type);
    variable.addParseSpanInfo(this.variable.sourceSpan);
    this.scope.addStatement(variable);
    return id;
  }
}
class TcbTemplateVariableOp extends TcbOp {
  tcb;
  scope;
  template;
  variable;
  constructor(tcb, scope, template, variable) {
    super();
    this.tcb = tcb;
    this.scope = scope;
    this.template = template;
    this.variable = variable;
  }
  get optional() {
    return false;
  }
  execute() {
    const ctx = this.scope.resolve(this.template);
    const id = new TcbExpr(this.tcb.allocateId());
    const initializer = new TcbExpr(`${ctx.print()}.${this.variable.value || '$implicit'}`);
    id.addParseSpanInfo(this.variable.keySpan);
    if (this.variable.valueSpan !== undefined) {
      initializer.addParseSpanInfo(this.variable.valueSpan).wrapForTypeChecker();
    }
    const variable = new TcbExpr(`var ${id.print()} = ${initializer.print()}`);
    variable.addParseSpanInfo(this.variable.sourceSpan);
    this.scope.addStatement(variable);
    return id;
  }
}
class TcbBlockVariableOp extends TcbOp {
  tcb;
  scope;
  initializer;
  variable;
  constructor(tcb, scope, initializer, variable) {
    super();
    this.tcb = tcb;
    this.scope = scope;
    this.initializer = initializer;
    this.variable = variable;
  }
  get optional() {
    return false;
  }
  execute() {
    const id = new TcbExpr(this.tcb.allocateId());
    id.addParseSpanInfo(this.variable.keySpan);
    this.initializer.wrapForTypeChecker();
    const variable = new TcbExpr(`var ${id.print()} = ${this.initializer.print()}`);
    variable.addParseSpanInfo(this.variable.sourceSpan);
    this.scope.addStatement(variable);
    return id;
  }
}

class TcbComponentContextCompletionOp extends TcbOp {
  scope;
  constructor(scope) {
    super();
    this.scope = scope;
  }
  optional = false;
  execute() {
    const ctx = new TcbExpr('this.');
    ctx.markIgnoreDiagnostics();
    ctx.addExpressionIdentifier(ExpressionIdentifier.COMPONENT_COMPLETION);
    this.scope.addStatement(ctx);
    return null;
  }
}

class TcbReferenceOp extends TcbOp {
  tcb;
  scope;
  node;
  host;
  target;
  constructor(tcb, scope, node, host, target) {
    super();
    this.tcb = tcb;
    this.scope = scope;
    this.node = node;
    this.host = host;
    this.target = target;
  }
  optional = true;
  execute() {
    const id = new TcbExpr(this.tcb.allocateId());
    let initializer = this.target instanceof Template || this.target instanceof Element$1 ? this.scope.resolve(this.target) : this.scope.resolve(this.host, this.target);
    if (this.target instanceof Element$1 && !this.tcb.env.config.checkTypeOfDomReferences || !this.tcb.env.config.checkTypeOfNonDomReferences) {
      initializer = new TcbExpr(`${initializer.print()} as any`);
    } else if (this.target instanceof Template) {
      const templateRef = this.tcb.env.referenceExternalSymbol('@angular/core', 'TemplateRef');
      initializer = new TcbExpr(`(${initializer.print()} as any as ${templateRef.print()}<any>)`);
    }
    initializer.addParseSpanInfo(this.node.sourceSpan);
    id.addParseSpanInfo(this.node.keySpan);
    this.scope.addStatement(new TcbExpr(`var ${id.print()} = ${initializer.print()}`));
    return id;
  }
}
class TcbInvalidReferenceOp extends TcbOp {
  tcb;
  scope;
  constructor(tcb, scope) {
    super();
    this.tcb = tcb;
    this.scope = scope;
  }
  optional = true;
  execute() {
    const id = new TcbExpr(this.tcb.allocateId());
    this.scope.addStatement(new TcbExpr(`var ${id.print()} = null! as any`));
    return id;
  }
}

class TcbIfBlockOp extends TcbOp {
  tcb;
  scope;
  block;
  expressionScopes = new Map();
  constructor(tcb, scope, block) {
    super();
    this.tcb = tcb;
    this.scope = scope;
    this.block = block;
  }
  get optional() {
    return false;
  }
  execute() {
    const root = this.generateBranch(0);
    root && this.scope.addStatement(root);
    return null;
  }
  generateBranch(index) {
    const branch = this.block.branches[index];
    if (!branch) {
      return undefined;
    }
    if (branch.expression === null) {
      const branchScope = this.getBranchScope(this.scope, branch, index);
      return new TcbExpr(`{\n${getStatementsBlock(branchScope.render())}}`);
    }
    const outerScope = this.scope.createChildScope(this.scope, branch, [], null);
    outerScope.render().forEach(stmt => this.scope.addStatement(stmt));
    this.expressionScopes.set(branch, outerScope);
    let expression = tcbExpression(branch.expression, this.tcb, this.scope);
    if (branch.expressionAlias !== null) {
      expression = new TcbExpr(`(${expression.print()}) && ${outerScope.resolve(branch.expressionAlias).print()}`);
    }
    const bodyScope = this.getBranchScope(outerScope, branch, index);
    const ifStatement = `if (${expression.print()}) {\n${getStatementsBlock(bodyScope.render())}}`;
    const elseBranch = this.generateBranch(index + 1);
    return new TcbExpr(ifStatement + (elseBranch ? ' else ' + elseBranch.print() : ''));
  }
  getBranchScope(parentScope, branch, index) {
    const checkBody = this.tcb.env.config.checkControlFlowBodies;
    return this.scope.createChildScope(parentScope, null, checkBody ? branch.children : [], checkBody ? this.generateBranchGuard(index) : null);
  }
  generateBranchGuard(index) {
    let guard = null;
    for (let i = 0; i <= index; i++) {
      const branch = this.block.branches[i];
      if (branch.expression === null) {
        continue;
      }
      if (!this.expressionScopes.has(branch)) {
        throw new Error(`Could not determine expression scope of branch at index ${i}`);
      }
      const expressionScope = this.expressionScopes.get(branch);
      let expression;
      expression = tcbExpression(branch.expression, this.tcb, expressionScope);
      if (branch.expressionAlias !== null) {
        expression = new TcbExpr(`(${expression.print()}) && ${expressionScope.resolve(branch.expressionAlias).print()}`);
      }
      expression.markIgnoreDiagnostics();
      const comparisonExpression = i === index ? expression : new TcbExpr(`!(${expression.print()})`);
      guard = guard === null ? comparisonExpression : new TcbExpr(`(${guard.print()}) && (${comparisonExpression.print()})`);
    }
    return guard;
  }
}

class TcbSwitchOp extends TcbOp {
  tcb;
  scope;
  block;
  constructor(tcb, scope, block) {
    super();
    this.tcb = tcb;
    this.scope = scope;
    this.block = block;
  }
  get optional() {
    return false;
  }
  execute() {
    const switchExpression = tcbExpression(this.block.expression, this.tcb, this.scope);
    const clauses = this.block.groups.flatMap(current => {
      const checkBody = this.tcb.env.config.checkControlFlowBodies;
      const clauseScope = this.scope.createChildScope(this.scope, null, checkBody ? current.children : [], checkBody ? this.generateGuard(current, switchExpression) : null);
      const statements = [...clauseScope.render(), new TcbExpr('break')];
      return current.cases.map((switchCase, index) => {
        const statementsStr = getStatementsBlock(index === current.cases.length - 1 ? statements : [], true);
        const source = switchCase.expression === null ? `default: ${statementsStr}` : `case ${tcbExpression(switchCase.expression, this.tcb, this.scope).print()}: ${statementsStr}`;
        return new TcbExpr(source);
      });
    });
    if (this.block.exhaustiveCheck) {
      let translateExpression = this.block.expression;
      if (this.block.exhaustiveCheck.expression) {
        translateExpression = this.block.exhaustiveCheck.expression;
      }
      const switchValue = tcbExpression(translateExpression, this.tcb, this.scope);
      const exhaustiveId = this.tcb.allocateId();
      clauses.push(new TcbExpr(`default: const tcbExhaustive${exhaustiveId}: never = ${switchValue.print()};`));
    }
    this.scope.addStatement(new TcbExpr(`switch (${switchExpression.print()}) { ${clauses.map(c => c.print()).join('\n')} }`));
    return null;
  }
  generateGuard(group, switchValue) {
    const hasDefault = group.cases.some(c => c.expression === null);
    if (!hasDefault) {
      let guard = null;
      for (const switchCase of group.cases) {
        if (switchCase.expression !== null) {
          const expression = tcbExpression(switchCase.expression, this.tcb, this.scope);
          expression.markIgnoreDiagnostics();
          const comparison = new TcbExpr(`${switchValue.print()} === ${expression.print()}`);
          if (guard === null) {
            guard = comparison;
          } else {
            guard = new TcbExpr(`(${guard.print()}) || (${comparison.print()})`);
          }
        }
      }
      return guard;
    }
    let guard = null;
    for (const currentGroup of this.block.groups) {
      if (currentGroup === group) {
        continue;
      }
      for (const switchCase of currentGroup.cases) {
        if (switchCase.expression === null) {
          continue;
        }
        const expression = tcbExpression(switchCase.expression, this.tcb, this.scope);
        expression.markIgnoreDiagnostics();
        const comparison = new TcbExpr(`${switchValue.print()} !== ${expression.print()}`);
        if (guard === null) {
          guard = comparison;
        } else {
          guard = new TcbExpr(`(${guard.print()}) && (${comparison.print()})`);
        }
      }
    }
    return guard;
  }
}

class TcbForOfOp extends TcbOp {
  tcb;
  scope;
  block;
  constructor(tcb, scope, block) {
    super();
    this.tcb = tcb;
    this.scope = scope;
    this.block = block;
  }
  get optional() {
    return false;
  }
  execute() {
    const loopScope = this.scope.createChildScope(this.scope, this.block, this.tcb.env.config.checkControlFlowBodies ? this.block.children : [], null);
    const initializerId = loopScope.resolve(this.block.item);
    const initializer = new TcbExpr(`const ${initializerId.print()}`);
    initializer.addParseSpanInfo(this.block.item.keySpan);
    const expression = new TcbExpr(`${tcbExpression(this.block.expression, this.tcb, this.scope).print()}!`);
    let statements;
    if (this.block.trackBy === null) {
      statements = loopScope.render();
    } else {
      const trackTranslator = new TcbForLoopTrackTranslator(this.tcb, loopScope, this.block);
      const trackExpression = trackTranslator.translate(this.block.trackBy);
      statements = [...loopScope.render(), trackExpression];
    }
    this.scope.addStatement(new TcbExpr(`for (${initializer.print()} of ${expression.print()}) {\n${getStatementsBlock(statements)} }`));
    return null;
  }
}
class TcbForLoopTrackTranslator extends TcbExpressionTranslator {
  block;
  allowedVariables;
  constructor(tcb, scope, block) {
    super(tcb, scope);
    this.block = block;
    this.allowedVariables = new Set([block.item]);
    for (const variable of block.contextVariables) {
      if (variable.value === '$index') {
        this.allowedVariables.add(variable);
      }
    }
  }
  resolve(ast) {
    if (ast instanceof PropertyRead && (ast.receiver instanceof ImplicitReceiver || ast.receiver instanceof ThisReceiver)) {
      const target = this.tcb.boundTarget.getExpressionTarget(ast);
      if (target !== null && (!(target instanceof Variable) || !this.allowedVariables.has(target))) {
        this.tcb.oobRecorder.illegalForLoopTrackAccess(this.tcb.id, this.block, ast);
      }
    }
    return super.resolve(ast);
  }
}

class TcbLetDeclarationOp extends TcbOp {
  tcb;
  scope;
  node;
  constructor(tcb, scope, node) {
    super();
    this.tcb = tcb;
    this.scope = scope;
    this.node = node;
  }
  optional = false;
  execute() {
    const id = new TcbExpr(this.tcb.allocateId()).addParseSpanInfo(this.node.nameSpan);
    const value = tcbExpression(this.node.value, this.tcb, this.scope).wrapForTypeChecker();
    const varStatement = new TcbExpr(`const ${id.print()} = ${value.print()}`);
    varStatement.addParseSpanInfo(this.node.sourceSpan);
    this.scope.addStatement(varStatement);
    return id;
  }
}

const formControlInputFields = ['errors', 'dirty', 'disabled', 'disabledReasons', 'hidden', 'invalid', 'name', 'pending', 'readonly', 'touched', 'max', 'maxLength', 'min', 'minLength', 'pattern', 'required'];
const customFormControlBannedInputFields = new Set([...formControlInputFields, 'value', 'checked']);
const formControlOptionalFields = new Set(['max', 'maxLength', 'min', 'minLength']);
class TcbNativeFieldOp extends TcbOp {
  tcb;
  scope;
  node;
  inputType;
  unsupportedBindingFields = new Set([...formControlInputFields, 'value', 'checked', 'maxlength', 'minlength']);
  hasDynamicType;
  get optional() {
    return false;
  }
  constructor(tcb, scope, node, inputType) {
    super();
    this.tcb = tcb;
    this.scope = scope;
    this.node = node;
    this.inputType = inputType;
    this.hasDynamicType = this.inputType === null && this.node.inputs.some(input => (input.type === BindingType.Property || input.type === BindingType.Attribute) && input.name === 'type');
    const isPossiblyDateOrTime = this.hasDynamicType || this.inputType === 'date' || this.inputType === 'time' || this.inputType === 'month' || this.inputType === 'week' || this.inputType === 'datetime-local';
    if (isPossiblyDateOrTime) {
      this.unsupportedBindingFields.delete('min');
      this.unsupportedBindingFields.delete('max');
    }
  }
  execute() {
    const inputs = this.node instanceof HostElement ? this.node.bindings : this.node.inputs;
    const fieldBinding = inputs.find(input => input.type === BindingType.Property && input.name === 'formField') ?? null;
    if (fieldBinding === null) {
      return null;
    }
    checkUnsupportedFieldBindings(this.node, this.unsupportedBindingFields, this.tcb);
    const rawExpectedType = this.getExpectedTypeFromDomNode(this.node);
    if (rawExpectedType === null) {
      const signal = extractFieldValueSignal(fieldBinding.value, this.tcb, this.scope);
      const id = new TcbExpr(this.tcb.allocateId());
      const unionType = new TcbExpr('{ (): string; set: (v: string) => void; } | { (): number | null; set: (v: number | null) => void; }');
      const assignment = new TcbExpr(`${id.print()} = ${signal.print()}`);
      assignment.addParseSpanInfo(fieldBinding.valueSpan ?? fieldBinding.sourceSpan);
      this.scope.addStatement(declareVariable(id, unionType));
      this.scope.addStatement(assignment);
    } else {
      const expectedType = new TcbExpr(rawExpectedType);
      const value = extractFieldValue(fieldBinding.value, this.tcb, this.scope);
      const id = new TcbExpr(this.tcb.allocateId());
      const assignment = new TcbExpr(`${id.print()} = ${value.print()}`);
      assignment.addParseSpanInfo(fieldBinding.valueSpan ?? fieldBinding.sourceSpan);
      this.scope.addStatement(declareVariable(id, expectedType));
      this.scope.addStatement(assignment);
    }
    return null;
  }
  getExpectedTypeFromDomNode(node) {
    if (node.name === 'textarea' || node.name === 'select') {
      return 'string';
    }
    if (node.name !== 'input') {
      return this.getUnsupportedType();
    }
    switch (this.inputType) {
      case 'checkbox':
        return 'boolean';
      case 'radio':
        return 'string';
      case 'number':
      case 'range':
      case 'datetime-local':
        return 'string | number | null';
      case 'date':
      case 'month':
      case 'time':
      case 'week':
        return 'string | number | Date | null';
    }
    if (this.hasDynamicType) {
      return 'string | number | boolean | Date | null';
    }
    if (this.inputType === 'text' || this.inputType === null) {
      return null;
    }
    return 'string';
  }
  getUnsupportedType() {
    return 'never';
  }
}
class TcbNativeRadioButtonFieldOp extends TcbNativeFieldOp {
  constructor(tcb, scope, node) {
    super(tcb, scope, node, 'radio');
    this.unsupportedBindingFields.delete('value');
  }
  execute() {
    super.execute();
    const valueBinding = this.node.inputs.find(attr => {
      return attr.type === BindingType.Property && attr.name === 'value';
    });
    if (valueBinding !== undefined) {
      const id = new TcbExpr(this.tcb.allocateId());
      const value = tcbExpression(valueBinding.value, this.tcb, this.scope);
      const assignment = new TcbExpr(`${id.print()} = ${value.print()}`);
      assignment.addParseSpanInfo(valueBinding.sourceSpan);
      this.scope.addStatement(declareVariable(id, new TcbExpr('string')));
      this.scope.addStatement(assignment);
    }
    return null;
  }
}
function expandBoundAttributesForField(directive, node, customFormControlType) {
  const fieldBinding = node.inputs.find(input => input.type === BindingType.Property && input.name === 'formField');
  if (!fieldBinding) {
    return null;
  }
  let boundInputs = null;
  let primaryInput;
  if (customFormControlType === 'value') {
    primaryInput = getSyntheticFieldBoundInput(directive, 'value', 'value', fieldBinding, customFormControlType);
  } else if (customFormControlType === 'checkbox') {
    primaryInput = getSyntheticFieldBoundInput(directive, 'checked', 'value', fieldBinding, customFormControlType);
  } else {
    primaryInput = null;
  }
  if (primaryInput !== null) {
    boundInputs ??= [];
    boundInputs.push(primaryInput);
  }
  for (const name of formControlInputFields) {
    const input = getSyntheticFieldBoundInput(directive, name, name, fieldBinding, customFormControlType);
    if (input !== null) {
      boundInputs ??= [];
      boundInputs.push(input);
    }
  }
  return boundInputs;
}
function isFieldDirective(meta) {
  if (meta.name !== 'FormField') {
    return false;
  }
  if (meta.ref.moduleName === '@angular/forms/signals') {
    return true;
  }
  return meta.hasNgFieldDirective;
}
function getSyntheticFieldBoundInput(dir, inputName, fieldPropertyName, fieldBinding, customFieldType) {
  const inputs = dir.inputs.getByBindingPropertyName(inputName);
  if (inputs === null || inputs.length === 0) {
    return null;
  }
  const {
    span,
    sourceSpan
  } = fieldBinding.value;
  const outerCall = new Call(span, sourceSpan, fieldBinding.value, [], sourceSpan);
  const read = new PropertyRead(span, sourceSpan, sourceSpan, outerCall, fieldPropertyName);
  const isTwoWayBinding = customFieldType === 'value' && inputName === 'value' || customFieldType === 'checkbox' && inputName === 'checked';
  let value;
  if (isTwoWayBinding) {
    value = read;
  } else if (formControlOptionalFields.has(fieldPropertyName)) {
    value = new SafeCall(span, sourceSpan, read, [], sourceSpan);
  } else {
    value = new Call(span, sourceSpan, read, [], sourceSpan);
  }
  return {
    value,
    sourceSpan: fieldBinding.sourceSpan,
    keySpan: fieldBinding.keySpan ?? null,
    inputs: inputs.map(input => ({
      fieldName: input.classPropertyName,
      required: input.required,
      transformType: input.transformType,
      isSignal: input.isSignal,
      isTwoWayBinding
    }))
  };
}
function getCustomFieldDirectiveType(meta) {
  if (hasModelInput('value', meta)) {
    return 'value';
  } else if (hasModelInput('checked', meta)) {
    return 'checkbox';
  }
  return null;
}
function isNativeField(dir, node, allDirectiveMatches) {
  if (!isFieldDirective(dir)) {
    return false;
  }
  if (!(node instanceof Element$1) || node.name !== 'input' && node.name !== 'select' && node.name !== 'textarea') {
    return false;
  }
  return allDirectiveMatches.every(meta => {
    return getCustomFieldDirectiveType(meta) === null && !isControlValueAccessorLike(meta);
  });
}
function isControlValueAccessorLike(meta) {
  return meta.publicMethods.has('writeValue') && meta.publicMethods.has('registerOnChange') && meta.publicMethods.has('registerOnTouched');
}
function checkUnsupportedFieldBindings(node, unsupportedBindingFields, tcb) {
  const inputs = node instanceof HostElement ? node.bindings : node.inputs;
  for (const input of inputs) {
    if (input.type === BindingType.Property && unsupportedBindingFields.has(input.name)) {
      tcb.oobRecorder.formFieldUnsupportedBinding(tcb.id, input);
    } else if (input.type === BindingType.Attribute && unsupportedBindingFields.has(input.name.toLowerCase())) {
      tcb.oobRecorder.formFieldUnsupportedBinding(tcb.id, input);
    } else if (input.type === BindingType.TwoWay && unsupportedBindingFields.has(input.name)) {
      tcb.oobRecorder.formFieldUnsupportedBinding(tcb.id, input);
    }
  }
  if (!(node instanceof HostElement)) {
    for (const attr of node.attributes) {
      if (unsupportedBindingFields.has(attr.name.toLowerCase())) {
        tcb.oobRecorder.formFieldUnsupportedBinding(tcb.id, attr);
      }
    }
  }
}
function extractFieldValue(expression, tcb, scope) {
  const innerCall = new TcbExpr(tcbExpression(expression, tcb, scope).print() + '()');
  innerCall.markIgnoreDiagnostics();
  return new TcbExpr(`${innerCall.print()}.value()`);
}
function extractFieldValueSignal(expression, tcb, scope) {
  const innerCall = new TcbExpr(tcbExpression(expression, tcb, scope).print() + '()');
  innerCall.markIgnoreDiagnostics();
  return new TcbExpr(`${innerCall.print()}.value`);
}
function hasModelInput(name, meta) {
  return meta.inputs.hasBindingPropertyName(name) && meta.outputs.hasBindingPropertyName(name + 'Change');
}
function isFormControl(allDirectiveMatches) {
  let result = false;
  for (const match of allDirectiveMatches) {
    if (match.inputs.hasBindingPropertyName('formField')) {
      if (!isFieldDirective(match)) {
        return false;
      }
      result = true;
    }
  }
  return result;
}

function getBoundAttributes(directive, node) {
  const boundInputs = [];
  const processAttribute = attr => {
    if (attr instanceof BoundAttribute && attr.type !== BindingType.Property && attr.type !== BindingType.TwoWay) {
      return;
    }
    const inputs = directive.inputs.getByBindingPropertyName(attr.name);
    if (inputs !== null) {
      boundInputs.push({
        value: attr.value,
        sourceSpan: attr.sourceSpan,
        keySpan: attr.keySpan ?? null,
        inputs: inputs.map(input => {
          return {
            fieldName: input.classPropertyName,
            required: input.required,
            transformType: input.transformType,
            isSignal: input.isSignal,
            isTwoWayBinding: attr instanceof BoundAttribute && attr.type === BindingType.TwoWay
          };
        })
      });
    }
  };
  if (node instanceof Template) {
    if (node.tagName === 'ng-template') {
      node.inputs.forEach(processAttribute);
      node.attributes.forEach(processAttribute);
    }
    node.templateAttrs.forEach(processAttribute);
  } else {
    node.inputs.forEach(processAttribute);
    node.attributes.forEach(processAttribute);
  }
  return boundInputs;
}
function checkSplitTwoWayBinding(inputName, output, inputs, tcb) {
  const input = inputs.find(input => input.name === inputName);
  if (input === undefined || input.sourceSpan !== output.sourceSpan) {
    return false;
  }
  const inputConsumer = tcb.boundTarget.getConsumerOfBinding(input);
  const outputConsumer = tcb.boundTarget.getConsumerOfBinding(output);
  if (outputConsumer === null || inputConsumer.ref === undefined || outputConsumer instanceof Template) {
    return false;
  }
  if (outputConsumer instanceof Element$1) {
    tcb.oobRecorder.splitTwoWayBinding(tcb.id, input, output, inputConsumer, outputConsumer);
    return true;
  } else if (outputConsumer.ref !== inputConsumer.ref) {
    tcb.oobRecorder.splitTwoWayBinding(tcb.id, input, output, inputConsumer, outputConsumer);
    return true;
  }
  return false;
}
function widenBinding(expr, tcb, originalValue) {
  if (!tcb.env.config.checkTypeOfInputBindings) {
    return new TcbExpr(`((${expr.print()}) as any)`);
  } else if (!tcb.env.config.strictNullInputBindings) {
    if (originalValue instanceof LiteralMap || originalValue instanceof LiteralArray) {
      return expr;
    } else {
      return new TcbExpr(`(${expr.print()})!`);
    }
  } else {
    return expr;
  }
}

const REGISTRY$1 = new DomElementSchemaRegistry();
function translateInput(value, tcb, scope) {
  if (typeof value === 'string') {
    return new TcbExpr(TcbExpr.quoteAndEscape(value));
  } else {
    return tcbExpression(value, tcb, scope);
  }
}
class TcbDirectiveInputsOp extends TcbOp {
  tcb;
  scope;
  node;
  dir;
  isFormControl;
  customFormControlType;
  constructor(tcb, scope, node, dir, isFormControl = false, customFormControlType) {
    super();
    this.tcb = tcb;
    this.scope = scope;
    this.node = node;
    this.dir = dir;
    this.isFormControl = isFormControl;
    this.customFormControlType = customFormControlType;
  }
  get optional() {
    return false;
  }
  execute() {
    let dirId = null;
    const seenRequiredInputs = new Set();
    const boundAttrs = getBoundAttributes(this.dir, this.node);
    if (this.customFormControlType !== null) {
      checkUnsupportedFieldBindings(this.node, customFormControlBannedInputFields, this.tcb);
    }
    if (this.customFormControlType !== null || this.isFormControl) {
      const additionalBindings = expandBoundAttributesForField(this.dir, this.node, this.customFormControlType);
      if (additionalBindings !== null) {
        boundAttrs.push(...additionalBindings);
      }
    }
    for (const attr of boundAttrs) {
      let assignment = widenBinding(translateInput(attr.value, this.tcb, this.scope), this.tcb, attr.value);
      assignment.wrapForTypeChecker();
      for (const {
        fieldName,
        required,
        transformType,
        isSignal,
        isTwoWayBinding
      } of attr.inputs) {
        let target;
        if (required) {
          seenRequiredInputs.add(fieldName);
        }
        if (this.dir.coercedInputFields.has(fieldName)) {
          let type;
          if (transformType !== undefined) {
            type = new TcbExpr(transformType);
          } else {
            const dirTypeRef = this.tcb.env.referenceTcbValue(this.dir.ref);
            const propName = `ngAcceptInputType_${fieldName}`;
            const access = isUnsafeObjectKey(fieldName) ? `[${TcbExpr.quoteAndEscape(propName)}]` : `.${propName}`;
            type = new TcbExpr(`typeof ${dirTypeRef.print()}${access}`);
          }
          const id = new TcbExpr(this.tcb.allocateId());
          this.scope.addStatement(declareVariable(id, type));
          target = id;
        } else if (this.dir.undeclaredInputFields.has(fieldName)) {
          continue;
        } else if (!this.tcb.env.config.honorAccessModifiersForInputBindings && this.dir.restrictedInputFields.has(fieldName)) {
          if (dirId === null) {
            dirId = this.scope.resolve(this.node, this.dir);
          }
          const id = new TcbExpr(this.tcb.allocateId());
          const type = new TcbExpr(`(typeof ${dirId.print()})[${TcbExpr.quoteAndEscape(fieldName)}]`);
          const temp = declareVariable(id, type);
          this.scope.addStatement(temp);
          target = id;
        } else {
          if (dirId === null) {
            dirId = this.scope.resolve(this.node, this.dir);
          }
          target = this.dir.stringLiteralInputFields.has(fieldName) ? new TcbExpr(`${dirId.print()}[${TcbExpr.quoteAndEscape(fieldName)}]`) : new TcbExpr(`${dirId.print()}.${fieldName}`);
        }
        if (isSignal) {
          const inputSignalBrandWriteSymbol = this.tcb.env.referenceExternalSymbol(Identifiers.InputSignalBrandWriteType.moduleName, Identifiers.InputSignalBrandWriteType.name);
          target = new TcbExpr(`${target.print()}[${inputSignalBrandWriteSymbol.print()}]`);
        }
        if (attr.keySpan !== null) {
          target.addParseSpanInfo(attr.keySpan);
        }
        if (isTwoWayBinding && this.tcb.env.config.allowSignalsInTwoWayBindings) {
          assignment = unwrapWritableSignal(assignment, this.tcb);
        }
        assignment = new TcbExpr(`${target.print()} = ${assignment.print()}`);
      }
      assignment.addParseSpanInfo(attr.sourceSpan);
      if (!this.tcb.env.config.checkTypeOfAttributes && typeof attr.value === 'string') {
        assignment.markIgnoreDiagnostics();
      }
      this.scope.addStatement(assignment);
    }
    this.checkRequiredInputs(seenRequiredInputs);
    return null;
  }
  checkRequiredInputs(seenRequiredInputs) {
    const missing = [];
    for (const input of this.dir.inputs) {
      if (input.required && !seenRequiredInputs.has(input.classPropertyName)) {
        missing.push(input.bindingPropertyName);
      }
    }
    if (missing.length > 0) {
      this.tcb.oobRecorder.missingRequiredInputs(this.tcb.id, this.node, this.dir.name, this.dir.isComponent, missing);
    }
  }
}
class TcbUnclaimedInputsOp extends TcbOp {
  tcb;
  scope;
  inputs;
  target;
  claimedInputs;
  constructor(tcb, scope, inputs, target, claimedInputs) {
    super();
    this.tcb = tcb;
    this.scope = scope;
    this.inputs = inputs;
    this.target = target;
    this.claimedInputs = claimedInputs;
  }
  get optional() {
    return false;
  }
  execute() {
    let elId = null;
    for (const binding of this.inputs) {
      const isPropertyBinding = binding.type === BindingType.Property || binding.type === BindingType.TwoWay;
      if (isPropertyBinding && this.claimedInputs?.has(binding.name)) {
        continue;
      }
      const expr = widenBinding(tcbExpression(binding.value, this.tcb, this.scope), this.tcb, binding.value);
      if (this.tcb.env.config.checkTypeOfDomBindings && isPropertyBinding) {
        if (binding.name !== 'style' && binding.name !== 'class') {
          if (elId === null) {
            elId = this.scope.resolve(this.target);
          }
          const propertyName = REGISTRY$1.getMappedPropName(binding.name);
          const stmt = new TcbExpr(`${elId.print()}[${TcbExpr.quoteAndEscape(propertyName)}] = ${expr.wrapForTypeChecker().print()}`).addParseSpanInfo(binding.sourceSpan);
          this.scope.addStatement(stmt);
        } else {
          this.scope.addStatement(expr);
        }
      } else {
        this.scope.addStatement(expr);
      }
    }
    return null;
  }
}

function getComponentTagName(node) {
  return node.tagName || 'ng-component';
}
class TcbComponentNodeOp extends TcbOp {
  tcb;
  scope;
  component;
  optional = true;
  constructor(tcb, scope, component) {
    super();
    this.tcb = tcb;
    this.scope = scope;
    this.component = component;
  }
  execute() {
    const id = this.tcb.allocateId();
    const initializer = new TcbExpr(`document.createElement("${getComponentTagName(this.component)}")`);
    initializer.addParseSpanInfo(this.component.startSourceSpan || this.component.sourceSpan);
    this.scope.addStatement(new TcbExpr(`var ${id} = ${initializer.print()}`));
    return new TcbExpr(id);
  }
}

const REGISTRY = new DomElementSchemaRegistry();
class TcbDomSchemaCheckerOp extends TcbOp {
  tcb;
  element;
  checkElement;
  claimedInputs;
  constructor(tcb, element, checkElement, claimedInputs) {
    super();
    this.tcb = tcb;
    this.element = element;
    this.checkElement = checkElement;
    this.claimedInputs = claimedInputs;
  }
  get optional() {
    return false;
  }
  execute() {
    const element = this.element;
    const isTemplateElement = element instanceof Element$1 || element instanceof Component$1;
    const bindings = isTemplateElement ? element.inputs : element.bindings;
    if (this.checkElement && isTemplateElement) {
      this.tcb.domSchemaChecker.checkElement(this.tcb.id, this.getTagName(element), element.startSourceSpan, this.tcb.schemas, this.tcb.hostIsStandalone);
    }
    for (const binding of bindings) {
      const isPropertyBinding = binding.type === BindingType.Property || binding.type === BindingType.TwoWay;
      if (isPropertyBinding && this.claimedInputs?.has(binding.name)) {
        continue;
      }
      if (isPropertyBinding && binding.name !== 'style' && binding.name !== 'class') {
        const propertyName = REGISTRY.getMappedPropName(binding.name);
        if (isTemplateElement) {
          this.tcb.domSchemaChecker.checkTemplateElementProperty(this.tcb.id, this.getTagName(element), propertyName, binding.sourceSpan, this.tcb.schemas, this.tcb.hostIsStandalone);
        } else {
          this.tcb.domSchemaChecker.checkHostElementProperty(this.tcb.id, element, propertyName, binding.keySpan, this.tcb.schemas);
        }
      }
    }
    return null;
  }
  getTagName(node) {
    return node instanceof Element$1 ? node.name : getComponentTagName(node);
  }
}

const EVENT_PARAMETER = '$event';
function tcbEventHandlerExpression(ast, tcb, scope) {
  const translator = new TcbEventHandlerTranslator(tcb, scope);
  return translator.translate(ast);
}
class TcbDirectiveOutputsOp extends TcbOp {
  tcb;
  scope;
  node;
  inputs;
  outputs;
  dir;
  constructor(tcb, scope, node, inputs, outputs, dir) {
    super();
    this.tcb = tcb;
    this.scope = scope;
    this.node = node;
    this.inputs = inputs;
    this.outputs = outputs;
    this.dir = dir;
  }
  get optional() {
    return false;
  }
  execute() {
    let dirId = null;
    const outputs = this.dir.outputs;
    for (const output of this.outputs) {
      if (output.type === ParsedEventType.LegacyAnimation || !outputs.hasBindingPropertyName(output.name)) {
        continue;
      }
      if (this.tcb.env.config.checkTypeOfOutputEvents && this.inputs !== null && output.name.endsWith('Change')) {
        const inputName = output.name.slice(0, -6);
        checkSplitTwoWayBinding(inputName, output, this.inputs, this.tcb);
      }
      const field = outputs.getByBindingPropertyName(output.name)[0].classPropertyName;
      if (dirId === null) {
        dirId = this.scope.resolve(this.node, this.dir);
      }
      const outputField = new TcbExpr(`${dirId.print()}[${TcbExpr.quoteAndEscape(field)}]`);
      outputField.addParseSpanInfo(output.keySpan);
      if (this.tcb.env.config.checkTypeOfOutputEvents) {
        const handler = tcbCreateEventHandler(output, this.tcb, this.scope, 0);
        const call = new TcbExpr(`${outputField.print()}.subscribe(${handler.print()})`);
        call.addParseSpanInfo(output.sourceSpan);
        this.scope.addStatement(call);
      } else {
        this.scope.addStatement(outputField);
        const handler = tcbCreateEventHandler(output, this.tcb, this.scope, 1);
        this.scope.addStatement(handler);
      }
    }
    return null;
  }
}
class TcbUnclaimedOutputsOp extends TcbOp {
  tcb;
  scope;
  target;
  outputs;
  inputs;
  claimedOutputs;
  constructor(tcb, scope, target, outputs, inputs, claimedOutputs) {
    super();
    this.tcb = tcb;
    this.scope = scope;
    this.target = target;
    this.outputs = outputs;
    this.inputs = inputs;
    this.claimedOutputs = claimedOutputs;
  }
  get optional() {
    return false;
  }
  execute() {
    let elId = null;
    for (const output of this.outputs) {
      if (this.claimedOutputs?.has(output.name)) {
        continue;
      }
      if (this.tcb.env.config.checkTypeOfOutputEvents && this.inputs !== null && output.name.endsWith('Change')) {
        const inputName = output.name.slice(0, -6);
        if (checkSplitTwoWayBinding(inputName, output, this.inputs, this.tcb)) {
          continue;
        }
      }
      if (output.type === ParsedEventType.LegacyAnimation) {
        const eventType = this.tcb.env.config.checkTypeOfAnimationEvents ? this.tcb.env.referenceExternalSymbol('@angular/animations', 'AnimationEvent').print() : 1;
        const handler = tcbCreateEventHandler(output, this.tcb, this.scope, eventType);
        this.scope.addStatement(handler);
      } else if (output.type === ParsedEventType.Animation) {
        const eventType = this.tcb.env.referenceExternalSymbol('@angular/core', 'AnimationCallbackEvent');
        const handler = tcbCreateEventHandler(output, this.tcb, this.scope, eventType.print());
        this.scope.addStatement(handler);
      } else if (this.tcb.env.config.checkTypeOfDomEvents) {
        let target;
        let domEventAssertion;
        if (output.target === 'window' || output.target === 'document') {
          target = new TcbExpr(output.target);
        } else if (elId === null) {
          target = elId = this.scope.resolve(this.target);
        } else {
          target = elId;
        }
        if (this.target instanceof Element$1 && this.target.isVoid && this.tcb.env.config.allowDomEventAssertion) {
          const assertUtil = this.tcb.env.referenceExternalSymbol('@angular/core', 'ɵassertType');
          domEventAssertion = new TcbExpr(`${assertUtil.print()}<typeof ${target.print()}>(${EVENT_PARAMETER}.target)`);
        }
        const propertyAccess = new TcbExpr(`${target.print()}.addEventListener`).addParseSpanInfo(output.keySpan);
        const handler = tcbCreateEventHandler(output, this.tcb, this.scope, 0, domEventAssertion);
        const call = new TcbExpr(`${propertyAccess.print()}(${TcbExpr.quoteAndEscape(output.name)}, ${handler.print()})`);
        call.addParseSpanInfo(output.sourceSpan);
        this.scope.addStatement(call);
      } else {
        const handler = tcbCreateEventHandler(output, this.tcb, this.scope, 1);
        this.scope.addStatement(handler);
      }
    }
    return null;
  }
}
class TcbEventHandlerTranslator extends TcbExpressionTranslator {
  resolve(ast) {
    if (ast instanceof PropertyRead && ast.receiver instanceof ImplicitReceiver && ast.name === EVENT_PARAMETER) {
      return new TcbExpr(EVENT_PARAMETER).addParseSpanInfo(ast.nameSpan);
    }
    return super.resolve(ast);
  }
  isValidLetDeclarationAccess() {
    return true;
  }
}
function tcbCreateEventHandler(event, tcb, scope, eventType, assertionExpression) {
  const handler = tcbEventHandlerExpression(event.handler, tcb, scope);
  const statements = [];
  if (assertionExpression !== undefined) {
    statements.push(assertionExpression);
  }
  statements.push(handler);
  let eventParamType;
  if (eventType === 0) {
    eventParamType = undefined;
  } else if (eventType === 1) {
    eventParamType = 'any';
  } else {
    eventParamType = eventType;
  }
  const guards = scope.guards();
  let body = `{\n${getStatementsBlock(statements)} }`;
  if (guards !== null) {
    body = `{ if (${guards.print()}) ${body} }`;
  }
  const eventParam = new TcbExpr(`${EVENT_PARAMETER}${eventParamType === undefined ? '' : ': ' + eventParamType}`);
  eventParam.addExpressionIdentifier(ExpressionIdentifier.EVENT_PARAMETER);
  return new TcbExpr(`(${eventParam.print()}): any => ${body}`);
}

class TcbDirectiveTypeOpBase extends TcbOp {
  tcb;
  scope;
  node;
  dir;
  directiveIndex;
  constructor(tcb, scope, node, dir, directiveIndex) {
    super();
    this.tcb = tcb;
    this.scope = scope;
    this.node = node;
    this.dir = dir;
    this.directiveIndex = directiveIndex;
  }
  get optional() {
    return true;
  }
  execute() {
    const rawType = this.tcb.env.referenceTcbValue(this.dir.ref);
    let type;
    let span;
    if (this.dir.isGeneric === false || this.dir.typeParameters === null || this.dir.typeParameters.length === 0) {
      type = rawType;
    } else {
      const typeArguments = Array(this.dir.typeParameters?.length ?? 0).fill('any').join(', ');
      type = new TcbExpr(`${rawType.print()}<${typeArguments}>`);
    }
    if (this.node instanceof HostElement) {
      span = this.node.sourceSpan;
    } else {
      span = this.node.startSourceSpan || this.node.sourceSpan;
    }
    const identifier = this.dir.matchSource === MatchSource.HostDirective ? ExpressionIdentifier.HOST_DIRECTIVE : ExpressionIdentifier.DIRECTIVE;
    const id = new TcbExpr(this.tcb.allocateId()).addExpressionIdentifier(identifier, this.directiveIndex).addParseSpanInfo(span);
    this.scope.addStatement(declareVariable(id, type));
    return id;
  }
}
class TcbNonGenericDirectiveTypeOp extends TcbDirectiveTypeOpBase {
  execute() {
    if (this.dir.isGeneric) {
      throw new Error(`Assertion Error: expected ${this.dir.ref.name} not to be generic.`);
    }
    return super.execute();
  }
}
class TcbGenericDirectiveTypeWithAnyParamsOp extends TcbDirectiveTypeOpBase {
  execute() {
    if (this.dir.typeParameters === null || this.dir.typeParameters.length === 0) {
      throw new Error(`Assertion Error: expected typeParameters when creating a declaration for ${this.dir.ref.name}`);
    }
    return super.execute();
  }
}

class TcbDirectiveCtorOp extends TcbOp {
  tcb;
  scope;
  node;
  dir;
  customFormControlType;
  directiveIndex;
  constructor(tcb, scope, node, dir, customFormControlType, directiveIndex) {
    super();
    this.tcb = tcb;
    this.scope = scope;
    this.node = node;
    this.dir = dir;
    this.customFormControlType = customFormControlType;
    this.directiveIndex = directiveIndex;
  }
  get optional() {
    return true;
  }
  execute() {
    const genericInputs = new Map();
    const id = new TcbExpr(this.tcb.allocateId());
    let boundAttrs;
    let span;
    if (this.node instanceof HostElement) {
      boundAttrs = [];
      span = this.node.sourceSpan;
    } else {
      span = this.node.startSourceSpan || this.node.sourceSpan;
      boundAttrs = getBoundAttributes(this.dir, this.node);
      if (this.customFormControlType !== null) {
        const additionalBindings = expandBoundAttributesForField(this.dir, this.node, this.customFormControlType);
        if (additionalBindings !== null) {
          boundAttrs.push(...additionalBindings);
        }
      }
    }
    const identifier = this.dir.matchSource === MatchSource.HostDirective ? ExpressionIdentifier.HOST_DIRECTIVE : ExpressionIdentifier.DIRECTIVE;
    id.addExpressionIdentifier(identifier, this.directiveIndex).addParseSpanInfo(span);
    for (const attr of boundAttrs) {
      if (!this.tcb.env.config.checkTypeOfAttributes && typeof attr.value === 'string') {
        continue;
      }
      for (const {
        fieldName,
        isTwoWayBinding
      } of attr.inputs) {
        if (genericInputs.has(fieldName)) {
          continue;
        }
        const expression = translateInput(attr.value, this.tcb, this.scope);
        genericInputs.set(fieldName, {
          type: 'binding',
          field: fieldName,
          expression,
          originalExpression: attr.value,
          sourceSpan: attr.sourceSpan,
          isTwoWayBinding
        });
      }
    }
    for (const {
      classPropertyName
    } of this.dir.inputs) {
      if (!genericInputs.has(classPropertyName)) {
        genericInputs.set(classPropertyName, {
          type: 'unset',
          field: classPropertyName
        });
      }
    }
    const typeCtor = tcbCallTypeCtor(this.dir, this.tcb, Array.from(genericInputs.values()));
    typeCtor.markIgnoreDiagnostics();
    this.scope.addStatement(new TcbExpr(`var ${id.print()} = ${typeCtor.print()}`));
    return id;
  }
  circularFallback() {
    return new TcbDirectiveCtorCircularFallbackOp(this.tcb, this.scope, this.dir);
  }
}
class TcbDirectiveCtorCircularFallbackOp extends TcbOp {
  tcb;
  scope;
  dir;
  constructor(tcb, scope, dir) {
    super();
    this.tcb = tcb;
    this.scope = scope;
    this.dir = dir;
  }
  get optional() {
    return false;
  }
  execute() {
    const id = this.tcb.allocateId();
    const typeCtor = this.tcb.env.typeCtorFor(this.dir);
    this.scope.addStatement(new TcbExpr(`var ${id} = ${typeCtor.print()}(null!)`));
    return new TcbExpr(id);
  }
}
function tcbCallTypeCtor(dir, tcb, inputs) {
  const typeCtor = tcb.env.typeCtorFor(dir);
  let literal = '{ ';
  for (let i = 0; i < inputs.length; i++) {
    const input = inputs[i];
    const propertyName = TcbExpr.quoteAndEscape(input.field);
    const isLast = i === inputs.length - 1;
    if (input.type === 'binding') {
      let expr = widenBinding(input.expression, tcb, input.originalExpression);
      if (input.isTwoWayBinding && tcb.env.config.allowSignalsInTwoWayBindings) {
        expr = unwrapWritableSignal(expr, tcb);
      }
      const assignment = new TcbExpr(`${propertyName}: ${expr.wrapForTypeChecker().print()}`);
      assignment.addParseSpanInfo(input.sourceSpan);
      literal += assignment.print();
    } else {
      literal += `${propertyName}: 0 as any`;
    }
    literal += `${isLast ? '' : ','} `;
  }
  literal += '}';
  return new TcbExpr(`${typeCtor.print()}(${literal})`);
}

class TcbControlFlowContentProjectionOp extends TcbOp {
  tcb;
  element;
  ngContentSelectors;
  componentName;
  category;
  constructor(tcb, element, ngContentSelectors, componentName) {
    super();
    this.tcb = tcb;
    this.element = element;
    this.ngContentSelectors = ngContentSelectors;
    this.componentName = componentName;
    this.category = tcb.env.config.controlFlowPreventingContentProjection === 'error' ? OutOfBandDiagnosticCategory.Error : OutOfBandDiagnosticCategory.Warning;
  }
  optional = false;
  execute() {
    const controlFlowToCheck = this.findPotentialControlFlowNodes();
    if (controlFlowToCheck.length > 0) {
      const matcher = new SelectorMatcher();
      for (const selector of this.ngContentSelectors) {
        if (selector !== '*') {
          matcher.addSelectables(CssSelector.parse(selector), selector);
        }
      }
      for (const root of controlFlowToCheck) {
        for (const child of root.children) {
          if (child instanceof Element$1 || child instanceof Template) {
            matcher.match(createCssSelectorFromNode(child), (_, originalSelector) => {
              this.tcb.oobRecorder.controlFlowPreventingContentProjection(this.tcb.id, this.category, child, this.componentName, originalSelector, root, this.tcb.hostPreserveWhitespaces);
            });
          }
        }
      }
    }
    return null;
  }
  findPotentialControlFlowNodes() {
    const result = [];
    for (const child of this.element.children) {
      if (child instanceof ForLoopBlock) {
        if (this.shouldCheck(child)) {
          result.push(child);
        }
        if (child.empty !== null && this.shouldCheck(child.empty)) {
          result.push(child.empty);
        }
      } else if (child instanceof IfBlock) {
        for (const branch of child.branches) {
          if (this.shouldCheck(branch)) {
            result.push(branch);
          }
        }
      } else if (child instanceof SwitchBlock) {
        for (const current of child.groups) {
          if (this.shouldCheck(current)) {
            result.push(current);
          }
        }
      }
    }
    return result;
  }
  shouldCheck(node) {
    if (node.children.length < 2) {
      return false;
    }
    let hasSeenRootNode = false;
    for (const child of node.children) {
      if (!(child instanceof Text$3) || this.tcb.hostPreserveWhitespaces || child.value.trim().length > 0) {
        if (hasSeenRootNode) {
          return true;
        }
        hasSeenRootNode = true;
      }
    }
    return false;
  }
}

class TcbIntersectionObserverOp extends TcbOp {
  tcb;
  scope;
  options;
  constructor(tcb, scope, options) {
    super();
    this.tcb = tcb;
    this.scope = scope;
    this.options = options;
  }
  optional = false;
  execute() {
    const options = tcbExpression(this.options, this.tcb, this.scope);
    this.scope.addStatement(new TcbExpr(`new IntersectionObserver(null!, ${options.print()})`));
    return null;
  }
}

class TcbHostElementOp extends TcbOp {
  tcb;
  scope;
  element;
  optional = true;
  constructor(tcb, scope, element) {
    super();
    this.tcb = tcb;
    this.scope = scope;
    this.element = element;
  }
  execute() {
    const id = this.tcb.allocateId();
    let tagNames;
    if (this.element.tagNames.length === 1) {
      tagNames = `"${this.element.tagNames[0]}"`;
    } else {
      tagNames = `null! as ${this.element.tagNames.map(t => `"${t}"`).join(' | ')}`;
    }
    const initializer = new TcbExpr(`document.createElement(${tagNames})`);
    initializer.addParseSpanInfo(this.element.sourceSpan);
    this.scope.addStatement(new TcbExpr(`var ${id} = ${initializer.print()}`));
    return new TcbExpr(id);
  }
}

class Scope {
  tcb;
  parent;
  guard;
  opQueue = [];
  elementOpMap = new Map();
  hostElementOpMap = new Map();
  componentNodeOpMap = new Map();
  directiveOpMap = new Map();
  referenceOpMap = new Map();
  templateCtxOpMap = new Map();
  varMap = new Map();
  letDeclOpMap = new Map();
  statements = [];
  static getForLoopContextVariableTypes() {
    return new Map([['$first', 'boolean'], ['$last', 'boolean'], ['$even', 'boolean'], ['$odd', 'boolean'], ['$index', 'number'], ['$count', 'number']]);
  }
  constructor(tcb, parent = null, guard = null) {
    this.tcb = tcb;
    this.parent = parent;
    this.guard = guard;
  }
  static forNodes(tcb, parentScope, scopedNode, children, guard) {
    const scope = new Scope(tcb, parentScope, guard);
    if (parentScope === null && tcb.env.config.enableTemplateTypeChecker) {
      scope.opQueue.push(new TcbComponentContextCompletionOp(scope));
    }
    if (scopedNode instanceof Template) {
      const varMap = new Map();
      for (const v of scopedNode.variables) {
        if (!varMap.has(v.name)) {
          varMap.set(v.name, v);
        } else {
          const firstDecl = varMap.get(v.name);
          tcb.oobRecorder.duplicateTemplateVar(tcb.id, v, firstDecl);
        }
        Scope.registerVariable(scope, v, new TcbTemplateVariableOp(tcb, scope, scopedNode, v));
      }
    } else if (scopedNode instanceof IfBlockBranch) {
      const {
        expression,
        expressionAlias
      } = scopedNode;
      if (expression !== null && expressionAlias !== null) {
        Scope.registerVariable(scope, expressionAlias, new TcbBlockVariableOp(tcb, scope, tcbExpression(expression, tcb, scope), expressionAlias));
      }
    } else if (scopedNode instanceof ForLoopBlock) {
      const loopInitializer = new TcbExpr(tcb.allocateId());
      loopInitializer.addParseSpanInfo(scopedNode.item.sourceSpan);
      scope.varMap.set(scopedNode.item, loopInitializer);
      const forLoopContextVariableTypes = Scope.getForLoopContextVariableTypes();
      for (const variable of scopedNode.contextVariables) {
        if (!forLoopContextVariableTypes.has(variable.value)) {
          throw new Error(`Unrecognized for loop context variable ${variable.name}`);
        }
        const type = new TcbExpr(forLoopContextVariableTypes.get(variable.value));
        Scope.registerVariable(scope, variable, new TcbBlockImplicitVariableOp(tcb, scope, type, variable));
      }
    } else if (scopedNode instanceof HostElement) {
      scope.appendNode(scopedNode);
    }
    if (children !== null) {
      for (const node of children) {
        scope.appendNode(node);
      }
    }
    for (const variable of scope.varMap.keys()) {
      Scope.checkConflictingLet(scope, variable);
    }
    for (const ref of scope.referenceOpMap.keys()) {
      Scope.checkConflictingLet(scope, ref);
    }
    return scope;
  }
  static registerVariable(scope, variable, op) {
    const opIndex = scope.opQueue.push(op) - 1;
    scope.varMap.set(variable, opIndex);
  }
  resolve(node, directive) {
    const res = this.resolveLocal(node, directive);
    if (res !== null) {
      return res;
    } else if (this.parent !== null) {
      return this.parent.resolve(node, directive);
    } else {
      throw new Error(`Could not resolve ${node} / ${directive}`);
    }
  }
  addStatement(stmt) {
    this.statements.push(stmt);
  }
  render() {
    for (let i = 0; i < this.opQueue.length; i++) {
      const skipOptional = !this.tcb.env.config.enableTemplateTypeChecker;
      this.executeOp(i, skipOptional);
    }
    return this.statements;
  }
  guards() {
    let parentGuards = null;
    if (this.parent !== null) {
      parentGuards = this.parent.guards();
    }
    if (this.guard === null) {
      return parentGuards;
    } else if (parentGuards === null) {
      return typeof this.guard === 'string' ? new TcbExpr(this.guard) : this.guard;
    } else {
      const guard = typeof this.guard === 'string' ? this.guard : this.guard.print();
      return new TcbExpr(`(${parentGuards.print()}) && (${guard})`);
    }
  }
  isLocal(node) {
    if (node instanceof Variable) {
      return this.varMap.has(node);
    }
    if (node instanceof LetDeclaration$1) {
      return this.letDeclOpMap.has(node.name);
    }
    return this.referenceOpMap.has(node);
  }
  createChildScope(parentScope, scopedNode, children, guard) {
    return Scope.forNodes(this.tcb, parentScope, scopedNode, children, guard);
  }
  resolveLocal(ref, directive) {
    if (ref instanceof Reference && this.referenceOpMap.has(ref)) {
      return this.resolveOp(this.referenceOpMap.get(ref));
    } else if (ref instanceof LetDeclaration$1 && this.letDeclOpMap.has(ref.name)) {
      return this.resolveOp(this.letDeclOpMap.get(ref.name).opIndex);
    } else if (ref instanceof Variable && this.varMap.has(ref)) {
      const opIndexOrNode = this.varMap.get(ref);
      return typeof opIndexOrNode === 'number' ? this.resolveOp(opIndexOrNode) : new TcbExpr(opIndexOrNode.print(true));
    } else if (ref instanceof Template && directive === undefined && this.templateCtxOpMap.has(ref)) {
      return this.resolveOp(this.templateCtxOpMap.get(ref));
    } else if ((ref instanceof Element$1 || ref instanceof Template || ref instanceof Component$1 || ref instanceof Directive$1 || ref instanceof HostElement) && directive !== undefined && this.directiveOpMap.has(ref)) {
      const dirMap = this.directiveOpMap.get(ref);
      return dirMap.has(directive) ? this.resolveOp(dirMap.get(directive)) : null;
    } else if (ref instanceof Element$1 && this.elementOpMap.has(ref)) {
      return this.resolveOp(this.elementOpMap.get(ref));
    } else if (ref instanceof Component$1 && this.componentNodeOpMap.has(ref)) {
      return this.resolveOp(this.componentNodeOpMap.get(ref));
    } else if (ref instanceof HostElement && this.hostElementOpMap.has(ref)) {
      return this.resolveOp(this.hostElementOpMap.get(ref));
    } else {
      return null;
    }
  }
  resolveOp(opIndex) {
    const res = this.executeOp(opIndex, false);
    if (res === null) {
      throw new Error(`Error resolving operation, got null`);
    }
    return res;
  }
  executeOp(opIndex, skipOptional) {
    const op = this.opQueue[opIndex];
    if (!(op instanceof TcbOp)) {
      return op === null ? null : new TcbExpr(op.print(true));
    }
    if (skipOptional && op.optional) {
      return null;
    }
    this.opQueue[opIndex] = op.circularFallback();
    let res = op.execute();
    if (res !== null) {
      res = new TcbExpr(res.print(true));
    }
    this.opQueue[opIndex] = res;
    return res;
  }
  appendNode(node) {
    if (node instanceof Element$1) {
      const opIndex = this.opQueue.push(new TcbElementOp(this.tcb, this, node)) - 1;
      this.elementOpMap.set(node, opIndex);
      if (this.tcb.env.config.controlFlowPreventingContentProjection !== 'suppress') {
        this.appendContentProjectionCheckOp(node);
      }
      this.appendDirectivesAndInputsOfElementLikeNode(node);
      this.appendOutputsOfElementLikeNode(node, node.inputs, node.outputs);
      this.appendSelectorlessDirectives(node);
      this.appendChildren(node);
      this.checkAndAppendReferencesOfNode(node);
    } else if (node instanceof Template) {
      this.appendDirectivesAndInputsOfElementLikeNode(node);
      this.appendOutputsOfElementLikeNode(node, node.inputs, node.outputs);
      this.appendSelectorlessDirectives(node);
      const ctxIndex = this.opQueue.push(new TcbTemplateContextOp(this.tcb, this)) - 1;
      this.templateCtxOpMap.set(node, ctxIndex);
      if (this.tcb.env.config.checkTemplateBodies) {
        this.opQueue.push(new TcbTemplateBodyOp(this.tcb, this, node));
      } else if (this.tcb.env.config.alwaysCheckSchemaInTemplateBodies) {
        this.appendDeepSchemaChecks(node.children);
      }
      this.checkAndAppendReferencesOfNode(node);
    } else if (node instanceof Component$1) {
      this.appendComponentNode(node);
    } else if (node instanceof DeferredBlock) {
      this.appendDeferredBlock(node);
    } else if (node instanceof IfBlock) {
      this.opQueue.push(new TcbIfBlockOp(this.tcb, this, node));
    } else if (node instanceof SwitchBlock) {
      this.opQueue.push(new TcbSwitchOp(this.tcb, this, node));
    } else if (node instanceof ForLoopBlock) {
      this.opQueue.push(new TcbForOfOp(this.tcb, this, node));
      node.empty && this.tcb.env.config.checkControlFlowBodies && this.appendChildren(node.empty);
    } else if (node instanceof BoundText) {
      this.opQueue.push(new TcbExpressionOp(this.tcb, this, node.value));
    } else if (node instanceof Icu$1) {
      this.appendIcuExpressions(node);
    } else if (node instanceof Content) {
      this.appendChildren(node);
    } else if (node instanceof LetDeclaration$1) {
      const opIndex = this.opQueue.push(new TcbLetDeclarationOp(this.tcb, this, node)) - 1;
      if (this.isLocal(node)) {
        this.tcb.oobRecorder.conflictingDeclaration(this.tcb.id, node);
      } else {
        this.letDeclOpMap.set(node.name, {
          opIndex,
          node
        });
      }
    } else if (node instanceof HostElement) {
      this.appendHostElement(node);
    }
  }
  appendChildren(node) {
    for (const child of node.children) {
      this.appendNode(child);
    }
  }
  checkAndAppendReferencesOfNode(node) {
    for (const ref of node.references) {
      const target = this.tcb.boundTarget.getReferenceTarget(ref);
      let ctxIndex;
      if (target === null) {
        this.tcb.oobRecorder.missingReferenceTarget(this.tcb.id, ref);
        ctxIndex = this.opQueue.push(new TcbInvalidReferenceOp(this.tcb, this)) - 1;
      } else if (target instanceof Template || target instanceof Element$1) {
        ctxIndex = this.opQueue.push(new TcbReferenceOp(this.tcb, this, ref, node, target)) - 1;
      } else {
        ctxIndex = this.opQueue.push(new TcbReferenceOp(this.tcb, this, ref, node, target.directive)) - 1;
      }
      this.referenceOpMap.set(ref, ctxIndex);
    }
  }
  appendDirectivesAndInputsOfElementLikeNode(node) {
    const claimedInputs = new Set();
    const directives = this.tcb.boundTarget.getDirectivesOfNode(node);
    if (directives === null || directives.length === 0) {
      if (node instanceof Element$1) {
        this.opQueue.push(new TcbUnclaimedInputsOp(this.tcb, this, node.inputs, node, claimedInputs));
        const isForeign = this.tcb.boundTarget.getForeignComponent(node) !== null;
        if (!isForeign) {
          this.opQueue.push(new TcbDomSchemaCheckerOp(this.tcb, node, true, claimedInputs));
        }
      }
      return;
    }
    this.reportConflictingBindings(node);
    if (node instanceof Element$1) {
      const isDeferred = this.tcb.boundTarget.isDeferred(node);
      if (!isDeferred && directives.some(dirMeta => dirMeta.isExplicitlyDeferred)) {
        this.tcb.oobRecorder.deferredComponentUsedEagerly(this.tcb.id, node);
      }
    }
    if (node instanceof Element$1) {
      const matchedComponents = directives.filter(dir => dir.isComponent);
      if (matchedComponents.length > 1) {
        this.tcb.oobRecorder.multipleMatchingComponents(this.tcb.id, node, matchedComponents.map(dir => dir.name));
      }
    }
    const dirMap = new Map();
    for (let i = 0; i < directives.length; i++) {
      const dir = directives[i];
      this.appendDirectiveInputs(dir, node, dirMap, directives, i);
    }
    this.directiveOpMap.set(node, dirMap);
    if (node instanceof Element$1) {
      for (const dir of directives) {
        for (const propertyName of dir.inputs.propertyNames) {
          claimedInputs.add(propertyName);
        }
      }
      this.opQueue.push(new TcbUnclaimedInputsOp(this.tcb, this, node.inputs, node, claimedInputs));
      const checkElement = directives.length === 0;
      this.opQueue.push(new TcbDomSchemaCheckerOp(this.tcb, node, checkElement, claimedInputs));
    }
  }
  appendOutputsOfElementLikeNode(node, bindings, events) {
    const claimedOutputs = new Set();
    const directives = this.tcb.boundTarget.getDirectivesOfNode(node);
    if (directives === null || directives.length === 0) {
      if (node instanceof Element$1) {
        this.opQueue.push(new TcbUnclaimedOutputsOp(this.tcb, this, node, events, bindings, claimedOutputs));
      }
      return;
    }
    for (const dir of directives) {
      this.opQueue.push(new TcbDirectiveOutputsOp(this.tcb, this, node, bindings, events, dir));
    }
    if (node instanceof Element$1 || node instanceof HostElement) {
      for (const dir of directives) {
        for (const outputProperty of dir.outputs.propertyNames) {
          claimedOutputs.add(outputProperty);
        }
      }
      this.opQueue.push(new TcbUnclaimedOutputsOp(this.tcb, this, node, events, bindings, claimedOutputs));
    }
  }
  appendInputsOfSelectorlessNode(node) {
    const directives = this.tcb.boundTarget.getDirectivesOfNode(node);
    const claimedInputs = new Set();
    if (directives !== null && directives.length > 0) {
      const dirMap = new Map();
      for (let i = 0; i < directives.length; i++) {
        const dir = directives[i];
        this.appendDirectiveInputs(dir, node, dirMap, directives, i);
        for (const propertyName of dir.inputs.propertyNames) {
          claimedInputs.add(propertyName);
        }
      }
      this.directiveOpMap.set(node, dirMap);
    }
    this.reportConflictingBindings(node);
    if (node instanceof Directive$1) {
      for (const input of node.inputs) {
        if (!claimedInputs.has(input.name)) {
          this.tcb.oobRecorder.unclaimedDirectiveBinding(this.tcb.id, node, input);
        }
      }
      for (const attr of node.attributes) {
        if (!claimedInputs.has(attr.name)) {
          this.tcb.oobRecorder.unclaimedDirectiveBinding(this.tcb.id, node, attr);
        }
      }
    } else {
      const checkElement = node.tagName !== null;
      this.opQueue.push(new TcbUnclaimedInputsOp(this.tcb, this, node.inputs, node, claimedInputs), new TcbDomSchemaCheckerOp(this.tcb, node, checkElement, claimedInputs));
    }
  }
  appendOutputsOfSelectorlessNode(node) {
    const directives = this.tcb.boundTarget.getDirectivesOfNode(node);
    const claimedOutputs = new Set();
    if (directives !== null && directives.length > 0) {
      for (const dir of directives) {
        this.opQueue.push(new TcbDirectiveOutputsOp(this.tcb, this, node, node.inputs, node.outputs, dir));
        for (const outputProperty of dir.outputs.propertyNames) {
          claimedOutputs.add(outputProperty);
        }
      }
    }
    if (node instanceof Directive$1) {
      for (const output of node.outputs) {
        if (!claimedOutputs.has(output.name)) {
          this.tcb.oobRecorder.unclaimedDirectiveBinding(this.tcb.id, node, output);
        }
      }
    } else {
      this.opQueue.push(new TcbUnclaimedOutputsOp(this.tcb, this, node, node.outputs, node.inputs, claimedOutputs));
    }
  }
  appendDirectiveInputs(dir, node, dirMap, allDirectiveMatches, directiveIndex) {
    const nodeIsFormControl = isFormControl(allDirectiveMatches);
    const customFormControlType = nodeIsFormControl ? getCustomFieldDirectiveType(dir) : null;
    const directiveOp = this.getDirectiveOp(dir, node, customFormControlType, directiveIndex);
    const dirIndex = this.opQueue.push(directiveOp) - 1;
    dirMap.set(dir, dirIndex);
    if (isNativeField(dir, node, allDirectiveMatches)) {
      const inputType = node.name === 'input' && node.attributes.find(attr => attr.name === 'type')?.value || null;
      this.opQueue.push(inputType === 'radio' ? new TcbNativeRadioButtonFieldOp(this.tcb, this, node) : new TcbNativeFieldOp(this.tcb, this, node, inputType));
    }
    this.opQueue.push(new TcbDirectiveInputsOp(this.tcb, this, node, dir, nodeIsFormControl, customFormControlType));
  }
  getDirectiveOp(dir, node, customFieldType, directiveIndex) {
    if (!dir.isGeneric) {
      return new TcbNonGenericDirectiveTypeOp(this.tcb, this, node, dir, directiveIndex);
    } else if (!dir.requiresInlineTypeCtor || this.tcb.env.config.useInlineTypeConstructors) {
      return new TcbDirectiveCtorOp(this.tcb, this, node, dir, customFieldType, directiveIndex);
    }
    return new TcbGenericDirectiveTypeWithAnyParamsOp(this.tcb, this, node, dir, directiveIndex);
  }
  appendSelectorlessDirectives(node) {
    for (const directive of node.directives) {
      if (!this.tcb.boundTarget.referencedDirectiveExists(directive.name)) {
        this.tcb.oobRecorder.missingNamedTemplateDependency(this.tcb.id, directive);
        continue;
      }
      const directives = this.tcb.boundTarget.getDirectivesOfNode(directive);
      if (directives === null || directives.length === 0 || directives.some(dir => dir.isComponent || !dir.isStandalone)) {
        this.tcb.oobRecorder.incorrectTemplateDependencyType(this.tcb.id, directive);
        continue;
      }
      this.appendInputsOfSelectorlessNode(directive);
      this.appendOutputsOfSelectorlessNode(directive);
      this.checkAndAppendReferencesOfNode(directive);
    }
  }
  appendDeepSchemaChecks(nodes) {
    for (const node of nodes) {
      if (!(node instanceof Element$1 || node instanceof Template)) {
        continue;
      }
      if (node instanceof Element$1) {
        const claimedInputs = new Set();
        let directives = this.tcb.boundTarget.getDirectivesOfNode(node);
        for (const dirNode of node.directives) {
          const directiveResults = this.tcb.boundTarget.getDirectivesOfNode(dirNode);
          if (directiveResults !== null && directiveResults.length > 0) {
            directives ??= [];
            directives.push(...directiveResults);
          }
        }
        let hasDirectives;
        if (directives === null || directives.length === 0) {
          hasDirectives = false;
        } else {
          hasDirectives = true;
          for (const dir of directives) {
            for (const propertyName of dir.inputs.propertyNames) {
              claimedInputs.add(propertyName);
            }
          }
        }
        const isForeign = this.tcb.boundTarget.getForeignComponent(node) !== null;
        if (!isForeign) {
          this.opQueue.push(new TcbDomSchemaCheckerOp(this.tcb, node, !hasDirectives, claimedInputs));
        }
      }
      this.appendDeepSchemaChecks(node.children);
    }
  }
  appendIcuExpressions(node) {
    for (const variable of Object.values(node.vars)) {
      this.opQueue.push(new TcbExpressionOp(this.tcb, this, variable.value));
    }
    for (const placeholder of Object.values(node.placeholders)) {
      if (placeholder instanceof BoundText) {
        this.opQueue.push(new TcbExpressionOp(this.tcb, this, placeholder.value));
      }
    }
  }
  appendContentProjectionCheckOp(root) {
    const meta = this.tcb.boundTarget.getDirectivesOfNode(root)?.find(meta => meta.isComponent) || null;
    if (meta !== null && meta.ngContentSelectors !== null && meta.ngContentSelectors.length > 0) {
      const selectors = meta.ngContentSelectors;
      if (selectors.length > 1 || selectors.length === 1 && selectors[0] !== '*') {
        this.opQueue.push(new TcbControlFlowContentProjectionOp(this.tcb, root, selectors, meta.name));
      }
    }
  }
  appendComponentNode(node) {
    if (!this.tcb.boundTarget.referencedDirectiveExists(node.componentName)) {
      this.tcb.oobRecorder.missingNamedTemplateDependency(this.tcb.id, node);
      return;
    }
    const directives = this.tcb.boundTarget.getDirectivesOfNode(node);
    if (directives === null || directives.length === 0 || directives.every(dir => !dir.isComponent || !dir.isStandalone)) {
      this.tcb.oobRecorder.incorrectTemplateDependencyType(this.tcb.id, node);
      return;
    }
    const opIndex = this.opQueue.push(new TcbComponentNodeOp(this.tcb, this, node)) - 1;
    this.componentNodeOpMap.set(node, opIndex);
    if (this.tcb.env.config.controlFlowPreventingContentProjection !== 'suppress') {
      this.appendContentProjectionCheckOp(node);
    }
    this.appendInputsOfSelectorlessNode(node);
    this.appendOutputsOfSelectorlessNode(node);
    this.appendSelectorlessDirectives(node);
    this.appendChildren(node);
    this.checkAndAppendReferencesOfNode(node);
  }
  appendDeferredBlock(block) {
    this.appendDeferredTriggers(block, block.triggers);
    this.appendDeferredTriggers(block, block.prefetchTriggers);
    if (block.hydrateTriggers.when) {
      this.opQueue.push(new TcbConditionOp(this.tcb, this, block.hydrateTriggers.when.value));
    }
    this.appendChildren(block);
    if (block.placeholder !== null) {
      this.appendChildren(block.placeholder);
    }
    if (block.loading !== null) {
      this.appendChildren(block.loading);
    }
    if (block.error !== null) {
      this.appendChildren(block.error);
    }
  }
  appendDeferredTriggers(block, triggers) {
    if (triggers.when !== undefined) {
      this.opQueue.push(new TcbConditionOp(this.tcb, this, triggers.when.value));
    }
    if (triggers.viewport !== undefined && triggers.viewport.options !== null) {
      this.opQueue.push(new TcbIntersectionObserverOp(this.tcb, this, triggers.viewport.options));
    }
    if (triggers.hover !== undefined) {
      this.validateReferenceBasedDeferredTrigger(block, triggers.hover);
    }
    if (triggers.interaction !== undefined) {
      this.validateReferenceBasedDeferredTrigger(block, triggers.interaction);
    }
    if (triggers.viewport !== undefined) {
      this.validateReferenceBasedDeferredTrigger(block, triggers.viewport);
    }
  }
  appendHostElement(node) {
    const opIndex = this.opQueue.push(new TcbHostElementOp(this.tcb, this, node)) - 1;
    const directives = this.tcb.boundTarget.getDirectivesOfNode(node);
    if (directives !== null && directives.length > 0) {
      const directiveOpMap = new Map();
      for (const directive of directives) {
        const directiveOp = this.getDirectiveOp(directive, node, null);
        directiveOpMap.set(directive, this.opQueue.push(directiveOp) - 1);
      }
      this.directiveOpMap.set(node, directiveOpMap);
    }
    this.hostElementOpMap.set(node, opIndex);
    this.opQueue.push(new TcbUnclaimedInputsOp(this.tcb, this, node.bindings, node, null), new TcbDomSchemaCheckerOp(this.tcb, node, false, null));
    this.appendOutputsOfElementLikeNode(node, null, node.listeners);
  }
  validateReferenceBasedDeferredTrigger(block, trigger) {
    if (trigger.reference === null) {
      if (block.placeholder === null) {
        this.tcb.oobRecorder.deferImplicitTriggerMissingPlaceholder(this.tcb.id, trigger);
        return;
      }
      let rootNode = null;
      for (const child of block.placeholder.children) {
        if (!this.tcb.hostPreserveWhitespaces && child instanceof Text$3 && child.value.trim().length === 0) {
          continue;
        }
        if (rootNode === null) {
          rootNode = child;
        } else {
          rootNode = null;
          break;
        }
      }
      if (rootNode === null || !(rootNode instanceof Element$1)) {
        this.tcb.oobRecorder.deferImplicitTriggerInvalidPlaceholder(this.tcb.id, trigger);
      }
      return;
    }
    if (this.tcb.boundTarget.getDeferredTriggerTarget(block, trigger) === null) {
      this.tcb.oobRecorder.inaccessibleDeferredTriggerElement(this.tcb.id, trigger);
    }
  }
  static checkConflictingLet(scope, node) {
    if (scope.letDeclOpMap.has(node.name)) {
      scope.tcb.oobRecorder.conflictingDeclaration(scope.tcb.id, scope.letDeclOpMap.get(node.name).node);
    }
  }
  reportConflictingBindings(node) {
    const conflictingBindings = this.tcb.boundTarget.getConflictingHostDirectiveBindings(node);
    if (conflictingBindings !== null) {
      for (const binding of conflictingBindings) {
        this.tcb.oobRecorder.conflictingHostDirectiveBinding(this.tcb.id, node, binding.directive.name, binding.kind, binding.classPropertyName, Array.from(binding.conflictingAliases));
      }
    }
  }
}

function generateTypeCheckBlock(env, component, name, meta, domSchemaChecker, oobRecorder) {
  const tcb = new Context(env, domSchemaChecker, oobRecorder, meta.id, meta.boundTarget, meta.pipes, meta.schemas, meta.isStandalone, meta.preserveWhitespaces);
  const ctxRawType = env.referenceTcbValue(component.ref);
  const {
    typeParameters,
    typeArguments
  } = component;
  const typeParamsStr = !env.config.useContextGenericType || typeParameters === null || typeParameters.length === 0 ? '' : `<${typeParameters.map(p => p.representation).join(', ')}>`;
  const typeArgsStr = typeArguments === null || typeArguments.length === 0 ? '' : `<${typeArguments.join(', ')}>`;
  const thisParamStr = `this: ${ctxRawType.print()}${typeArgsStr}`;
  const statements = [];
  if (tcb.boundTarget.target.template !== undefined) {
    const templateScope = Scope.forNodes(tcb, null, null, tcb.boundTarget.target.template, null);
    statements.push(renderBlockStatements(env, templateScope, 'true'));
  }
  if (tcb.boundTarget.target.host !== undefined) {
    const hostScope = Scope.forNodes(tcb, null, tcb.boundTarget.target.host.node, null, null);
    statements.push(renderBlockStatements(env, hostScope, createHostBindingsBlockGuard()));
  }
  const bodyStr = `{\n${statements.join('\n')}\n}`;
  const funcDeclStr = `function ${name}${typeParamsStr}(${thisParamStr}) ${bodyStr}`;
  return `/*${meta.id}*/\n${funcDeclStr}`;
}
function renderBlockStatements(env, scope, wrapperExpression) {
  const scopeStatements = scope.render();
  const statements = getStatementsBlock([...env.getPreludeStatements(), ...scopeStatements]);
  return `if (${wrapperExpression}) {\n${statements}\n}`;
}

publishFacade(_global);

export { AST, ASTWithName, ASTWithSource, AbsoluteSourceSpan, AbstractEmitterVisitor, ArrayType, ArrowFunction, ArrowFunctionExpr$1 as ArrowFunctionExpr, ArrowFunctionIdentifierParameter, Attribute, Binary, BinaryOperator, BinaryOperatorExpr, BindingPipe, BindingPipeType, BindingType, Block, BlockParameter, BoundElementProperty, BuiltinType, BuiltinTypeName, CUSTOM_ELEMENTS_SCHEMA, Call, Chain, ChangeDetectionStrategy, ClassPropertyMapping, CombinedRecursiveAstVisitor, CommaExpr, Comment, CommentTriviaType, CompilerConfig, CompilerFacadeImpl, Component, Conditional, ConditionalExpr, ConstantPool, CssSelector, DYNAMIC_TYPE, DeclareFunctionStmt, DeclareVarStmt, Directive, DomElementSchemaRegistry, DynamicImportExpr, EOF, Element, ElementSchemaRegistry, EmitterVisitorContext, EmptyExpr$1 as EmptyExpr, Expansion, ExpansionCase, Expression, ExpressionBinding, ExpressionIdentifier, ExpressionStatement, ExpressionType, ExternalExpr, ExternalReference, FactoryTarget, FunctionExpr, HOST_BINDING_GUARD_COMMENT_TEXT, HtmlParser, HtmlTagDefinition, I18NHtmlParser, IfStmt, ImplicitReceiver, InstantiateExpr, Interpolation$1 as Interpolation, InvokeFunctionExpr, JSDocComment, JitEvaluator, KeyedRead, LEGACY_OPTIONAL_CHAINING_DEFAULT, LeadingComment, LetDeclaration, Lexer, LiteralArray, LiteralArrayExpr, LiteralExpr, LiteralMap, LiteralMapExpr, LiteralMapPropertyAssignment, LiteralMapSpreadAssignment, LiteralPrimitive, LocalizedString, MapType, MatchSource, MessageBundle, NONE_TYPE, NO_ERRORS_SCHEMA, NodeWithI18n, NonNullAssert, NotExpr, OutOfBandDiagnosticCategory, ParenthesizedExpr, ParenthesizedExpression, ParseError, ParseErrorLevel, ParseLocation, ParseSourceFile, ParseSourceSpan, ParseSpan, ParseTreeResult, ParsedEvent, ParsedEventType, ParsedProperty, ParsedPropertyType, ParsedVariable, Parser, PrefixNot, PropertyRead, Identifiers as R3Identifiers, R3NgModuleMetadataKind, R3SelectorScopeMode, R3TargetBinder, R3TemplateDependencyKind, ReadKeyExpr, ReadPropExpr, ReadVarExpr, RecursiveAstVisitor, RecursiveVisitor, RegularExpressionLiteral, RegularExpressionLiteralExpr, ResourceLoader, ReturnStatement, SCHEMA, STRING_TYPE, SafeCall, SafeKeyedRead, SafePropertyRead, SelectorContext, SelectorListContext, SelectorMatcher, SelectorlessMatcher, Serializer, SplitInterpolation, SpreadElement, SpreadElementExpr, StartTagComment, Statement, StmtModifier, StringToken, StringTokenKind, TagContentType, TaggedTemplateLiteral, TaggedTemplateLiteralExpr, TcbExpr, TcbGenericContextBehavior, TemplateBindingParseResult, TemplateLiteral, TemplateLiteralElement, TemplateLiteralElementExpr, TemplateLiteralExpr, Text, ThisReceiver, BlockNode as TmplAstBlockNode, BoundAttribute as TmplAstBoundAttribute, BoundDeferredTrigger as TmplAstBoundDeferredTrigger, BoundEvent as TmplAstBoundEvent, BoundText as TmplAstBoundText, Component$1 as TmplAstComponent, Content as TmplAstContent, ContentBlock as TmplAstContentBlock, DeferredBlock as TmplAstDeferredBlock, DeferredBlockError as TmplAstDeferredBlockError, DeferredBlockLoading as TmplAstDeferredBlockLoading, DeferredBlockPlaceholder as TmplAstDeferredBlockPlaceholder, DeferredTrigger as TmplAstDeferredTrigger, Directive$1 as TmplAstDirective, Element$1 as TmplAstElement, ForLoopBlock as TmplAstForLoopBlock, ForLoopBlockEmpty as TmplAstForLoopBlockEmpty, HostElement as TmplAstHostElement, HoverDeferredTrigger as TmplAstHoverDeferredTrigger, Icu$1 as TmplAstIcu, IdleDeferredTrigger as TmplAstIdleDeferredTrigger, IfBlock as TmplAstIfBlock, IfBlockBranch as TmplAstIfBlockBranch, ImmediateDeferredTrigger as TmplAstImmediateDeferredTrigger, InteractionDeferredTrigger as TmplAstInteractionDeferredTrigger, LetDeclaration$1 as TmplAstLetDeclaration, NeverDeferredTrigger as TmplAstNeverDeferredTrigger, RecursiveVisitor$1 as TmplAstRecursiveVisitor, Reference as TmplAstReference, SwitchBlock as TmplAstSwitchBlock, SwitchBlockCase as TmplAstSwitchBlockCase, SwitchBlockCaseGroup as TmplAstSwitchBlockCaseGroup, SwitchExhaustiveCheck as TmplAstSwitchExhaustiveCheck, Template as TmplAstTemplate, Text$3 as TmplAstText, TextAttribute as TmplAstTextAttribute, TimerDeferredTrigger as TmplAstTimerDeferredTrigger, UnknownBlock as TmplAstUnknownBlock, Variable as TmplAstVariable, ViewportDeferredTrigger as TmplAstViewportDeferredTrigger, Token, TokenType, TransplantedType, TreeError, Type, TypeModifier, TypeofExpr, TypeofExpression, Unary, UnaryOperator, UnaryOperatorExpr, VERSION, VariableBinding, Version, ViewEncapsulation$1 as ViewEncapsulation, VoidExpr, VoidExpression, WrappedNodeExpr, Xliff, Xliff2, Xmb, XmlParser, Xtb, _ATTR_TO_PROP, compileClassDebugInfo, compileClassMetadata, compileComponentClassMetadata, compileComponentDeclareClassMetadata, compileComponentFromMetadata, compileDeclareClassMetadata, compileDeclareComponentFromMetadata, compileDeclareDirectiveFromMetadata, compileDeclareFactoryFunction, compileDeclareInjectableFromMetadata, compileDeclareInjectorFromMetadata, compileDeclareNgModuleFromMetadata, compileDeclarePipeFromMetadata, compileDeclareServiceFromMetadata, compileDeferResolverFunction, compileDirectiveFromMetadata, compileFactoryFunction, compileHmrInitializer, compileHmrUpdateCallback, compileInjectable, compileInjector, compileNgModule, compileOpaqueAsyncClassMetadata, compilePipeFromMetadata, compileService, computeMsgId, core, createCssSelectorFromNode, createHostBindingsBlockGuard, createHostElement, createInjectableType, createMayBeForwardRefExpression, delegateToFactory, devOnlyGuardedExpression, emitDistinctChangesOnlyDefaultValue, encapsulateStyle, escapeRegExp, findMatchingDirectivesAndPipes, generateTypeCheckBlock, getHtmlTagDefinition, getNsPrefix, getSafePropertyAccessString, identifierName, isNgContainer, isNgContent, isNgTemplate, isUnsafeObjectKey, jsDocComment, leadingComment, literal, literalMap, makeBindingParser, mergeNsAndName, output_ast as outputAst, parseHostBindings, parseTemplate, preserveWhitespacesDefault, publishFacade, r3JitTypeSourceSpan, sanitizeIdentifier, splitNsName, visitAll$1 as tmplAstVisitAll, verifyHostBindings, visitAll };
//# sourceMappingURL=compiler.mjs.map