Repository: alangpierce/sucrase
Pull request #717 (2022-07-08 07:26:43)

Port babel-parser changes from 2022-03-06 to 2022-04-29
Instructions: https://github.com/alangpierce/sucrase/wiki/Porting-changes-from-Babel's-parser

4bb9b89b2d Remove length restriction from JSX entities, and ignore `Object.prototype` (#14327)
✅ Fixed prototype issue by switching to Map. Fixed length restriction by porting
code in a similar way.

9ba894c123 Type-safe ParseErrors (#14320)
🚫 Appears to only affect error handling, so not relevant to Sucrase.

24f0944e2d Report single error for invalid num seps in unicode escapes (#14338)
🚫 Only affects error handling.

bae5027844 Allow variable and function with the same name in static blocks (#14344)
🚫 Already worked in Sucrase, and Sucrase never does this type of checking, so
doesn't seem useful to add a test.

983f707611 move static-block and private-in tests to es2022 (#14346)
🚫 Babel-internal change.

4f1617cdd0 v7.17.7
🚫 Release only.

01380a61f1 Allow keywords in TS qualified types (#14362)
🚫 Fixes regression that didn't happen in Sucrase.

4392e4f69f Defer `<T>() => {}` TSX error to Babel 8 (#14367)
🚫 Only affects error handling. Sucrase handles this syntax without the trailing comma.

1a58c7ed6a v7.17.8
🚫 Release only.

cb74c3772e refactor: replace deprecated String.prototype.substr() (#14377)
🚫 Already done in Sucrase.

c79709a669 Parenthesize non-simple decorator expression (#14378)
🚫 Only affects paren parsing, which Sucrase doesn't need to handle.

326c4208fc fix: parse type parameters with inType context (#14384)
✅ Fixed by switching tokenizing approach to be more similar to Babel. We now
always treat > as greater-than in a type context and rescan if necessary after
an `as` operator. The original fix from this PR was unnecessary because type
aliases already are in a type context.

84336bb184 Merge `babel-check-duplicated-nodes` into monorepo (#14420)
🚫 Internal Babel change that doesn't affect Sucrase.

7a473ed0c6 Restore numeric seaprators support in `@babel/standalone` (#14427)
🚫 Fix for regression that didn't happen in Sucrase.

3c762e876d v7.17.9
🚫 Release only.

99842ace6e chore: correct typos (#14440)
🚫 These typos aren't present in Sucrase.

df5c1ebb45 Add missing `startColumn` to `ParserOptions` type definition (#14453)
🚫 Only affects type definitions.

09b335ad5d v7.17.10
🚫 Release only.

c90add779a Provide plugin/preset typings from plugin-utils (#14499)
🚫 Only affects types for the Babel project.

codecov[bot]: # [Codecov](https://codecov.io/gh/alangpierce/sucrase/pull/717?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Alan+Pierce) Report
> Merging [#717](https://codecov.io/gh/alangpierce/sucrase/pull/717?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Alan+Pierce) (2d0b14a) into [main](https://codecov.io/gh/alangpierce/sucrase/commit/173e4fefc2288a0d38d89dcd9ce8c21acc175f81?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Alan+Pierce) (173e4fe) will **increase** coverage by `0.04%`.
> The diff coverage is `97.29%`.

```diff
@@            Coverage Diff             @@
##             main     #717      +/-   ##
==========================================
+ Coverage   86.86%   86.91%   +0.04%     
==========================================
  Files          54       54              
  Lines        5665     5679      +14     
  Branches     1333     1338       +5     
==========================================
+ Hits         4921     4936      +15     
  Misses        472      472              
+ Partials      272      271       -1     
```


| [Impacted Files](https://codecov.io/gh/alangpierce/sucrase/pull/717?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Alan+Pierce) | Coverage Δ | |
|---|---|---|
| [src/transformers/JSXTransformer.ts](https://codecov.io/gh/alangpierce/sucrase/pull/717/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Alan+Pierce#diff-c3JjL3RyYW5zZm9ybWVycy9KU1hUcmFuc2Zvcm1lci50cw==) | `97.16% <96.15%> (+0.63%)` | :arrow_up: |
| [src/parser/plugins/jsx/xhtml.ts](https://codecov.io/gh/alangpierce/sucrase/pull/717/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Alan+Pierce#diff-c3JjL3BhcnNlci9wbHVnaW5zL2pzeC94aHRtbC50cw==) | `100.00% <100.00%> (ø)` | |
| [src/parser/tokenizer/index.ts](https://codecov.io/gh/alangpierce/sucrase/pull/717/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Alan+Pierce#diff-c3JjL3BhcnNlci90b2tlbml6ZXIvaW5kZXgudHM=) | `86.05% <100.00%> (+0.09%)` | :arrow_up: |
| [src/parser/traverser/expression.ts](https://codecov.io/gh/alangpierce/sucrase/pull/717/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Alan+Pierce#diff-c3JjL3BhcnNlci90cmF2ZXJzZXIvZXhwcmVzc2lvbi50cw==) | `88.46% <100.00%> (+0.02%)` | :arrow_up: |

:mega: Codecov can now indicate which changes are the most critical in Pull Requests. [Learn more](https://about.codecov.io/product/feature/runtime-insights/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Alan+Pierce)

github-actions[bot]: ## Benchmark results
**Before this PR:** 328.1 thousand lines per second
**After this PR:**  330.1 thousand lines per second

**Measured change:** 0.62% faster (0.21% slower to 1.07% faster)
**Summary:** Likely no significant difference

Patch:
diff --git a/src/parser/plugins/jsx/xhtml.ts b/src/parser/plugins/jsx/xhtml.ts
index e2dd5f8..8e5a9a9 100644
--- a/src/parser/plugins/jsx/xhtml.ts
+++ b/src/parser/plugins/jsx/xhtml.ts
@@ -1,256 +1,256 @@
-const entities: {[name: string]: string} = {
-  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",
-};
-export default entities;
+// Use a Map rather than object to avoid unexpected __proto__ access.
+export default new Map<string, string>([
+  ["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"],
+]);
diff --git a/src/parser/tokenizer/index.ts b/src/parser/tokenizer/index.ts
index 2eb68f2..3349a60 100644
--- a/src/parser/tokenizer/index.ts
+++ b/src/parser/tokenizer/index.ts
@@ -507,20 +507,21 @@ function readToken_lt(): void {
 }
 
 function readToken_gt(): void {
-  const code = charCodes.greaterThan;
+  if (state.isType) {
+    // Avoid right-shift for things like `Array<Array<string>>` and
+    // greater-than-or-equal for things like `const a: Array<number>=[];`.
+    finishOp(tt.greaterThan, 1);
+    return;
+  }
+
   const nextChar = input.charCodeAt(state.pos + 1);
 
-  if (nextChar === code) {
+  if (nextChar === charCodes.greaterThan) {
     const size = input.charCodeAt(state.pos + 2) === charCodes.greaterThan ? 3 : 2;
     if (input.charCodeAt(state.pos + size) === charCodes.equalsTo) {
       finishOp(tt.assign, size + 1);
       return;
     }
-    // Avoid right-shift for things like Array<Array<string>>.
-    if (code === charCodes.greaterThan && state.isType) {
-      finishOp(tt.greaterThan, 1);
-      return;
-    }
     finishOp(tt.bitShiftR, size);
     return;
   }
@@ -533,6 +534,17 @@ function readToken_gt(): void {
   }
 }
 
+/**
+ * Called after `as` expressions in TS; we're switching from a type to a
+ * non-type context, so a > token may actually be >=
+ */
+export function rescan_gt(): void {
+  if (state.type === tt.greaterThan) {
+    state.pos -= 1;
+    readToken_gt();
+  }
+}
+
 function readToken_eq_excl(code: number): void {
   // '=!'
   const nextChar = input.charCodeAt(state.pos + 1);
diff --git a/src/parser/traverser/expression.ts b/src/parser/traverser/expression.ts
index 78e2c26..a3530df 100644
--- a/src/parser/traverser/expression.ts
+++ b/src/parser/traverser/expression.ts
@@ -52,6 +52,7 @@ import {
   nextTemplateToken,
   popTypeContext,
   pushTypeContext,
+  rescan_gt,
   retokenizeSlashAsRegex,
 } from "../tokenizer/index";
 import {ContextualKeyword} from "../tokenizer/keywords";
@@ -206,6 +207,7 @@ function parseExprOp(startTokenIndex: number, minPrec: number, noIn: boolean): v
     const oldIsType = pushTypeContext(1);
     tsParseType();
     popTypeContext(oldIsType);
+    rescan_gt();
     parseExprOp(startTokenIndex, minPrec, noIn);
     return;
   }
diff --git a/src/transformers/JSXTransformer.ts b/src/transformers/JSXTransformer.ts
index 1d22c7b..f13c002 100644
--- a/src/transformers/JSXTransformer.ts
+++ b/src/transformers/JSXTransformer.ts
@@ -9,9 +9,6 @@ import getJSXPragmaInfo, {JSXPragmaInfo} from "../util/getJSXPragmaInfo";
 import type RootTransformer from "./RootTransformer";
 import Transformer from "./Transformer";
 
-const HEX_NUMBER = /^[\da-fA-F]+$/;
-const DECIMAL_NUMBER = /^\d+$/;
-
 export default class JSXTransformer extends Transformer {
   lastLineNumber: number = 1;
   lastIndex: number = 0;
@@ -360,6 +357,9 @@ function formatJSXStringValueLiteral(text: string): string {
 }
 
 /**
+ * Starting at a &, see if there's an HTML entity (specified by name, decimal
+ * char code, or hex char code) and return it if so.
+ *
  * Modified from jsxReadString in babel-parser.
  */
 function processEntity(text: string, indexAfterAmpersand: number): {entity: string; newI: number} {
@@ -368,31 +368,56 @@ function processEntity(text: string, indexAfterAmpersand: number): {entity: stri
   let entity;
   let i = indexAfterAmpersand;
 
-  while (i < text.length && count++ < 10) {
-    const ch = text[i];
+  if (text[i] === "#") {
+    let radix = 10;
     i++;
-    if (ch === ";") {
-      if (str[0] === "#") {
-        if (str[1] === "x") {
-          str = str.slice(2);
-          if (HEX_NUMBER.test(str)) {
-            entity = String.fromCodePoint(parseInt(str, 16));
-          }
-        } else {
-          str = str.slice(1);
-          if (DECIMAL_NUMBER.test(str)) {
-            entity = String.fromCodePoint(parseInt(str, 10));
-          }
-        }
-      } else {
-        entity = XHTMLEntities[str];
+    let numStart;
+    if (text[i] === "x") {
+      radix = 16;
+      i++;
+      numStart = i;
+      while (i < text.length && isHexDigit(text.charCodeAt(i))) {
+        i++;
+      }
+    } else {
+      numStart = i;
+      while (i < text.length && isDecimalDigit(text.charCodeAt(i))) {
+        i++;
+      }
+    }
+    if (text[i] === ";") {
+      const numStr = text.slice(numStart, i);
+      if (numStr) {
+        i++;
+        entity = String.fromCodePoint(parseInt(numStr, radix));
       }
-      break;
     }
-    str += ch;
+  } else {
+    while (i < text.length && count++ < 10) {
+      const ch = text[i];
+      i++;
+      if (ch === ";") {
+        entity = XHTMLEntities.get(str);
+        break;
+      }
+      str += ch;
+    }
   }
+
   if (!entity) {
     return {entity: "&", newI: indexAfterAmpersand};
   }
   return {entity, newI: i};
 }
+
+function isDecimalDigit(code: number): boolean {
+  return code >= charCodes.digit0 && code <= charCodes.digit9;
+}
+
+function isHexDigit(code: number): boolean {
+  return (
+    (code >= charCodes.digit0 && code <= charCodes.digit9) ||
+    (code >= charCodes.lowercaseA && code <= charCodes.lowercaseF) ||
+    (code >= charCodes.uppercaseA && code <= charCodes.uppercaseF)
+  );
+}


Test patch:
diff --git a/test/jsx-test.ts b/test/jsx-test.ts
index 3919502..0bca017 100644
--- a/test/jsx-test.ts
+++ b/test/jsx-test.ts
@@ -255,6 +255,39 @@ describe("transform JSX", () => {
     );
   });
 
+  it("does not transform empty number HTML entities", () => {
+    assertResult(
+      `
+      <span>a&#;b</span>
+    `,
+      `${JSX_PREFIX}
+      React.createElement('span', {${devProps(2)}}, "a&#;b")
+    `,
+    );
+  });
+
+  it("allows adjacent HTML entities", () => {
+    assertResult(
+      `
+      <span>a&#100;&#100;b</span>
+    `,
+      `${JSX_PREFIX}
+      React.createElement('span', {${devProps(2)}}, "addb")
+    `,
+    );
+  });
+
+  it("allows HTML entity right after near-entity with semicolon missing", () => {
+    assertResult(
+      `
+      <span>a&#100&#100;b</span>
+    `,
+      `${JSX_PREFIX}
+      React.createElement('span', {${devProps(2)}}, "a&#100db")
+    `,
+    );
+  });
+
   it("handles ampersand in HTML", () => {
     assertResult(
       `
@@ -604,4 +637,27 @@ describe("transform JSX", () => {
       );
     });
   });
+
+  it("handles long HTML entities with many leading 0s", () => {
+    // https://github.com/babel/babel/issues/14316
+    assertResult(
+      `
+      <div> &#00000000000000000020; </div>
+    `,
+      `${JSX_PREFIX}
+      React.createElement('div', {${devProps(2)}}, " \\u0014 "  )
+    `,
+    );
+  });
+
+  it("does not allow prototype access in JSX entity handling", () => {
+    assertResult(
+      `
+      <a>&valueOf;</a>
+    `,
+      `${JSX_PREFIX}
+      React.createElement('a', {${devProps(2)}}, "&valueOf;")
+    `,
+    );
+  });
 });
diff --git a/test/typescript-test.ts b/test/typescript-test.ts
index 3449966..ab9613a 100644
--- a/test/typescript-test.ts
+++ b/test/typescript-test.ts
@@ -3116,4 +3116,18 @@ describe("typescript transform", () => {
       {transforms: ["typescript"]},
     );
   });
+
+  it("handles >= as the end of a type parameter followed by assignment", () => {
+    assertResult(
+      `
+      type T<U>=U;
+      const a: Array<number>=[];
+    `,
+      `
+      
+      const a=[];
+    `,
+      {transforms: ["typescript"]},
+    );
+  });
 });