Skip to content

Commit c2581aa

Browse files
authored
fix(backend): jsx compatible with html-entities & curly braces (#243)
1 parent 4cb2621 commit c2581aa

File tree

7 files changed

+39
-3
lines changed

7 files changed

+39
-3
lines changed

packages/backend/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
},
1515
"dependencies": {
1616
"@figma/plugin-typings": "^1.121.0",
17+
"html-entities": "^2.6.0",
1718
"js-base64": "^3.7.8",
1819
"nanoid": "^5.1.6",
1920
"react": "19.0.0",

packages/backend/src/common/parseJSX.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { encode } from "html-entities";
12
import { numberToFixedString } from "./numToAutoFixed";
23

34
export const formatWithJSX = (
@@ -40,3 +41,10 @@ export const formatMultipleJSX = (
4041
.filter(([key, value]) => value)
4142
.map(([key, value]) => formatWithJSX(key, isJsx, value!))
4243
.join(isJsx ? ", " : "; ");
44+
45+
export const escapeJSXText = (text: string): string => {
46+
return encode(text, { level: "html5" })
47+
// process JSX curly braces
48+
.replace(/\{/g, "{")
49+
.replace(/\}/g, "}");
50+
};

packages/backend/src/html/htmlDefaultBuilder.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,11 @@ export class HtmlDefaultBuilder {
6262
return this.settings.htmlGenerationMode === "svelte";
6363
}
6464

65+
get needsJSXTextEscaping() {
66+
const mode = this.settings.htmlGenerationMode;
67+
return mode === "jsx" || mode === "styled-components" || mode === "svelte";
68+
}
69+
6570
get useStyledComponents() {
6671
return this.settings.htmlGenerationMode === "styled-components";
6772
}

packages/backend/src/html/htmlTextBuilder.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { formatMultipleJSX, formatWithJSX } from "../common/parseJSX";
1+
import { formatMultipleJSX, formatWithJSX, escapeJSXText } from "../common/parseJSX";
22
import { HtmlDefaultBuilder } from "./htmlDefaultBuilder";
33
import { htmlColorFromFills } from "./builderImpl/htmlColor";
44
import {
@@ -70,7 +70,11 @@ export class HtmlTextBuilder extends HtmlDefaultBuilder {
7070
this.isJSX,
7171
);
7272

73-
const charsWithLineBreak = segment.characters.split("\n").join("<br/>");
73+
let chars = segment.characters;
74+
if (this.needsJSXTextEscaping) {
75+
chars = escapeJSXText(chars);
76+
}
77+
const charsWithLineBreak = chars.split("\n").join("<br/>");
7478
const result: any = {
7579
style: styleAttributes,
7680
text: charsWithLineBreak,

packages/backend/src/tailwind/tailwindDefaultBuilder.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ export class TailwindDefaultBuilder {
5454
return this.settings.tailwindGenerationMode === "jsx";
5555
}
5656

57+
get needsJSXTextEscaping() {
58+
return this.isJSX;
59+
}
60+
5761
get isTwigComponent() {
5862
return this.settings.tailwindGenerationMode === "twig" && this.node.type === "INSTANCE"
5963
}

packages/backend/src/tailwind/tailwindTextBuilder.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import {
22
commonLetterSpacing,
33
commonLineHeight,
44
} from "../common/commonTextHeightSpacing";
5+
import { escapeJSXText } from "../common/parseJSX";
56
import { tailwindColorFromFills } from "./builderImpl/tailwindColor";
67
import {
78
pxToFontSize,
@@ -60,7 +61,11 @@ export class TailwindTextBuilder extends TailwindDefaultBuilder {
6061
.filter(Boolean)
6162
.join(" ");
6263

63-
const charsWithLineBreak = segment.characters.split("\n").join("<br/>");
64+
let chars = segment.characters;
65+
if (this.needsJSXTextEscaping) {
66+
chars = escapeJSXText(chars);
67+
}
68+
const charsWithLineBreak = chars.split("\n").join("<br/>");
6469
return {
6570
style: styleClasses,
6671
text: charsWithLineBreak,

pnpm-lock.yaml

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)