diff --git a/apps/app/src/components/generative-ui/__tests__/export-utils.test.ts b/apps/app/src/components/generative-ui/__tests__/export-utils.test.ts
index 8853eee..cb853c4 100644
--- a/apps/app/src/components/generative-ui/__tests__/export-utils.test.ts
+++ b/apps/app/src/components/generative-ui/__tests__/export-utils.test.ts
@@ -1,5 +1,8 @@
import { describe, it, expect } from "vitest";
-import { assembleStandaloneHtmlFromActivity } from "../export-utils";
+import {
+ assembleStandaloneHtmlFromActivity,
+ chartToStandaloneHtml,
+} from "../export-utils";
describe("assembleStandaloneHtmlFromActivity", () => {
const content = {
@@ -123,3 +126,18 @@ it("includes the shared trip animator before generated itinerary code", () => {
expect(doc).toContain("window.createTripAnimator =");
expect(doc.indexOf("window.createTripAnimator =")).toBeLessThan(doc.indexOf("window.createTripAnimator({"));
});
+
+describe("chartToStandaloneHtml", () => {
+ it("keeps data labels from closing the inline script", () => {
+ const label = "";
+ const doc = chartToStandaloneHtml("bar", {
+ title: "Chart",
+ description: "Labels",
+ data: [{ label, value: 1 }],
+ });
+ // Only the Chart.js CDN tag and the inline config script close.
+ expect(doc.match(/<\/script>/g)).toHaveLength(2);
+ expect(doc).not.toContain(label);
+ expect(doc).toContain("\u003c/script>");
+ });
+});
diff --git a/apps/app/src/components/generative-ui/export-utils.ts b/apps/app/src/components/generative-ui/export-utils.ts
index 106eec4..943f494 100644
--- a/apps/app/src/components/generative-ui/export-utils.ts
+++ b/apps/app/src/components/generative-ui/export-utils.ts
@@ -29,6 +29,12 @@ function escapeScriptClose(js: string): string {
return js.replace(/<\/script/gi, "<\\/script");
}
+// JSON for an inline " from closing the tag, and the result is still the same JS value.
+function toScriptJson(value: unknown): string {
+ return JSON.stringify(value).replace(/ }
): string {
- const labels = JSON.stringify(data.data.map((d) => d.label));
- const values = JSON.stringify(data.data.map((d) => d.value));
- const colors = JSON.stringify(
+ const labels = toScriptJson(data.data.map((d) => d.label));
+ const values = toScriptJson(data.data.map((d) => d.value));
+ const colors = toScriptJson(
data.data.map((_, i) => CHART_COLORS[i % CHART_COLORS.length])
);