diff --git a/internal/transformers/jsxtransforms/jsx.go b/internal/transformers/jsxtransforms/jsx.go
index a9650e5438..6b3b1e0302 100644
--- a/internal/transformers/jsxtransforms/jsx.go
+++ b/internal/transformers/jsxtransforms/jsx.go
@@ -839,23 +839,22 @@ func (tx *JSXTransformer) visitJsxExpression(expression *ast.JsxExpression) *ast
var htmlEntityMatcher = regexp2.MustCompile(`&((#((\d+)|x([\da-fA-F]+)))|(\w+));`, regexp2.ECMAScript)
func htmlEntityReplacer(m regexp2.Match) string {
- decimal := m.GroupByNumber(3)
- if decimal != nil {
+ decimal := m.GroupByNumber(4)
+ if decimal != nil && decimal.Capture.String() != "" {
parsed, err := strconv.ParseInt(decimal.Capture.String(), 10, 32)
if err == nil {
return string(rune(parsed))
}
}
- hex := m.GroupByNumber(4)
- if hex != nil {
+ hex := m.GroupByNumber(5)
+ if hex != nil && hex.Capture.String() != "" {
parsed, err := strconv.ParseInt(hex.Capture.String(), 16, 32)
if err == nil {
return string(rune(parsed))
}
}
- word := m.GroupByNumber(5)
- if word != nil {
- // If this is not a valid entity, then just use `match` (replace it with itself, i.e. don't replace)
+ word := m.GroupByNumber(6)
+ if word != nil && word.Capture.String() != "" {
res, ok := entities[word.Capture.String()]
if ok {
return string(res)
diff --git a/testdata/baselines/reference/submodule/conformance/tsxReactEmitEntities.js b/testdata/baselines/reference/submodule/conformance/tsxReactEmitEntities.js
index 5bf423bf70..4eed5bcb7e 100644
--- a/testdata/baselines/reference/submodule/conformance/tsxReactEmitEntities.js
+++ b/testdata/baselines/reference/submodule/conformance/tsxReactEmitEntities.js
@@ -25,16 +25,16 @@ declare var React: any;
🐈🐕🐇🐑
;
//// [file.js]
-React.createElement("div", null, "Dot goes here: · ¬AnEntity; ");
-React.createElement("div", null, "Be careful of "-ed strings!");
-React.createElement("div", null, "{{braces}}");
+React.createElement("div", null, "Dot goes here: \u00B7 ¬AnEntity; ");
+React.createElement("div", null, "Be careful of \"-ed strings!");
+React.createElement("div", null, "{{braces}}");
// Escapes do nothing
React.createElement("div", null, "\\n");
// Also works in string literal attributes
-React.createElement("div", { attr: "{…}\\" });
+React.createElement("div", { attr: "{\u2026}\\" });
// Does not happen for a string literal that happens to be inside an attribute (and escapes then work)
React.createElement("div", { attr: "{…}\"" });
// Preserves single quotes
React.createElement("div", { attr: "\"" });
// https://github.com/microsoft/TypeScript/issues/35732
-React.createElement("div", null, "🐈🐕\uD83D\uDC07\uD83D\uDC11");
+React.createElement("div", null, "\uD83D\uDC08\uD83D\uDC15\uD83D\uDC07\uD83D\uDC11");
diff --git a/testdata/baselines/reference/submodule/conformance/tsxReactEmitEntities.js.diff b/testdata/baselines/reference/submodule/conformance/tsxReactEmitEntities.js.diff
index caf74392c1..7316f258cb 100644
--- a/testdata/baselines/reference/submodule/conformance/tsxReactEmitEntities.js.diff
+++ b/testdata/baselines/reference/submodule/conformance/tsxReactEmitEntities.js.diff
@@ -1,25 +1,10 @@
--- old.tsxReactEmitEntities.js
+++ new.tsxReactEmitEntities.js
-@@= skipped -24, +24 lines =@@
- 🐈🐕🐇🐑
;
-
- //// [file.js]
--React.createElement("div", null, "Dot goes here: \u00B7 ¬AnEntity; ");
--React.createElement("div", null, "Be careful of \"-ed strings!");
--React.createElement("div", null, "{{braces}}");
-+React.createElement("div", null, "Dot goes here: · ¬AnEntity; ");
-+React.createElement("div", null, "Be careful of "-ed strings!");
-+React.createElement("div", null, "{{braces}}");
- // Escapes do nothing
- React.createElement("div", null, "\\n");
- // Also works in string literal attributes
--React.createElement("div", { attr: "{\u2026}\\" });
-+React.createElement("div", { attr: "{…}\\" });
+@@= skipped -34, +34 lines =@@
// Does not happen for a string literal that happens to be inside an attribute (and escapes then work)
React.createElement("div", { attr: "{…}\"" });
// Preserves single quotes
-React.createElement("div", { attr: '"' });
+React.createElement("div", { attr: "\"" });
// https://github.com/microsoft/TypeScript/issues/35732
--React.createElement("div", null, "\uD83D\uDC08\uD83D\uDC15\uD83D\uDC07\uD83D\uDC11");
-+React.createElement("div", null, "🐈🐕\uD83D\uDC07\uD83D\uDC11");
\ No newline at end of file
+ React.createElement("div", null, "\uD83D\uDC08\uD83D\uDC15\uD83D\uDC07\uD83D\uDC11");
\ No newline at end of file
diff --git a/testdata/baselines/reference/submodule/conformance/tsxReactEmitNesting.js b/testdata/baselines/reference/submodule/conformance/tsxReactEmitNesting.js
index 212b2a5476..6ce168d46f 100644
--- a/testdata/baselines/reference/submodule/conformance/tsxReactEmitNesting.js
+++ b/testdata/baselines/reference/submodule/conformance/tsxReactEmitNesting.js
@@ -38,6 +38,6 @@ let render = (ctrl, model) =>
//// [file.js]
// A simple render function with nesting and control statements
-let render = (ctrl, model) => vdom.createElement("section", { class: "todoapp" }, vdom.createElement("header", { class: "header" }, vdom.createElement("h1", null, "todos <x>"), vdom.createElement("input", { class: "new-todo", autofocus: true, autocomplete: "off", placeholder: "What needs to be done?", value: model.newTodo, onKeyup: ctrl.addTodo.bind(ctrl, model) })), vdom.createElement("section", { class: "main", style: { display: (model.todos && model.todos.length) ? "block" : "none" } }, vdom.createElement("input", { class: "toggle-all", type: "checkbox", onChange: ctrl.toggleAll.bind(ctrl) }), vdom.createElement("ul", { class: "todo-list" }, model.filteredTodos.map((todo) => vdom.createElement("li", { class: { todo: true, completed: todo.completed, editing: todo == model.editedTodo } }, vdom.createElement("div", { class: "view" }, (!todo.editable) ?
+let render = (ctrl, model) => vdom.createElement("section", { class: "todoapp" }, vdom.createElement("header", { class: "header" }, vdom.createElement("h1", null, "todos "), vdom.createElement("input", { class: "new-todo", autofocus: true, autocomplete: "off", placeholder: "What needs to be done?", value: model.newTodo, onKeyup: ctrl.addTodo.bind(ctrl, model) })), vdom.createElement("section", { class: "main", style: { display: (model.todos && model.todos.length) ? "block" : "none" } }, vdom.createElement("input", { class: "toggle-all", type: "checkbox", onChange: ctrl.toggleAll.bind(ctrl) }), vdom.createElement("ul", { class: "todo-list" }, model.filteredTodos.map((todo) => vdom.createElement("li", { class: { todo: true, completed: todo.completed, editing: todo == model.editedTodo } }, vdom.createElement("div", { class: "view" }, (!todo.editable) ?
vdom.createElement("input", { class: "toggle", type: "checkbox" })
: null, vdom.createElement("label", { onDoubleClick: () => { ctrl.editTodo(todo); } }, todo.title), vdom.createElement("button", { class: "destroy", onClick: ctrl.removeTodo.bind(ctrl, todo) }), vdom.createElement("div", { class: "iconBorder" }, vdom.createElement("div", { class: "icon" }))))))));
diff --git a/testdata/baselines/reference/submodule/conformance/tsxReactEmitNesting.js.diff b/testdata/baselines/reference/submodule/conformance/tsxReactEmitNesting.js.diff
index 78b7410280..c57bf6ef74 100644
--- a/testdata/baselines/reference/submodule/conformance/tsxReactEmitNesting.js.diff
+++ b/testdata/baselines/reference/submodule/conformance/tsxReactEmitNesting.js.diff
@@ -19,6 +19,6 @@
- vdom.createElement("button", { class: "destroy", onClick: ctrl.removeTodo.bind(ctrl, todo) }),
- vdom.createElement("div", { class: "iconBorder" },
- vdom.createElement("div", { class: "icon" }))))))));
-+let render = (ctrl, model) => vdom.createElement("section", { class: "todoapp" }, vdom.createElement("header", { class: "header" }, vdom.createElement("h1", null, "todos <x>"), vdom.createElement("input", { class: "new-todo", autofocus: true, autocomplete: "off", placeholder: "What needs to be done?", value: model.newTodo, onKeyup: ctrl.addTodo.bind(ctrl, model) })), vdom.createElement("section", { class: "main", style: { display: (model.todos && model.todos.length) ? "block" : "none" } }, vdom.createElement("input", { class: "toggle-all", type: "checkbox", onChange: ctrl.toggleAll.bind(ctrl) }), vdom.createElement("ul", { class: "todo-list" }, model.filteredTodos.map((todo) => vdom.createElement("li", { class: { todo: true, completed: todo.completed, editing: todo == model.editedTodo } }, vdom.createElement("div", { class: "view" }, (!todo.editable) ?
++let render = (ctrl, model) => vdom.createElement("section", { class: "todoapp" }, vdom.createElement("header", { class: "header" }, vdom.createElement("h1", null, "todos "), vdom.createElement("input", { class: "new-todo", autofocus: true, autocomplete: "off", placeholder: "What needs to be done?", value: model.newTodo, onKeyup: ctrl.addTodo.bind(ctrl, model) })), vdom.createElement("section", { class: "main", style: { display: (model.todos && model.todos.length) ? "block" : "none" } }, vdom.createElement("input", { class: "toggle-all", type: "checkbox", onChange: ctrl.toggleAll.bind(ctrl) }), vdom.createElement("ul", { class: "todo-list" }, model.filteredTodos.map((todo) => vdom.createElement("li", { class: { todo: true, completed: todo.completed, editing: todo == model.editedTodo } }, vdom.createElement("div", { class: "view" }, (!todo.editable) ?
+ vdom.createElement("input", { class: "toggle", type: "checkbox" })
+ : null, vdom.createElement("label", { onDoubleClick: () => { ctrl.editTodo(todo); } }, todo.title), vdom.createElement("button", { class: "destroy", onClick: ctrl.removeTodo.bind(ctrl, todo) }), vdom.createElement("div", { class: "iconBorder" }, vdom.createElement("div", { class: "icon" }))))))));
\ No newline at end of file