summaryrefslogtreecommitdiff
path: root/node_modules/sucrase/dist/esm/parser/plugins/jsx
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/sucrase/dist/esm/parser/plugins/jsx')
-rw-r--r--node_modules/sucrase/dist/esm/parser/plugins/jsx/index.js367
-rw-r--r--node_modules/sucrase/dist/esm/parser/plugins/jsx/xhtml.js256
2 files changed, 623 insertions, 0 deletions
diff --git a/node_modules/sucrase/dist/esm/parser/plugins/jsx/index.js b/node_modules/sucrase/dist/esm/parser/plugins/jsx/index.js
new file mode 100644
index 0000000..83f3983
--- /dev/null
+++ b/node_modules/sucrase/dist/esm/parser/plugins/jsx/index.js
@@ -0,0 +1,367 @@
+import {
+ eat,
+ finishToken,
+ getTokenFromCode,
+ IdentifierRole,
+ JSXRole,
+ match,
+ next,
+ skipSpace,
+ Token,
+} from "../../tokenizer/index";
+import {TokenType as tt} from "../../tokenizer/types";
+import {input, isTypeScriptEnabled, state} from "../../traverser/base";
+import {parseExpression, parseMaybeAssign} from "../../traverser/expression";
+import {expect, unexpected} from "../../traverser/util";
+import {charCodes} from "../../util/charcodes";
+import {IS_IDENTIFIER_CHAR, IS_IDENTIFIER_START} from "../../util/identifier";
+import {tsTryParseJSXTypeArgument} from "../typescript";
+
+/**
+ * Read token with JSX contents.
+ *
+ * In addition to detecting jsxTagStart and also regular tokens that might be
+ * part of an expression, this code detects the start and end of text ranges
+ * within JSX children. In order to properly count the number of children, we
+ * distinguish jsxText from jsxEmptyText, which is a text range that simplifies
+ * to the empty string after JSX whitespace trimming.
+ *
+ * It turns out that a JSX text range will simplify to the empty string if and
+ * only if both of these conditions hold:
+ * - The range consists entirely of whitespace characters (only counting space,
+ * tab, \r, and \n).
+ * - The range has at least one newline.
+ * This can be proven by analyzing any implementation of whitespace trimming,
+ * e.g. formatJSXTextLiteral in Sucrase or cleanJSXElementLiteralChild in Babel.
+ */
+function jsxReadToken() {
+ let sawNewline = false;
+ let sawNonWhitespace = false;
+ while (true) {
+ if (state.pos >= input.length) {
+ unexpected("Unterminated JSX contents");
+ return;
+ }
+
+ const ch = input.charCodeAt(state.pos);
+ if (ch === charCodes.lessThan || ch === charCodes.leftCurlyBrace) {
+ if (state.pos === state.start) {
+ if (ch === charCodes.lessThan) {
+ state.pos++;
+ finishToken(tt.jsxTagStart);
+ return;
+ }
+ getTokenFromCode(ch);
+ return;
+ }
+ if (sawNewline && !sawNonWhitespace) {
+ finishToken(tt.jsxEmptyText);
+ } else {
+ finishToken(tt.jsxText);
+ }
+ return;
+ }
+
+ // This is part of JSX text.
+ if (ch === charCodes.lineFeed) {
+ sawNewline = true;
+ } else if (ch !== charCodes.space && ch !== charCodes.carriageReturn && ch !== charCodes.tab) {
+ sawNonWhitespace = true;
+ }
+ state.pos++;
+ }
+}
+
+function jsxReadString(quote) {
+ state.pos++;
+ for (;;) {
+ if (state.pos >= input.length) {
+ unexpected("Unterminated string constant");
+ return;
+ }
+
+ const ch = input.charCodeAt(state.pos);
+ if (ch === quote) {
+ state.pos++;
+ break;
+ }
+ state.pos++;
+ }
+ finishToken(tt.string);
+}
+
+// Read a JSX identifier (valid tag or attribute name).
+//
+// Optimized version since JSX identifiers can't contain
+// escape characters and so can be read as single slice.
+// Also assumes that first character was already checked
+// by isIdentifierStart in readToken.
+
+function jsxReadWord() {
+ let ch;
+ do {
+ if (state.pos > input.length) {
+ unexpected("Unexpectedly reached the end of input.");
+ return;
+ }
+ ch = input.charCodeAt(++state.pos);
+ } while (IS_IDENTIFIER_CHAR[ch] || ch === charCodes.dash);
+ finishToken(tt.jsxName);
+}
+
+// Parse next token as JSX identifier
+function jsxParseIdentifier() {
+ nextJSXTagToken();
+}
+
+// Parse namespaced identifier.
+function jsxParseNamespacedName(identifierRole) {
+ jsxParseIdentifier();
+ if (!eat(tt.colon)) {
+ // Plain identifier, so this is an access.
+ state.tokens[state.tokens.length - 1].identifierRole = identifierRole;
+ return;
+ }
+ // Process the second half of the namespaced name.
+ jsxParseIdentifier();
+}
+
+// Parses element name in any form - namespaced, member
+// or single identifier.
+function jsxParseElementName() {
+ const firstTokenIndex = state.tokens.length;
+ jsxParseNamespacedName(IdentifierRole.Access);
+ let hadDot = false;
+ while (match(tt.dot)) {
+ hadDot = true;
+ nextJSXTagToken();
+ jsxParseIdentifier();
+ }
+ // For tags like <div> with a lowercase letter and no dots, the name is
+ // actually *not* an identifier access, since it's referring to a built-in
+ // tag name. Remove the identifier role in this case so that it's not
+ // accidentally transformed by the imports transform when preserving JSX.
+ if (!hadDot) {
+ const firstToken = state.tokens[firstTokenIndex];
+ const firstChar = input.charCodeAt(firstToken.start);
+ if (firstChar >= charCodes.lowercaseA && firstChar <= charCodes.lowercaseZ) {
+ firstToken.identifierRole = null;
+ }
+ }
+}
+
+// Parses any type of JSX attribute value.
+function jsxParseAttributeValue() {
+ switch (state.type) {
+ case tt.braceL:
+ next();
+ parseExpression();
+ nextJSXTagToken();
+ return;
+
+ case tt.jsxTagStart:
+ jsxParseElement();
+ nextJSXTagToken();
+ return;
+
+ case tt.string:
+ nextJSXTagToken();
+ return;
+
+ default:
+ unexpected("JSX value should be either an expression or a quoted JSX text");
+ }
+}
+
+// Parse JSX spread child, after already processing the {
+// Does not parse the closing }
+function jsxParseSpreadChild() {
+ expect(tt.ellipsis);
+ parseExpression();
+}
+
+// Parses JSX opening tag starting after "<".
+// Returns true if the tag was self-closing.
+// Does not parse the last token.
+function jsxParseOpeningElement(initialTokenIndex) {
+ if (match(tt.jsxTagEnd)) {
+ // This is an open-fragment.
+ return false;
+ }
+ jsxParseElementName();
+ if (isTypeScriptEnabled) {
+ tsTryParseJSXTypeArgument();
+ }
+ let hasSeenPropSpread = false;
+ while (!match(tt.slash) && !match(tt.jsxTagEnd) && !state.error) {
+ if (eat(tt.braceL)) {
+ hasSeenPropSpread = true;
+ expect(tt.ellipsis);
+ parseMaybeAssign();
+ // }
+ nextJSXTagToken();
+ continue;
+ }
+ if (
+ hasSeenPropSpread &&
+ state.end - state.start === 3 &&
+ input.charCodeAt(state.start) === charCodes.lowercaseK &&
+ input.charCodeAt(state.start + 1) === charCodes.lowercaseE &&
+ input.charCodeAt(state.start + 2) === charCodes.lowercaseY
+ ) {
+ state.tokens[initialTokenIndex].jsxRole = JSXRole.KeyAfterPropSpread;
+ }
+ jsxParseNamespacedName(IdentifierRole.ObjectKey);
+ if (match(tt.eq)) {
+ nextJSXTagToken();
+ jsxParseAttributeValue();
+ }
+ }
+ const isSelfClosing = match(tt.slash);
+ if (isSelfClosing) {
+ // /
+ nextJSXTagToken();
+ }
+ return isSelfClosing;
+}
+
+// Parses JSX closing tag starting after "</".
+// Does not parse the last token.
+function jsxParseClosingElement() {
+ if (match(tt.jsxTagEnd)) {
+ // Fragment syntax, so we immediately have a tag end.
+ return;
+ }
+ jsxParseElementName();
+}
+
+// Parses entire JSX element, including its opening tag
+// (starting after "<"), attributes, contents and closing tag.
+// Does not parse the last token.
+function jsxParseElementAt() {
+ const initialTokenIndex = state.tokens.length - 1;
+ state.tokens[initialTokenIndex].jsxRole = JSXRole.NoChildren;
+ let numExplicitChildren = 0;
+ const isSelfClosing = jsxParseOpeningElement(initialTokenIndex);
+ if (!isSelfClosing) {
+ nextJSXExprToken();
+ while (true) {
+ switch (state.type) {
+ case tt.jsxTagStart:
+ nextJSXTagToken();
+ if (match(tt.slash)) {
+ nextJSXTagToken();
+ jsxParseClosingElement();
+ // Key after prop spread takes precedence over number of children,
+ // since it means we switch to createElement, which doesn't care
+ // about number of children.
+ if (state.tokens[initialTokenIndex].jsxRole !== JSXRole.KeyAfterPropSpread) {
+ if (numExplicitChildren === 1) {
+ state.tokens[initialTokenIndex].jsxRole = JSXRole.OneChild;
+ } else if (numExplicitChildren > 1) {
+ state.tokens[initialTokenIndex].jsxRole = JSXRole.StaticChildren;
+ }
+ }
+ return;
+ }
+ numExplicitChildren++;
+ jsxParseElementAt();
+ nextJSXExprToken();
+ break;
+
+ case tt.jsxText:
+ numExplicitChildren++;
+ nextJSXExprToken();
+ break;
+
+ case tt.jsxEmptyText:
+ nextJSXExprToken();
+ break;
+
+ case tt.braceL:
+ next();
+ if (match(tt.ellipsis)) {
+ jsxParseSpreadChild();
+ nextJSXExprToken();
+ // Spread children are a mechanism to explicitly mark children as
+ // static, so count it as 2 children to satisfy the "more than one
+ // child" condition.
+ numExplicitChildren += 2;
+ } else {
+ // If we see {}, this is an empty pseudo-expression that doesn't
+ // count as a child.
+ if (!match(tt.braceR)) {
+ numExplicitChildren++;
+ parseExpression();
+ }
+ nextJSXExprToken();
+ }
+
+ break;
+
+ // istanbul ignore next - should never happen
+ default:
+ unexpected();
+ return;
+ }
+ }
+ }
+}
+
+// Parses entire JSX element from current position.
+// Does not parse the last token.
+export function jsxParseElement() {
+ nextJSXTagToken();
+ jsxParseElementAt();
+}
+
+// ==================================
+// Overrides
+// ==================================
+
+export function nextJSXTagToken() {
+ state.tokens.push(new Token());
+ skipSpace();
+ state.start = state.pos;
+ const code = input.charCodeAt(state.pos);
+
+ if (IS_IDENTIFIER_START[code]) {
+ jsxReadWord();
+ } else if (code === charCodes.quotationMark || code === charCodes.apostrophe) {
+ jsxReadString(code);
+ } else {
+ // The following tokens are just one character each.
+ ++state.pos;
+ switch (code) {
+ case charCodes.greaterThan:
+ finishToken(tt.jsxTagEnd);
+ break;
+ case charCodes.lessThan:
+ finishToken(tt.jsxTagStart);
+ break;
+ case charCodes.slash:
+ finishToken(tt.slash);
+ break;
+ case charCodes.equalsTo:
+ finishToken(tt.eq);
+ break;
+ case charCodes.leftCurlyBrace:
+ finishToken(tt.braceL);
+ break;
+ case charCodes.dot:
+ finishToken(tt.dot);
+ break;
+ case charCodes.colon:
+ finishToken(tt.colon);
+ break;
+ default:
+ unexpected();
+ }
+ }
+}
+
+function nextJSXExprToken() {
+ state.tokens.push(new Token());
+ state.start = state.pos;
+ jsxReadToken();
+}
diff --git a/node_modules/sucrase/dist/esm/parser/plugins/jsx/xhtml.js b/node_modules/sucrase/dist/esm/parser/plugins/jsx/xhtml.js
new file mode 100644
index 0000000..c6a0741
--- /dev/null
+++ b/node_modules/sucrase/dist/esm/parser/plugins/jsx/xhtml.js
@@ -0,0 +1,256 @@
+// Use a Map rather than object to avoid unexpected __proto__ access.
+export default new Map([
+ ["quot", "\u0022"],
+ ["amp", "&"],
+ ["apos", "\u0027"],
+ ["lt", "<"],
+ ["gt", ">"],
+ ["nbsp", "\u00A0"],
+ ["iexcl", "\u00A1"],
+ ["cent", "\u00A2"],
+ ["pound", "\u00A3"],
+ ["curren", "\u00A4"],
+ ["yen", "\u00A5"],
+ ["brvbar", "\u00A6"],
+ ["sect", "\u00A7"],
+ ["uml", "\u00A8"],
+ ["copy", "\u00A9"],
+ ["ordf", "\u00AA"],
+ ["laquo", "\u00AB"],
+ ["not", "\u00AC"],
+ ["shy", "\u00AD"],
+ ["reg", "\u00AE"],
+ ["macr", "\u00AF"],
+ ["deg", "\u00B0"],
+ ["plusmn", "\u00B1"],
+ ["sup2", "\u00B2"],
+ ["sup3", "\u00B3"],
+ ["acute", "\u00B4"],
+ ["micro", "\u00B5"],
+ ["para", "\u00B6"],
+ ["middot", "\u00B7"],
+ ["cedil", "\u00B8"],
+ ["sup1", "\u00B9"],
+ ["ordm", "\u00BA"],
+ ["raquo", "\u00BB"],
+ ["frac14", "\u00BC"],
+ ["frac12", "\u00BD"],
+ ["frac34", "\u00BE"],
+ ["iquest", "\u00BF"],
+ ["Agrave", "\u00C0"],
+ ["Aacute", "\u00C1"],
+ ["Acirc", "\u00C2"],
+ ["Atilde", "\u00C3"],
+ ["Auml", "\u00C4"],
+ ["Aring", "\u00C5"],
+ ["AElig", "\u00C6"],
+ ["Ccedil", "\u00C7"],
+ ["Egrave", "\u00C8"],
+ ["Eacute", "\u00C9"],
+ ["Ecirc", "\u00CA"],
+ ["Euml", "\u00CB"],
+ ["Igrave", "\u00CC"],
+ ["Iacute", "\u00CD"],
+ ["Icirc", "\u00CE"],
+ ["Iuml", "\u00CF"],
+ ["ETH", "\u00D0"],
+ ["Ntilde", "\u00D1"],
+ ["Ograve", "\u00D2"],
+ ["Oacute", "\u00D3"],
+ ["Ocirc", "\u00D4"],
+ ["Otilde", "\u00D5"],
+ ["Ouml", "\u00D6"],
+ ["times", "\u00D7"],
+ ["Oslash", "\u00D8"],
+ ["Ugrave", "\u00D9"],
+ ["Uacute", "\u00DA"],
+ ["Ucirc", "\u00DB"],
+ ["Uuml", "\u00DC"],
+ ["Yacute", "\u00DD"],
+ ["THORN", "\u00DE"],
+ ["szlig", "\u00DF"],
+ ["agrave", "\u00E0"],
+ ["aacute", "\u00E1"],
+ ["acirc", "\u00E2"],
+ ["atilde", "\u00E3"],
+ ["auml", "\u00E4"],
+ ["aring", "\u00E5"],
+ ["aelig", "\u00E6"],
+ ["ccedil", "\u00E7"],
+ ["egrave", "\u00E8"],
+ ["eacute", "\u00E9"],
+ ["ecirc", "\u00EA"],
+ ["euml", "\u00EB"],
+ ["igrave", "\u00EC"],
+ ["iacute", "\u00ED"],
+ ["icirc", "\u00EE"],
+ ["iuml", "\u00EF"],
+ ["eth", "\u00F0"],
+ ["ntilde", "\u00F1"],
+ ["ograve", "\u00F2"],
+ ["oacute", "\u00F3"],
+ ["ocirc", "\u00F4"],
+ ["otilde", "\u00F5"],
+ ["ouml", "\u00F6"],
+ ["divide", "\u00F7"],
+ ["oslash", "\u00F8"],
+ ["ugrave", "\u00F9"],
+ ["uacute", "\u00FA"],
+ ["ucirc", "\u00FB"],
+ ["uuml", "\u00FC"],
+ ["yacute", "\u00FD"],
+ ["thorn", "\u00FE"],
+ ["yuml", "\u00FF"],
+ ["OElig", "\u0152"],
+ ["oelig", "\u0153"],
+ ["Scaron", "\u0160"],
+ ["scaron", "\u0161"],
+ ["Yuml", "\u0178"],
+ ["fnof", "\u0192"],
+ ["circ", "\u02C6"],
+ ["tilde", "\u02DC"],
+ ["Alpha", "\u0391"],
+ ["Beta", "\u0392"],
+ ["Gamma", "\u0393"],
+ ["Delta", "\u0394"],
+ ["Epsilon", "\u0395"],
+ ["Zeta", "\u0396"],
+ ["Eta", "\u0397"],
+ ["Theta", "\u0398"],
+ ["Iota", "\u0399"],
+ ["Kappa", "\u039A"],
+ ["Lambda", "\u039B"],
+ ["Mu", "\u039C"],
+ ["Nu", "\u039D"],
+ ["Xi", "\u039E"],
+ ["Omicron", "\u039F"],
+ ["Pi", "\u03A0"],
+ ["Rho", "\u03A1"],
+ ["Sigma", "\u03A3"],
+ ["Tau", "\u03A4"],
+ ["Upsilon", "\u03A5"],
+ ["Phi", "\u03A6"],
+ ["Chi", "\u03A7"],
+ ["Psi", "\u03A8"],
+ ["Omega", "\u03A9"],
+ ["alpha", "\u03B1"],
+ ["beta", "\u03B2"],
+ ["gamma", "\u03B3"],
+ ["delta", "\u03B4"],
+ ["epsilon", "\u03B5"],
+ ["zeta", "\u03B6"],
+ ["eta", "\u03B7"],
+ ["theta", "\u03B8"],
+ ["iota", "\u03B9"],
+ ["kappa", "\u03BA"],
+ ["lambda", "\u03BB"],
+ ["mu", "\u03BC"],
+ ["nu", "\u03BD"],
+ ["xi", "\u03BE"],
+ ["omicron", "\u03BF"],
+ ["pi", "\u03C0"],
+ ["rho", "\u03C1"],
+ ["sigmaf", "\u03C2"],
+ ["sigma", "\u03C3"],
+ ["tau", "\u03C4"],
+ ["upsilon", "\u03C5"],
+ ["phi", "\u03C6"],
+ ["chi", "\u03C7"],
+ ["psi", "\u03C8"],
+ ["omega", "\u03C9"],
+ ["thetasym", "\u03D1"],
+ ["upsih", "\u03D2"],
+ ["piv", "\u03D6"],
+ ["ensp", "\u2002"],
+ ["emsp", "\u2003"],
+ ["thinsp", "\u2009"],
+ ["zwnj", "\u200C"],
+ ["zwj", "\u200D"],
+ ["lrm", "\u200E"],
+ ["rlm", "\u200F"],
+ ["ndash", "\u2013"],
+ ["mdash", "\u2014"],
+ ["lsquo", "\u2018"],
+ ["rsquo", "\u2019"],
+ ["sbquo", "\u201A"],
+ ["ldquo", "\u201C"],
+ ["rdquo", "\u201D"],
+ ["bdquo", "\u201E"],
+ ["dagger", "\u2020"],
+ ["Dagger", "\u2021"],
+ ["bull", "\u2022"],
+ ["hellip", "\u2026"],
+ ["permil", "\u2030"],
+ ["prime", "\u2032"],
+ ["Prime", "\u2033"],
+ ["lsaquo", "\u2039"],
+ ["rsaquo", "\u203A"],
+ ["oline", "\u203E"],
+ ["frasl", "\u2044"],
+ ["euro", "\u20AC"],
+ ["image", "\u2111"],
+ ["weierp", "\u2118"],
+ ["real", "\u211C"],
+ ["trade", "\u2122"],
+ ["alefsym", "\u2135"],
+ ["larr", "\u2190"],
+ ["uarr", "\u2191"],
+ ["rarr", "\u2192"],
+ ["darr", "\u2193"],
+ ["harr", "\u2194"],
+ ["crarr", "\u21B5"],
+ ["lArr", "\u21D0"],
+ ["uArr", "\u21D1"],
+ ["rArr", "\u21D2"],
+ ["dArr", "\u21D3"],
+ ["hArr", "\u21D4"],
+ ["forall", "\u2200"],
+ ["part", "\u2202"],
+ ["exist", "\u2203"],
+ ["empty", "\u2205"],
+ ["nabla", "\u2207"],
+ ["isin", "\u2208"],
+ ["notin", "\u2209"],
+ ["ni", "\u220B"],
+ ["prod", "\u220F"],
+ ["sum", "\u2211"],
+ ["minus", "\u2212"],
+ ["lowast", "\u2217"],
+ ["radic", "\u221A"],
+ ["prop", "\u221D"],
+ ["infin", "\u221E"],
+ ["ang", "\u2220"],
+ ["and", "\u2227"],
+ ["or", "\u2228"],
+ ["cap", "\u2229"],
+ ["cup", "\u222A"],
+ ["int", "\u222B"],
+ ["there4", "\u2234"],
+ ["sim", "\u223C"],
+ ["cong", "\u2245"],
+ ["asymp", "\u2248"],
+ ["ne", "\u2260"],
+ ["equiv", "\u2261"],
+ ["le", "\u2264"],
+ ["ge", "\u2265"],
+ ["sub", "\u2282"],
+ ["sup", "\u2283"],
+ ["nsub", "\u2284"],
+ ["sube", "\u2286"],
+ ["supe", "\u2287"],
+ ["oplus", "\u2295"],
+ ["otimes", "\u2297"],
+ ["perp", "\u22A5"],
+ ["sdot", "\u22C5"],
+ ["lceil", "\u2308"],
+ ["rceil", "\u2309"],
+ ["lfloor", "\u230A"],
+ ["rfloor", "\u230B"],
+ ["lang", "\u2329"],
+ ["rang", "\u232A"],
+ ["loz", "\u25CA"],
+ ["spades", "\u2660"],
+ ["clubs", "\u2663"],
+ ["hearts", "\u2665"],
+ ["diams", "\u2666"],
+]);