text: "use strict";
  
  Object.defineProperty(exports, "__esModule", {
    value: true
  });
  exports.default = void 0;
  
  var _xhtml = _interopRequireDefault(require("./xhtml"));
  
  var _types = require("../../tokenizer/types");
  
  var _context = require("../../tokenizer/context");
  
  var N = _interopRequireWildcard(require("../../types"));
  
  var _identifier = require("../../util/identifier");
  
  var _whitespace = require("../../util/whitespace");
  
  function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } }
  
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  
  const HEX_NUMBER = /^[\da-fA-F]+$/;
  const DECIMAL_NUMBER = /^\d+$/;
  _context.types.j_oTag = new _context.TokContext("<tag", false);
  _context.types.j_cTag = new _context.TokContext("</tag", false);
  _context.types.j_expr = new _context.TokContext("<tag>...</tag>", true, true);
  _types.types.jsxName = new _types.TokenType("jsxName");
  _types.types.jsxText = new _types.TokenType("jsxText", {
    beforeExpr: true
  });
  _types.types.jsxTagStart = new _types.TokenType("jsxTagStart", {
    startsExpr: true
  });
  _types.types.jsxTagEnd = new _types.TokenType("jsxTagEnd");
  
  _types.types.jsxTagStart.updateContext = function () {
    this.state.context.push(_context.types.j_expr);
    this.state.context.push(_context.types.j_oTag);
    this.state.exprAllowed = false;
  };
  
  _types.types.jsxTagEnd.updateContext = function (prevType) {
    const out = this.state.context.pop();
  
    if (out === _context.types.j_oTag && prevType === _types.types.slash || out === _context.types.j_cTag) {
      this.state.context.pop();
      this.state.exprAllowed = this.curContext() === _context.types.j_expr;
    } else {
      this.state.exprAllowed = true;
    }
  };
  
  function isFragment(object) {
    return object ? object.type === "JSXOpeningFragment" || object.type === "JSXClosingFragment" : false;
  }
  
  function getQualifiedJSXName(object) {
    if (object.type === "JSXIdentifier") {
      return object.name;
    }
  
    if (object.type === "JSXNamespacedName") {
      return object.namespace.name + ":" + object.name.name;
    }
  
    if (object.type === "JSXMemberExpression") {
      return getQualifiedJSXName(object.object) + "." + getQualifiedJSXName(object.property);
    }
  
    throw new Error("Node had unexpected type: " + object.type);
  }
  
  var _default = superClass => class extends superClass {
    jsxReadToken() {
      let out = "";
      let chunkStart = this.state.pos;
  
      for (;;) {
        if (this.state.pos >= this.input.length) {
          this.raise(this.state.start, "Unterminated JSX contents");
        }
  
        const ch = this.input.charCodeAt(this.state.pos);
  
        switch (ch) {
          case 60:
          case 123:
            if (this.state.pos === this.state.start) {
              if (ch === 60 && this.state.exprAllowed) {
                ++this.state.pos;
                return this.finishToken(_types.types.jsxTagStart);
              }
  
              return this.getTokenFromCode(ch);
            }
  
            out += this.input.slice(chunkStart, this.state.pos);
            return this.finishToken(_types.types.jsxText, out);
  
          case 38:
            out += this.input.slice(chunkStart, this.state.pos);
            out += this.jsxReadEntity();
            chunkStart = this.state.pos;
            break;
  
          default:
            if ((0, _whitespace.isNewLine)(ch)) {
              out += this.input.slice(chunkStart, this.state.pos);
              out += this.jsxReadNewLine(true);
              chunkStart = this.state.pos;
            } else {
              ++this.state.pos;
            }
  
        }
      }
    }
  
    jsxReadNewLine(normalizeCRLF) {
      const ch = this.input.charCodeAt(this.state.pos);
      let out;
      ++this.state.pos;
  
      if (ch === 13 && this.input.charCodeAt(this.state.pos) === 10) {
        ++this.state.pos;
        out = normalizeCRLF ? "\n" : "\r\n";
      } else {
        out = String.fromCharCode(ch);
      }
  
      ++this.state.curLine;
      this.state.lineStart = this.state.pos;
      return out;
    }
  
    jsxReadString(quote) {
      let out = "";
      let chunkStart = ++this.state.pos;
  
      for (;;) {
        if (this.state.pos >= this.input.length) {
          this.raise(this.state.start, "Unterminated string constant");
        }
  
        const ch = this.input.charCodeAt(this.state.pos);
        if (ch === quote) break;
  
        if (ch === 38) {
          out += this.input.slice(chunkStart, this.state.pos);
          out += this.jsxReadEntity();
          chunkStart = this.state.pos;
        } else if ((0, _whitespace.isNewLine)(ch)) {
          out += this.input.slice(chunkStart, this.state.pos);
          out += this.jsxReadNewLine(false);
          chunkStart = this.state.pos;
        } else {
          ++this.state.pos;
        }
      }
  
      out += this.input.slice(chunkStart, this.state.pos++);
      return this.finishToken(_types.types.string, out);
    }
  
    jsxReadEntity() {
      let str = "";
      let count = 0;
      let entity;
      let ch = this.input[this.state.pos];
      const startPos = ++this.state.pos;
  
      while (this.state.pos < this.input.length && count++ < 10) {
        ch = this.input[this.state.pos++];
  
        if (ch === ";") {
          if (str[0] === "#") {
            if (str[1] === "x") {
              str = str.substr(2);
  
              if (HEX_NUMBER.test(str)) {
                entity = String.fromCodePoint(parseInt(str, 16));
              }
            } else {
              str = str.substr(1);
  
              if (DECIMAL_NUMBER.test(str)) {
                entity = String.fromCodePoint(parseInt(str, 10));
              }
            }
          } else {
            entity = _xhtml.default[str];
          }
  
          break;
        }
  
        str += ch;
      }
  
      if (!entity) {
        this.state.pos = startPos;
        return "&";
      }
  
      return entity;
    }
  
    jsxReadWord() {
      let ch;
      const start = this.state.pos;
  
      do {
        ch = this.input.charCodeAt(++this.state.pos);
      } while ((0, _identifier.isIdentifierChar)(ch) || ch === 45);
  
      return this.finishToken(_types.types.jsxName, this.input.slice(start, this.state.pos));
    }
  
    jsxParseIdentifier() {
      const node = this.startNode();
  
      if (this.match(_types.types.jsxName)) {
        node.name = this.state.value;
      } else if (this.state.type.keyword) {
        node.name = this.state.type.keyword;
      } else {
        this.unexpected();
      }
  
      this.next();
      return this.finishNode(node, "JSXIdentifier");
    }
  
    jsxParseNamespacedName() {
      const startPos = this.state.start;
      const startLoc = this.state.startLoc;
      const name = this.jsxParseIdentifier();
      if (!this.eat(_types.types.colon)) return name;
      const node = this.startNodeAt(startPos, startLoc);
      node.namespace = name;
      node.name = this.jsxParseIdentifier();
      return this.finishNode(node, "JSXNamespacedName");
    }
  
    jsxParseElementName() {
      const startPos = this.state.start;
      const startLoc = this.state.startLoc;
      let node = this.jsxParseNamespacedName();
  
      while (this.eat(_types.types.dot)) {
        const newNode = this.startNodeAt(startPos, startLoc);
        newNode.object = node;
        newNode.property = this.jsxParseIdentifier();
        node = this.finishNode(newNode, "JSXMemberExpression");
      }
  
      return node;
    }
  
    jsxParseAttributeValue() {
      let node;
  
      switch (this.state.type) {
        case _types.types.braceL:
          node = this.jsxParseExpressionContainer();
  
          if (node.expression.type === "JSXEmptyExpression") {
            throw this.raise(node.start, "JSX attributes must only be assigned a non-empty expression");
          } else {
            return node;
          }
  
        case _types.types.jsxTagStart:
        case _types.types.string:
          return this.parseExprAtom();
  
        default:
          throw this.raise(this.state.start, "JSX value should be either an expression or a quoted JSX text");
      }
    }
  
    jsxParseEmptyExpression() {
      const node = this.startNodeAt(this.state.lastTokEnd, this.state.lastTokEndLoc);
      return this.finishNodeAt(node, "JSXEmptyExpression", this.state.start, this.state.startLoc);
    }
  
    jsxParseSpreadChild() {
      const node = this.startNode();
      this.expect(_types.types.braceL);
      this.expect(_types.types.ellipsis);
      node.expression = this.parseExpression();
      this.expect(_types.types.braceR);
      return this.finishNode(node, "JSXSpreadChild");
    }
  
    jsxParseExpressionContainer() {
      const node = this.startNode();
      this.next();
  
      if (this.match(_types.types.braceR)) {
        node.expression = this.jsxParseEmptyExpression();
      } else {
        node.expression = this.parseExpression();
      }
  
      this.expect(_types.types.braceR);
      return this.finishNode(node, "JSXExpressionContainer");
    }
  
    jsxParseAttribute() {
      const node = this.startNode();
  
      if (this.eat(_types.types.braceL)) {
        this.expect(_types.types.ellipsis);
        node.argument = this.parseMaybeAssign();
        this.expect(_types.types.braceR);
        return this.finishNode(node, "JSXSpreadAttribute");
      }
  
      node.name = this.jsxParseNamespacedName();
      node.value = this.eat(_types.types.eq) ? this.jsxParseAttributeValue() : null;
      return this.finishNode(node, "JSXAttribute");
    }
  
    jsxParseOpeningElementAt(startPos, startLoc) {
      const node = this.startNodeAt(startPos, startLoc);
  
      if (this.match(_types.types.jsxTagEnd)) {
        this.expect(_types.types.jsxTagEnd);
        return this.finishNode(node, "JSXOpeningFragment");
      }
  
      node.name = this.jsxParseElementName();
      return this.jsxParseOpeningElementAfterName(node);
    }
  
    jsxParseOpeningElementAfterName(node) {
      const attributes = [];
  
      while (!this.match(_types.types.slash) && !this.match(_types.types.jsxTagEnd)) {
        attributes.push(this.jsxParseAttribute());
      }
  
      node.attributes = attributes;
      node.selfClosing = this.eat(_types.types.slash);
      this.expect(_types.types.jsxTagEnd);
      return this.finishNode(node, "JSXOpeningElement");
    }
  
    jsxParseClosingElementAt(startPos, startLoc) {
      const node = this.startNodeAt(startPos, startLoc);
  
      if (this.match(_types.types.jsxTagEnd)) {
        this.expect(_types.types.jsxTagEnd);
        return this.finishNode(node, "JSXClosingFragment");
      }
  
      node.name = this.jsxParseElementName();
      this.expect(_types.types.jsxTagEnd);
      return this.finishNode(node, "JSXClosingElement");
    }
  
    jsxParseElementAt(startPos, startLoc) {
      const node = this.startNodeAt(startPos, startLoc);
      const children = [];
      const openingElement = this.jsxParseOpeningElementAt(startPos, startLoc);
      let closingElement = null;
  
      if (!openingElement.selfClosing) {
        contents: for (;;) {
          switch (this.state.type) {
            case _types.types.jsxTagStart:
              startPos = this.state.start;
              startLoc = this.state.startLoc;
              this.next();
  
              if (this.eat(_types.types.slash)) {
                closingElement = this.jsxParseClosingElementAt(startPos, startLoc);
                break contents;
              }
  
              children.push(this.jsxParseElementAt(startPos, startLoc));
              break;
  
            case _types.types.jsxText:
              children.push(this.parseExprAtom());
              break;
  
            case _types.types.braceL:
              if (this.lookahead().type === _types.types.ellipsis) {
                children.push(this.jsxParseSpreadChild());
              } else {
                children.push(this.jsxParseExpressionContainer());
              }
  
              break;
  
            default:
              throw this.unexpected();
          }
        }
  
        if (isFragment(openingElement) && !isFragment(closingElement)) {
          this.raise(closingElement.start, "Expected corresponding JSX closing tag for <>");
        } else if (!isFragment(openingElement) && isFragment(closingElement)) {
          this.raise(closingElement.start, "Expected corresponding JSX closing tag for <" + getQualifiedJSXName(openingElement.name) + ">");
        } else if (!isFragment(openingElement) && !isFragment(closingElement)) {
          if (getQualifiedJSXName(closingElement.name) !== getQualifiedJSXName(openingElement.name)) {
            this.raise(closingElement.start, "Expected corresponding JSX closing tag for <" + getQualifiedJSXName(openingElement.name) + ">");
          }
        }
      }
  
      if (isFragment(openingElement)) {
        node.openingFragment = openingElement;
        node.closingFragment = closingElement;
      } else {
        node.openingElement = openingElement;
        node.closingElement = closingElement;
      }
  
      node.children = children;
  
      if (this.match(_types.types.relational) && this.state.value === "<") {
        this.raise(this.state.start, "Adjacent JSX elements must be wrapped in an enclosing tag. " + "Did you want a JSX fragment <>...</>?");
      }
  
      return isFragment(openingElement) ? this.finishNode(node, "JSXFragment") : this.finishNode(node, "JSXElement");
    }
  
    jsxParseElement() {
      const startPos = this.state.start;
      const startLoc = this.state.startLoc;
      this.next();
      return this.jsxParseElementAt(startPos, startLoc);
    }
  
    parseExprAtom(refShortHandDefaultPos) {
      if (this.match(_types.types.jsxText)) {
        return this.parseLiteral(this.state.value, "JSXText");
      } else if (this.match(_types.types.jsxTagStart)) {
        return this.jsxParseElement();
      } else if (this.isRelational("<") && this.state.input.charCodeAt(this.state.pos) !== 33) {
        this.finishToken(_types.types.jsxTagStart);
        return this.jsxParseElement();
      } else {
        return super.parseExprAtom(refShortHandDefaultPos);
      }
    }
  
    readToken(code) {
      if (this.state.inPropertyName) return super.readToken(code);
      const context = this.curContext();
  
      if (context === _context.types.j_expr) {
        return this.jsxReadToken();
      }
  
      if (context === _context.types.j_oTag || context === _context.types.j_cTag) {
        if ((0, _identifier.isIdentifierStart)(code)) {
          return this.jsxReadWord();
        }
  
        if (code === 62) {
          ++this.state.pos;
          return this.finishToken(_types.types.jsxTagEnd);
        }
  
        if ((code === 34 || code === 39) && context === _context.types.j_oTag) {
          return this.jsxReadString(code);
        }
      }
  
      if (code === 60 && this.state.exprAllowed && this.state.input.charCodeAt(this.state.pos + 1) !== 33) {
        ++this.state.pos;
        return this.finishToken(_types.types.jsxTagStart);
      }
  
      return super.readToken(code);
    }
  
    updateContext(prevType) {
      if (this.match(_types.types.braceL)) {
        const curContext = this.curContext();
  
        if (curContext === _context.types.j_oTag) {
          this.state.context.push(_context.types.braceExpression);
        } else if (curContext === _context.types.j_expr) {
          this.state.context.push(_context.types.templateQuasi);
        } else {
          super.updateContext(prevType);
        }
  
        this.state.exprAllowed = true;
      } else if (this.match(_types.types.slash) && prevType === _types.types.jsxTagStart) {
        this.state.context.length -= 2;
        this.state.context.push(_context.types.j_cTag);
        this.state.exprAllowed = false;
      } else {
        return super.updateContext(prevType);
      }
    }
  
  };
  
  exports.default = _default;