"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"); var _location = require("../../parser/location"); function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; } function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } const HEX_NUMBER = /^[\da-fA-F]+$/; const DECIMAL_NUMBER = /^\d+$/; const JsxErrors = Object.freeze({ AttributeIsEmpty: "JSX attributes must only be assigned a non-empty expression", MissingClosingTagFragment: "Expected corresponding JSX closing tag for <>", MissingClosingTagElement: "Expected corresponding JSX closing tag for <%0>", UnsupportedJsxValue: "JSX value should be either an expression or a quoted JSX text", UnterminatedJsxContent: "Unterminated JSX contents", UnwrappedAdjacentJSXElements: "Adjacent JSX elements must be wrapped in an enclosing tag. Did you want a JSX fragment <>...?" }); _context.types.j_oTag = new _context.TokContext("...", 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.length) { throw this.raise(this.state.start, JsxErrors.UnterminatedJsxContent); } 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 super.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.length) { throw this.raise(this.state.start, _location.Errors.UnterminatedString); } 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.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(); if (node.type === "JSXNamespacedName") { return node; } 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.startNode(); this.next(); node = this.jsxParseExpressionContainer(node); if (node.expression.type === "JSXEmptyExpression") { this.raise(node.start, JsxErrors.AttributeIsEmpty); } return node; case _types.types.jsxTagStart: case _types.types.string: return this.parseExprAtom(); default: throw this.raise(this.state.start, JsxErrors.UnsupportedJsxValue); } } jsxParseEmptyExpression() { const node = this.startNodeAt(this.state.lastTokEnd, this.state.lastTokEndLoc); return this.finishNodeAt(node, "JSXEmptyExpression", this.state.start, this.state.startLoc); } jsxParseSpreadChild(node) { this.next(); node.expression = this.parseExpression(); this.expect(_types.types.braceR); return this.finishNode(node, "JSXSpreadChild"); } jsxParseExpressionContainer(node) { 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: { const node = this.startNode(); this.next(); if (this.match(_types.types.ellipsis)) { children.push(this.jsxParseSpreadChild(node)); } else { children.push(this.jsxParseExpressionContainer(node)); } break; } default: throw this.unexpected(); } } if (isFragment(openingElement) && !isFragment(closingElement)) { this.raise(closingElement.start, JsxErrors.MissingClosingTagFragment); } else if (!isFragment(openingElement) && isFragment(closingElement)) { this.raise(closingElement.start, JsxErrors.MissingClosingTagElement, getQualifiedJSXName(openingElement.name)); } else if (!isFragment(openingElement) && !isFragment(closingElement)) { if (getQualifiedJSXName(closingElement.name) !== getQualifiedJSXName(openingElement.name)) { this.raise(closingElement.start, JsxErrors.MissingClosingTagElement, getQualifiedJSXName(openingElement.name)); } } } if (isFragment(openingElement)) { node.openingFragment = openingElement; node.closingFragment = closingElement; } else { node.openingElement = openingElement; node.closingElement = closingElement; } node.children = children; if (this.isRelational("<")) { throw this.raise(this.state.start, JsxErrors.UnwrappedAdjacentJSXElements); } 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(refExpressionErrors) { 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.input.charCodeAt(this.state.pos) !== 33) { this.finishToken(_types.types.jsxTagStart); return this.jsxParseElement(); } else { return super.parseExprAtom(refExpressionErrors); } } getTokenFromCode(code) { if (this.state.inPropertyName) return super.getTokenFromCode(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.input.charCodeAt(this.state.pos + 1) !== 33) { ++this.state.pos; return this.finishToken(_types.types.jsxTagStart); } return super.getTokenFromCode(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;