index.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.default = void 0;
  6. var _xhtml = _interopRequireDefault(require("./xhtml"));
  7. var _types = require("../../tokenizer/types");
  8. var _context = require("../../tokenizer/context");
  9. var N = _interopRequireWildcard(require("../../types"));
  10. var _identifier = require("../../util/identifier");
  11. var _whitespace = require("../../util/whitespace");
  12. var _error = require("../../parser/error");
  13. function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; }
  14. 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; }
  15. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  16. const HEX_NUMBER = /^[\da-fA-F]+$/;
  17. const DECIMAL_NUMBER = /^\d+$/;
  18. const JsxErrors = Object.freeze({
  19. AttributeIsEmpty: "JSX attributes must only be assigned a non-empty expression",
  20. MissingClosingTagFragment: "Expected corresponding JSX closing tag for <>",
  21. MissingClosingTagElement: "Expected corresponding JSX closing tag for <%0>",
  22. UnsupportedJsxValue: "JSX value should be either an expression or a quoted JSX text",
  23. UnterminatedJsxContent: "Unterminated JSX contents",
  24. UnwrappedAdjacentJSXElements: "Adjacent JSX elements must be wrapped in an enclosing tag. Did you want a JSX fragment <>...</>?"
  25. });
  26. _context.types.j_oTag = new _context.TokContext("<tag", false);
  27. _context.types.j_cTag = new _context.TokContext("</tag", false);
  28. _context.types.j_expr = new _context.TokContext("<tag>...</tag>", true, true);
  29. _types.types.jsxName = new _types.TokenType("jsxName");
  30. _types.types.jsxText = new _types.TokenType("jsxText", {
  31. beforeExpr: true
  32. });
  33. _types.types.jsxTagStart = new _types.TokenType("jsxTagStart", {
  34. startsExpr: true
  35. });
  36. _types.types.jsxTagEnd = new _types.TokenType("jsxTagEnd");
  37. _types.types.jsxTagStart.updateContext = function () {
  38. this.state.context.push(_context.types.j_expr);
  39. this.state.context.push(_context.types.j_oTag);
  40. this.state.exprAllowed = false;
  41. };
  42. _types.types.jsxTagEnd.updateContext = function (prevType) {
  43. const out = this.state.context.pop();
  44. if (out === _context.types.j_oTag && prevType === _types.types.slash || out === _context.types.j_cTag) {
  45. this.state.context.pop();
  46. this.state.exprAllowed = this.curContext() === _context.types.j_expr;
  47. } else {
  48. this.state.exprAllowed = true;
  49. }
  50. };
  51. function isFragment(object) {
  52. return object ? object.type === "JSXOpeningFragment" || object.type === "JSXClosingFragment" : false;
  53. }
  54. function getQualifiedJSXName(object) {
  55. if (object.type === "JSXIdentifier") {
  56. return object.name;
  57. }
  58. if (object.type === "JSXNamespacedName") {
  59. return object.namespace.name + ":" + object.name.name;
  60. }
  61. if (object.type === "JSXMemberExpression") {
  62. return getQualifiedJSXName(object.object) + "." + getQualifiedJSXName(object.property);
  63. }
  64. throw new Error("Node had unexpected type: " + object.type);
  65. }
  66. var _default = superClass => class extends superClass {
  67. jsxReadToken() {
  68. let out = "";
  69. let chunkStart = this.state.pos;
  70. for (;;) {
  71. if (this.state.pos >= this.length) {
  72. throw this.raise(this.state.start, JsxErrors.UnterminatedJsxContent);
  73. }
  74. const ch = this.input.charCodeAt(this.state.pos);
  75. switch (ch) {
  76. case 60:
  77. case 123:
  78. if (this.state.pos === this.state.start) {
  79. if (ch === 60 && this.state.exprAllowed) {
  80. ++this.state.pos;
  81. return this.finishToken(_types.types.jsxTagStart);
  82. }
  83. return super.getTokenFromCode(ch);
  84. }
  85. out += this.input.slice(chunkStart, this.state.pos);
  86. return this.finishToken(_types.types.jsxText, out);
  87. case 38:
  88. out += this.input.slice(chunkStart, this.state.pos);
  89. out += this.jsxReadEntity();
  90. chunkStart = this.state.pos;
  91. break;
  92. default:
  93. if ((0, _whitespace.isNewLine)(ch)) {
  94. out += this.input.slice(chunkStart, this.state.pos);
  95. out += this.jsxReadNewLine(true);
  96. chunkStart = this.state.pos;
  97. } else {
  98. ++this.state.pos;
  99. }
  100. }
  101. }
  102. }
  103. jsxReadNewLine(normalizeCRLF) {
  104. const ch = this.input.charCodeAt(this.state.pos);
  105. let out;
  106. ++this.state.pos;
  107. if (ch === 13 && this.input.charCodeAt(this.state.pos) === 10) {
  108. ++this.state.pos;
  109. out = normalizeCRLF ? "\n" : "\r\n";
  110. } else {
  111. out = String.fromCharCode(ch);
  112. }
  113. ++this.state.curLine;
  114. this.state.lineStart = this.state.pos;
  115. return out;
  116. }
  117. jsxReadString(quote) {
  118. let out = "";
  119. let chunkStart = ++this.state.pos;
  120. for (;;) {
  121. if (this.state.pos >= this.length) {
  122. throw this.raise(this.state.start, _error.Errors.UnterminatedString);
  123. }
  124. const ch = this.input.charCodeAt(this.state.pos);
  125. if (ch === quote) break;
  126. if (ch === 38) {
  127. out += this.input.slice(chunkStart, this.state.pos);
  128. out += this.jsxReadEntity();
  129. chunkStart = this.state.pos;
  130. } else if ((0, _whitespace.isNewLine)(ch)) {
  131. out += this.input.slice(chunkStart, this.state.pos);
  132. out += this.jsxReadNewLine(false);
  133. chunkStart = this.state.pos;
  134. } else {
  135. ++this.state.pos;
  136. }
  137. }
  138. out += this.input.slice(chunkStart, this.state.pos++);
  139. return this.finishToken(_types.types.string, out);
  140. }
  141. jsxReadEntity() {
  142. let str = "";
  143. let count = 0;
  144. let entity;
  145. let ch = this.input[this.state.pos];
  146. const startPos = ++this.state.pos;
  147. while (this.state.pos < this.length && count++ < 10) {
  148. ch = this.input[this.state.pos++];
  149. if (ch === ";") {
  150. if (str[0] === "#") {
  151. if (str[1] === "x") {
  152. str = str.substr(2);
  153. if (HEX_NUMBER.test(str)) {
  154. entity = String.fromCodePoint(parseInt(str, 16));
  155. }
  156. } else {
  157. str = str.substr(1);
  158. if (DECIMAL_NUMBER.test(str)) {
  159. entity = String.fromCodePoint(parseInt(str, 10));
  160. }
  161. }
  162. } else {
  163. entity = _xhtml.default[str];
  164. }
  165. break;
  166. }
  167. str += ch;
  168. }
  169. if (!entity) {
  170. this.state.pos = startPos;
  171. return "&";
  172. }
  173. return entity;
  174. }
  175. jsxReadWord() {
  176. let ch;
  177. const start = this.state.pos;
  178. do {
  179. ch = this.input.charCodeAt(++this.state.pos);
  180. } while ((0, _identifier.isIdentifierChar)(ch) || ch === 45);
  181. return this.finishToken(_types.types.jsxName, this.input.slice(start, this.state.pos));
  182. }
  183. jsxParseIdentifier() {
  184. const node = this.startNode();
  185. if (this.match(_types.types.jsxName)) {
  186. node.name = this.state.value;
  187. } else if (this.state.type.keyword) {
  188. node.name = this.state.type.keyword;
  189. } else {
  190. this.unexpected();
  191. }
  192. this.next();
  193. return this.finishNode(node, "JSXIdentifier");
  194. }
  195. jsxParseNamespacedName() {
  196. const startPos = this.state.start;
  197. const startLoc = this.state.startLoc;
  198. const name = this.jsxParseIdentifier();
  199. if (!this.eat(_types.types.colon)) return name;
  200. const node = this.startNodeAt(startPos, startLoc);
  201. node.namespace = name;
  202. node.name = this.jsxParseIdentifier();
  203. return this.finishNode(node, "JSXNamespacedName");
  204. }
  205. jsxParseElementName() {
  206. const startPos = this.state.start;
  207. const startLoc = this.state.startLoc;
  208. let node = this.jsxParseNamespacedName();
  209. if (node.type === "JSXNamespacedName") {
  210. return node;
  211. }
  212. while (this.eat(_types.types.dot)) {
  213. const newNode = this.startNodeAt(startPos, startLoc);
  214. newNode.object = node;
  215. newNode.property = this.jsxParseIdentifier();
  216. node = this.finishNode(newNode, "JSXMemberExpression");
  217. }
  218. return node;
  219. }
  220. jsxParseAttributeValue() {
  221. let node;
  222. switch (this.state.type) {
  223. case _types.types.braceL:
  224. node = this.startNode();
  225. this.next();
  226. node = this.jsxParseExpressionContainer(node);
  227. if (node.expression.type === "JSXEmptyExpression") {
  228. this.raise(node.start, JsxErrors.AttributeIsEmpty);
  229. }
  230. return node;
  231. case _types.types.jsxTagStart:
  232. case _types.types.string:
  233. return this.parseExprAtom();
  234. default:
  235. throw this.raise(this.state.start, JsxErrors.UnsupportedJsxValue);
  236. }
  237. }
  238. jsxParseEmptyExpression() {
  239. const node = this.startNodeAt(this.state.lastTokEnd, this.state.lastTokEndLoc);
  240. return this.finishNodeAt(node, "JSXEmptyExpression", this.state.start, this.state.startLoc);
  241. }
  242. jsxParseSpreadChild(node) {
  243. this.next();
  244. node.expression = this.parseExpression();
  245. this.expect(_types.types.braceR);
  246. return this.finishNode(node, "JSXSpreadChild");
  247. }
  248. jsxParseExpressionContainer(node) {
  249. if (this.match(_types.types.braceR)) {
  250. node.expression = this.jsxParseEmptyExpression();
  251. } else {
  252. node.expression = this.parseExpression();
  253. }
  254. this.expect(_types.types.braceR);
  255. return this.finishNode(node, "JSXExpressionContainer");
  256. }
  257. jsxParseAttribute() {
  258. const node = this.startNode();
  259. if (this.eat(_types.types.braceL)) {
  260. this.expect(_types.types.ellipsis);
  261. node.argument = this.parseMaybeAssignAllowIn();
  262. this.expect(_types.types.braceR);
  263. return this.finishNode(node, "JSXSpreadAttribute");
  264. }
  265. node.name = this.jsxParseNamespacedName();
  266. node.value = this.eat(_types.types.eq) ? this.jsxParseAttributeValue() : null;
  267. return this.finishNode(node, "JSXAttribute");
  268. }
  269. jsxParseOpeningElementAt(startPos, startLoc) {
  270. const node = this.startNodeAt(startPos, startLoc);
  271. if (this.match(_types.types.jsxTagEnd)) {
  272. this.expect(_types.types.jsxTagEnd);
  273. return this.finishNode(node, "JSXOpeningFragment");
  274. }
  275. node.name = this.jsxParseElementName();
  276. return this.jsxParseOpeningElementAfterName(node);
  277. }
  278. jsxParseOpeningElementAfterName(node) {
  279. const attributes = [];
  280. while (!this.match(_types.types.slash) && !this.match(_types.types.jsxTagEnd)) {
  281. attributes.push(this.jsxParseAttribute());
  282. }
  283. node.attributes = attributes;
  284. node.selfClosing = this.eat(_types.types.slash);
  285. this.expect(_types.types.jsxTagEnd);
  286. return this.finishNode(node, "JSXOpeningElement");
  287. }
  288. jsxParseClosingElementAt(startPos, startLoc) {
  289. const node = this.startNodeAt(startPos, startLoc);
  290. if (this.match(_types.types.jsxTagEnd)) {
  291. this.expect(_types.types.jsxTagEnd);
  292. return this.finishNode(node, "JSXClosingFragment");
  293. }
  294. node.name = this.jsxParseElementName();
  295. this.expect(_types.types.jsxTagEnd);
  296. return this.finishNode(node, "JSXClosingElement");
  297. }
  298. jsxParseElementAt(startPos, startLoc) {
  299. const node = this.startNodeAt(startPos, startLoc);
  300. const children = [];
  301. const openingElement = this.jsxParseOpeningElementAt(startPos, startLoc);
  302. let closingElement = null;
  303. if (!openingElement.selfClosing) {
  304. contents: for (;;) {
  305. switch (this.state.type) {
  306. case _types.types.jsxTagStart:
  307. startPos = this.state.start;
  308. startLoc = this.state.startLoc;
  309. this.next();
  310. if (this.eat(_types.types.slash)) {
  311. closingElement = this.jsxParseClosingElementAt(startPos, startLoc);
  312. break contents;
  313. }
  314. children.push(this.jsxParseElementAt(startPos, startLoc));
  315. break;
  316. case _types.types.jsxText:
  317. children.push(this.parseExprAtom());
  318. break;
  319. case _types.types.braceL:
  320. {
  321. const node = this.startNode();
  322. this.next();
  323. if (this.match(_types.types.ellipsis)) {
  324. children.push(this.jsxParseSpreadChild(node));
  325. } else {
  326. children.push(this.jsxParseExpressionContainer(node));
  327. }
  328. break;
  329. }
  330. default:
  331. throw this.unexpected();
  332. }
  333. }
  334. if (isFragment(openingElement) && !isFragment(closingElement)) {
  335. this.raise(closingElement.start, JsxErrors.MissingClosingTagFragment);
  336. } else if (!isFragment(openingElement) && isFragment(closingElement)) {
  337. this.raise(closingElement.start, JsxErrors.MissingClosingTagElement, getQualifiedJSXName(openingElement.name));
  338. } else if (!isFragment(openingElement) && !isFragment(closingElement)) {
  339. if (getQualifiedJSXName(closingElement.name) !== getQualifiedJSXName(openingElement.name)) {
  340. this.raise(closingElement.start, JsxErrors.MissingClosingTagElement, getQualifiedJSXName(openingElement.name));
  341. }
  342. }
  343. }
  344. if (isFragment(openingElement)) {
  345. node.openingFragment = openingElement;
  346. node.closingFragment = closingElement;
  347. } else {
  348. node.openingElement = openingElement;
  349. node.closingElement = closingElement;
  350. }
  351. node.children = children;
  352. if (this.isRelational("<")) {
  353. throw this.raise(this.state.start, JsxErrors.UnwrappedAdjacentJSXElements);
  354. }
  355. return isFragment(openingElement) ? this.finishNode(node, "JSXFragment") : this.finishNode(node, "JSXElement");
  356. }
  357. jsxParseElement() {
  358. const startPos = this.state.start;
  359. const startLoc = this.state.startLoc;
  360. this.next();
  361. return this.jsxParseElementAt(startPos, startLoc);
  362. }
  363. parseExprAtom(refExpressionErrors) {
  364. if (this.match(_types.types.jsxText)) {
  365. return this.parseLiteral(this.state.value, "JSXText");
  366. } else if (this.match(_types.types.jsxTagStart)) {
  367. return this.jsxParseElement();
  368. } else if (this.isRelational("<") && this.input.charCodeAt(this.state.pos) !== 33) {
  369. this.finishToken(_types.types.jsxTagStart);
  370. return this.jsxParseElement();
  371. } else {
  372. return super.parseExprAtom(refExpressionErrors);
  373. }
  374. }
  375. getTokenFromCode(code) {
  376. if (this.state.inPropertyName) return super.getTokenFromCode(code);
  377. const context = this.curContext();
  378. if (context === _context.types.j_expr) {
  379. return this.jsxReadToken();
  380. }
  381. if (context === _context.types.j_oTag || context === _context.types.j_cTag) {
  382. if ((0, _identifier.isIdentifierStart)(code)) {
  383. return this.jsxReadWord();
  384. }
  385. if (code === 62) {
  386. ++this.state.pos;
  387. return this.finishToken(_types.types.jsxTagEnd);
  388. }
  389. if ((code === 34 || code === 39) && context === _context.types.j_oTag) {
  390. return this.jsxReadString(code);
  391. }
  392. }
  393. if (code === 60 && this.state.exprAllowed && this.input.charCodeAt(this.state.pos + 1) !== 33) {
  394. ++this.state.pos;
  395. return this.finishToken(_types.types.jsxTagStart);
  396. }
  397. return super.getTokenFromCode(code);
  398. }
  399. updateContext(prevType) {
  400. if (this.match(_types.types.braceL)) {
  401. const curContext = this.curContext();
  402. if (curContext === _context.types.j_oTag) {
  403. this.state.context.push(_context.types.braceExpression);
  404. } else if (curContext === _context.types.j_expr) {
  405. this.state.context.push(_context.types.templateQuasi);
  406. } else {
  407. super.updateContext(prevType);
  408. }
  409. this.state.exprAllowed = true;
  410. } else if (this.match(_types.types.slash) && prevType === _types.types.jsxTagStart) {
  411. this.state.context.length -= 2;
  412. this.state.context.push(_context.types.j_cTag);
  413. this.state.exprAllowed = false;
  414. } else {
  415. return super.updateContext(prevType);
  416. }
  417. }
  418. };
  419. exports.default = _default;