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]) );