diff --git a/lexicons/pub.coral.bookmark.json b/lexicons/pub.coral.bookmark.json index e8384f9..af722ae 100644 --- a/lexicons/pub.coral.bookmark.json +++ b/lexicons/pub.coral.bookmark.json @@ -1,27 +1,27 @@ { - "lexicon": 1, - "id": "pub.coral.bookmark", - "defs": { - "main": { - "type": "record", - "description": "A bookmark for a note. Stored on the user's PDS, portable across appviews.", - "key": "tid", - "record": { - "type": "object", - "required": ["noteRef", "createdAt"], - "properties": { - "noteRef": { - "type": "string", - "format": "at-uri", - "description": "AT-URI of the bookmarked note." - }, - "createdAt": { - "type": "string", - "format": "datetime", - "description": "When the bookmark was created." - } - } - } - } - } + "lexicon": 1, + "id": "pub.coral.bookmark", + "defs": { + "main": { + "type": "record", + "description": "A bookmark for a note. Stored on the user's PDS, portable across appviews.", + "key": "tid", + "record": { + "type": "object", + "required": ["noteRef", "createdAt"], + "properties": { + "noteRef": { + "type": "string", + "format": "at-uri", + "description": "AT-URI of the bookmarked note." + }, + "createdAt": { + "type": "string", + "format": "datetime", + "description": "When the bookmark was created." + } + } + } + } + } } diff --git a/lexicons/pub.coral.memberRequest.json b/lexicons/pub.coral.memberRequest.json index c5fda0e..32c036d 100644 --- a/lexicons/pub.coral.memberRequest.json +++ b/lexicons/pub.coral.memberRequest.json @@ -1,27 +1,27 @@ { - "lexicon": 1, - "id": "pub.coral.memberRequest", - "defs": { - "main": { - "type": "record", - "description": "A request to join a wiki.", - "key": "tid", - "record": { - "type": "object", - "required": ["wikiRef", "createdAt"], - "properties": { - "wikiRef": { - "type": "string", - "format": "at-uri", - "description": "AT-URI of the wiki the user wants to join." - }, - "createdAt": { - "type": "string", - "format": "datetime", - "description": "When the request was made." - } - } - } - } - } + "lexicon": 1, + "id": "pub.coral.memberRequest", + "defs": { + "main": { + "type": "record", + "description": "A request to join a wiki.", + "key": "tid", + "record": { + "type": "object", + "required": ["wikiRef", "createdAt"], + "properties": { + "wikiRef": { + "type": "string", + "format": "at-uri", + "description": "AT-URI of the wiki the user wants to join." + }, + "createdAt": { + "type": "string", + "format": "datetime", + "description": "When the request was made." + } + } + } + } + } } diff --git a/lexicons/pub.coral.membership.json b/lexicons/pub.coral.membership.json index cb9ced6..b21de22 100644 --- a/lexicons/pub.coral.membership.json +++ b/lexicons/pub.coral.membership.json @@ -1,36 +1,36 @@ { - "lexicon": 1, - "id": "pub.coral.membership", - "defs": { - "main": { - "type": "record", - "description": "A membership grant for a wiki. The rkey is a TID. The member's DID lives in the record body.", - "key": "tid", - "record": { - "type": "object", - "required": ["memberDid", "wikiRef", "role", "createdAt"], - "properties": { - "memberDid": { - "type": "string", - "description": "DID of the member being granted access." - }, - "wikiRef": { - "type": "string", - "format": "at-uri", - "description": "AT-URI of the wiki." - }, - "role": { - "type": "string", - "knownValues": ["admin", "viewer"], - "description": "The member's role in the wiki." - }, - "createdAt": { - "type": "string", - "format": "datetime", - "description": "When the membership was granted." - } - } - } - } - } + "lexicon": 1, + "id": "pub.coral.membership", + "defs": { + "main": { + "type": "record", + "description": "A membership grant for a wiki. The rkey is a TID. The member's DID lives in the record body.", + "key": "tid", + "record": { + "type": "object", + "required": ["memberDid", "wikiRef", "role", "createdAt"], + "properties": { + "memberDid": { + "type": "string", + "description": "DID of the member being granted access." + }, + "wikiRef": { + "type": "string", + "format": "at-uri", + "description": "AT-URI of the wiki." + }, + "role": { + "type": "string", + "knownValues": ["admin", "viewer"], + "description": "The member's role in the wiki." + }, + "createdAt": { + "type": "string", + "format": "datetime", + "description": "When the membership was granted." + } + } + } + } + } } diff --git a/lexicons/pub.coral.note.json b/lexicons/pub.coral.note.json index 3e49444..5da45a0 100644 --- a/lexicons/pub.coral.note.json +++ b/lexicons/pub.coral.note.json @@ -1,35 +1,35 @@ { - "lexicon": 1, - "id": "pub.coral.note", - "defs": { - "main": { - "type": "record", - "description": "A note within a wiki. The rkey is a TID. Human-readable slug lives in the record body.", - "key": "tid", - "record": { - "type": "object", - "required": ["slug", "title", "wikiRef", "createdAt"], - "properties": { - "slug": { - "type": "string", - "description": "Permanent human-readable identifier, used in URLs. Never changes once set." - }, - "title": { - "type": "string", - "description": "Display name for the note. Can be updated freely." - }, - "wikiRef": { - "type": "string", - "format": "at-uri", - "description": "AT-URI of the parent wiki record." - }, - "createdAt": { - "type": "string", - "format": "datetime", - "description": "When the note was created." - } - } - } - } - } + "lexicon": 1, + "id": "pub.coral.note", + "defs": { + "main": { + "type": "record", + "description": "A note within a wiki. The rkey is a TID. Human-readable slug lives in the record body.", + "key": "tid", + "record": { + "type": "object", + "required": ["slug", "title", "wikiRef", "createdAt"], + "properties": { + "slug": { + "type": "string", + "description": "Permanent human-readable identifier, used in URLs. Never changes once set." + }, + "title": { + "type": "string", + "description": "Display name for the note. Can be updated freely." + }, + "wikiRef": { + "type": "string", + "format": "at-uri", + "description": "AT-URI of the parent wiki record." + }, + "createdAt": { + "type": "string", + "format": "datetime", + "description": "When the note was created." + } + } + } + } + } } diff --git a/lexicons/pub.coral.noteRevision.json b/lexicons/pub.coral.noteRevision.json index e341e9f..3ca4a35 100644 --- a/lexicons/pub.coral.noteRevision.json +++ b/lexicons/pub.coral.noteRevision.json @@ -1,68 +1,68 @@ { - "lexicon": 1, - "id": "pub.coral.noteRevision", - "defs": { - "main": { - "type": "record", - "description": "A revision to a note, stored as a diff from the previous revision.", - "key": "tid", - "record": { - "type": "object", - "required": ["noteRef", "diff", "diffFormat", "createdAt"], - "properties": { - "noteRef": { - "type": "string", - "format": "at-uri", - "description": "AT-URI of the parent note record." - }, - "parentRevision": { - "type": "string", - "format": "at-uri", - "description": "AT-URI of the previous revision. Null for the first revision." - }, - "diff": { - "type": "string", - "description": "The diff content in the format specified by diffFormat." - }, - "diffFormat": { - "type": "string", - "knownValues": ["diff-match-patch"], - "description": "Format of the diff string." - }, - "message": { - "type": "string", - "maxLength": 1024, - "description": "Optional commit message describing this revision." - }, - "createdAt": { - "type": "string", - "format": "datetime", - "description": "When this revision was created." - }, - "blobs": { - "type": "array", - "items": { - "type": "ref", - "ref": "#blobRef" - }, - "description": "Blobs referenced by this revision's content." - } - } - } - }, - "blobRef": { - "type": "object", - "required": ["cid", "mimeType"], - "properties": { - "cid": { - "type": "string", - "description": "CID of the blob." - }, - "mimeType": { - "type": "string", - "description": "MIME type of the blob." - } - } - } - } + "lexicon": 1, + "id": "pub.coral.noteRevision", + "defs": { + "main": { + "type": "record", + "description": "A revision to a note, stored as a diff from the previous revision.", + "key": "tid", + "record": { + "type": "object", + "required": ["noteRef", "diff", "diffFormat", "createdAt"], + "properties": { + "noteRef": { + "type": "string", + "format": "at-uri", + "description": "AT-URI of the parent note record." + }, + "parentRevision": { + "type": "string", + "format": "at-uri", + "description": "AT-URI of the previous revision. Null for the first revision." + }, + "diff": { + "type": "string", + "description": "The diff content in the format specified by diffFormat." + }, + "diffFormat": { + "type": "string", + "knownValues": ["diff-match-patch"], + "description": "Format of the diff string." + }, + "message": { + "type": "string", + "maxLength": 1024, + "description": "Optional commit message describing this revision." + }, + "createdAt": { + "type": "string", + "format": "datetime", + "description": "When this revision was created." + }, + "blobs": { + "type": "array", + "items": { + "type": "ref", + "ref": "#blobRef" + }, + "description": "Blobs referenced by this revision's content." + } + } + } + }, + "blobRef": { + "type": "object", + "required": ["cid", "mimeType"], + "properties": { + "cid": { + "type": "string", + "description": "CID of the blob." + }, + "mimeType": { + "type": "string", + "description": "MIME type of the blob." + } + } + } + } } diff --git a/lexicons/pub.coral.wiki.json b/lexicons/pub.coral.wiki.json index e6cbf5a..37934a8 100644 --- a/lexicons/pub.coral.wiki.json +++ b/lexicons/pub.coral.wiki.json @@ -1,32 +1,32 @@ { - "lexicon": 1, - "id": "pub.coral.wiki", - "defs": { - "main": { - "type": "record", - "description": "A wiki. The rkey is a permanent slug.", - "key": "any", - "record": { - "type": "object", - "required": ["name", "visibility", "createdAt"], - "properties": { - "name": { - "type": "string", - "maxLength": 256, - "description": "Display name of the wiki." - }, - "visibility": { - "type": "string", - "knownValues": ["public", "private"], - "description": "Access level." - }, - "createdAt": { - "type": "string", - "format": "datetime", - "description": "When the wiki was created." - } - } - } - } - } + "lexicon": 1, + "id": "pub.coral.wiki", + "defs": { + "main": { + "type": "record", + "description": "A wiki. The rkey is a permanent slug.", + "key": "any", + "record": { + "type": "object", + "required": ["name", "visibility", "createdAt"], + "properties": { + "name": { + "type": "string", + "maxLength": 256, + "description": "Display name of the wiki." + }, + "visibility": { + "type": "string", + "knownValues": ["public", "private"], + "description": "Access level." + }, + "createdAt": { + "type": "string", + "format": "datetime", + "description": "When the wiki was created." + } + } + } + } + } } diff --git a/package.json b/package.json index 96de25a..c482601 100644 --- a/package.json +++ b/package.json @@ -1,40 +1,40 @@ { - "name": "atwiki", - "module": "src/server/index.ts", - "type": "module", - "private": true, - "scripts": { - "dev": "bun run --watch src/server/index.ts", - "dev:firehose": "bun run --watch src/firehose/index.ts", - "build:css": "bunx @tailwindcss/cli -i public/style.css -o public/dist.css", - "test": "bun test", - "lint": "bunx biome check src/", - "lint:fix": "bunx biome check --write src/", - "format": "bunx biome format --write src/", - "typecheck": "tsc --noEmit && tsc --noEmit -p public/tsconfig.json", - "build:viz": "bun build public/viz/viz-hydrate.ts --outfile public/viz/dist.js --minify", - "dev:viz": "bun build public/viz/viz-hydrate.ts --outfile public/viz/dist.js --watch" - }, - "devDependencies": { - "@biomejs/biome": "^2.4.4", - "@tailwindcss/cli": "^4.2.1", - "@types/bun": "latest", - "@types/d3": "^7.4.3", - "@types/diff-match-patch": "^1.0.36", - "@types/markdown-it": "^14.1.2", - "tailwindcss": "^4.2.1" - }, - "peerDependencies": { - "typescript": "^5" - }, - "dependencies": { - "@atproto/api": "^0.13.0", - "@atproto/jwk-jose": "^0.1.0", - "@atproto/oauth-client-node": "^0.1.0", - "@elysiajs/static": "^1.4.7", - "@sindresorhus/slugify": "^3.0.0", - "diff-match-patch": "^1.0.5", - "elysia": "^1.4.27", - "markdown-it": "^14.1.1" - } + "name": "atwiki", + "module": "src/server/index.ts", + "type": "module", + "private": true, + "scripts": { + "dev": "bun run --watch src/server/index.ts", + "dev:firehose": "bun run --watch src/firehose/index.ts", + "build:css": "bunx @tailwindcss/cli -i public/style.css -o public/dist.css", + "test": "bun test", + "lint": "bunx biome check src/", + "lint:fix": "bunx biome check --write src/", + "format": "bunx biome format --write src/", + "typecheck": "tsc --noEmit && tsc --noEmit -p public/tsconfig.json", + "build:viz": "bun build public/viz/viz-hydrate.ts --outfile public/viz/dist.js --minify", + "dev:viz": "bun build public/viz/viz-hydrate.ts --outfile public/viz/dist.js --watch" + }, + "devDependencies": { + "@biomejs/biome": "^2.4.4", + "@tailwindcss/cli": "^4.2.1", + "@types/bun": "latest", + "@types/d3": "^7.4.3", + "@types/diff-match-patch": "^1.0.36", + "@types/markdown-it": "^14.1.2", + "tailwindcss": "^4.2.1" + }, + "peerDependencies": { + "typescript": "^5" + }, + "dependencies": { + "@atproto/api": "^0.13.0", + "@atproto/jwk-jose": "^0.1.0", + "@atproto/oauth-client-node": "^0.1.0", + "@elysiajs/static": "^1.4.7", + "@sindresorhus/slugify": "^3.0.0", + "diff-match-patch": "^1.0.5", + "elysia": "^1.4.27", + "markdown-it": "^14.1.1" + } } diff --git a/public/tsconfig.json b/public/tsconfig.json index ec5b78c..c0e494a 100644 --- a/public/tsconfig.json +++ b/public/tsconfig.json @@ -1,8 +1,8 @@ { - "extends": "../tsconfig.json", - "compilerOptions": { - "lib": ["ESNext", "DOM", "DOM.Iterable"] - }, - "include": ["./**/*.ts"], - "exclude": [] + "extends": "../tsconfig.json", + "compilerOptions": { + "lib": ["ESNext", "DOM", "DOM.Iterable"] + }, + "include": ["./**/*.ts"], + "exclude": [] } diff --git a/public/viz/renderers/force-graph.ts b/public/viz/renderers/force-graph.ts index f992412..34f5d10 100644 --- a/public/viz/renderers/force-graph.ts +++ b/public/viz/renderers/force-graph.ts @@ -29,12 +29,17 @@ const GROUP_COLORS = [ "#ec4899", // pink ]; -export function renderForceGraph(container: HTMLElement, data: ForceGraphData): void { +export function renderForceGraph( + container: HTMLElement, + data: ForceGraphData, +): void { const width = container.clientWidth || 800; const height = 500; const groups = [...new Set(data.nodes.map((n) => n.group ?? "default"))]; - const colorMap = new Map(groups.map((g, i) => [g, GROUP_COLORS[i % GROUP_COLORS.length]!])); + const colorMap = new Map( + groups.map((g, i) => [g, GROUP_COLORS[i % GROUP_COLORS.length]!]), + ); const svg = d3 .select(container) @@ -104,21 +109,43 @@ export function renderForceGraph(container: HTMLElement, data: ForceGraphData): function drag( simulation: d3.Simulation, -): d3.DragBehavior { +): d3.DragBehavior< + SVGCircleElement, + ForceGraphNode, + ForceGraphNode | d3.SubjectPosition +> { return d3 .drag() - .on("start", (event: d3.D3DragEvent, d) => { - if (!event.active) simulation.alphaTarget(0.3).restart(); - d.fx = d.x; - d.fy = d.y; - }) - .on("drag", (event: d3.D3DragEvent, d) => { - d.fx = event.x; - d.fy = event.y; - }) - .on("end", (event: d3.D3DragEvent, d) => { - if (!event.active) simulation.alphaTarget(0); - d.fx = null; - d.fy = null; - }); + .on( + "start", + ( + event: d3.D3DragEvent, + d, + ) => { + if (!event.active) simulation.alphaTarget(0.3).restart(); + d.fx = d.x; + d.fy = d.y; + }, + ) + .on( + "drag", + ( + event: d3.D3DragEvent, + d, + ) => { + d.fx = event.x; + d.fy = event.y; + }, + ) + .on( + "end", + ( + event: d3.D3DragEvent, + d, + ) => { + if (!event.active) simulation.alphaTarget(0); + d.fx = null; + d.fy = null; + }, + ); } diff --git a/public/viz/renderers/sunburst.ts b/public/viz/renderers/sunburst.ts index 69f2d1e..2dc335c 100644 --- a/public/viz/renderers/sunburst.ts +++ b/public/viz/renderers/sunburst.ts @@ -7,7 +7,10 @@ import type { const COLORS = d3.schemeTableau10; -export function renderSunburst(container: HTMLElement, data: SunburstData): void { +export function renderSunburst( + container: HTMLElement, + data: SunburstData, +): void { const width = container.clientWidth || 800; const height = Math.min(width, 500); const radius = height / 2; @@ -17,13 +20,12 @@ export function renderSunburst(container: HTMLElement, data: SunburstData): void .sum((d) => d.value ?? 1) .sort((a, b) => (b.value ?? 0) - (a.value ?? 0)); - const partition = d3 - .partition() - .size([2 * Math.PI, radius]); + const partition = d3.partition().size([2 * Math.PI, radius]); const root = partition(hierarchy); - const color = d3.scaleOrdinal() + const color = d3 + .scaleOrdinal() .domain(root.children?.map((d) => d.data.name) ?? []) .range(COLORS); @@ -58,7 +60,11 @@ export function renderSunburst(container: HTMLElement, data: SunburstData): void .append("title") .text( (d) => - `${d.ancestors().map((a) => a.data.name).reverse().join(" → ")}\n${d.value ?? ""}`, + `${d + .ancestors() + .map((a) => a.data.name) + .reverse() + .join(" → ")}\n${d.value ?? ""}`, ); svg @@ -67,11 +73,7 @@ export function renderSunburst(container: HTMLElement, data: SunburstData): void .attr("font-size", 10) .attr("fill", "#374151") .selectAll("text") - .data( - root - .descendants() - .filter((d) => d.depth && (d.x1 - d.x0) > 0.1), - ) + .data(root.descendants().filter((d) => d.depth && d.x1 - d.x0 > 0.1)) .join("text") .attr("transform", (d) => { const x = ((d.x0 + d.x1) / 2) * (180 / Math.PI); diff --git a/src/lib/html.ts b/src/lib/html.ts new file mode 100644 index 0000000..072076d --- /dev/null +++ b/src/lib/html.ts @@ -0,0 +1,11 @@ +export function escapeHtml(str: string): string { + return str + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/"/g, """); +} + +export function escapeForTextarea(str: string): string { + return str.replace(/&/g, "&").replace(//g, ">"); +} diff --git a/src/lib/viz/plugin.ts b/src/lib/viz/plugin.ts index 3d78c82..d47e5a1 100644 --- a/src/lib/viz/plugin.ts +++ b/src/lib/viz/plugin.ts @@ -1,4 +1,5 @@ import type MarkdownIt from "markdown-it"; +import { escapeHtml } from "../html.ts"; import { type VizType, validate } from "./schemas.ts"; const VIZ_PREFIX = "viz-"; @@ -41,11 +42,3 @@ export function vizPlugin(md: MarkdownIt): void { return `
\n`; }; } - -function escapeHtml(str: string): string { - return str - .replace(/&/g, "&") - .replace(//g, ">") - .replace(/"/g, """); -} diff --git a/src/views/edit-note.ts b/src/views/edit-note.ts index 37cbf8c..2af39e2 100644 --- a/src/views/edit-note.ts +++ b/src/views/edit-note.ts @@ -1,23 +1,21 @@ +import { escapeForTextarea, escapeHtml } from "../lib/html.ts"; import { type LayoutOptions, layout } from "./layout.ts"; -function escapeForTextarea(s: string): string { - return s.replace(/&/g, "&").replace(//g, ">"); -} - export function editNotePage( wikiName: string, wikiSlug: string, noteSlug: string, + noteTitle: string, currentContent: string, options?: LayoutOptions, ): string { return layout( - `Edit ${noteSlug} — ${wikiName}`, + `Edit ${noteTitle} — ${wikiName}`, `
diff --git a/src/views/layout.ts b/src/views/layout.ts index 69a433f..de42f48 100644 --- a/src/views/layout.ts +++ b/src/views/layout.ts @@ -1,3 +1,5 @@ +import { escapeHtml } from "../lib/html.ts"; + export interface LayoutOptions { scripts?: string[]; session?: { did: string; handle: string } | null; @@ -46,11 +48,3 @@ ${extraScripts} `; } - -function escapeHtml(str: string): string { - return str - .replace(/&/g, "&") - .replace(//g, ">") - .replace(/"/g, """); -} diff --git a/src/views/new-note.ts b/src/views/new-note.ts index 95ae31b..baf62ae 100644 --- a/src/views/new-note.ts +++ b/src/views/new-note.ts @@ -1,13 +1,6 @@ +import { escapeHtml } from "../lib/html.ts"; import { type LayoutOptions, layout } from "./layout.ts"; -function escapeHtml(s: string): string { - return s - .replace(/&/g, "&") - .replace(//g, ">") - .replace(/"/g, """); -} - interface NewNoteOptions extends LayoutOptions { error?: string; titleValue?: string; diff --git a/src/views/note.ts b/src/views/note.ts index 687cbd3..37a19c0 100644 --- a/src/views/note.ts +++ b/src/views/note.ts @@ -1,20 +1,22 @@ +import { escapeHtml } from "../lib/html.ts"; import { type LayoutOptions, layout } from "./layout.ts"; export function notePage( wikiName: string, wikiSlug: string, noteSlug: string, + noteTitle: string, renderedHtml: string, options?: LayoutOptions, ): string { return layout( - `${noteSlug} — ${wikiName}`, + `${noteTitle} — ${wikiName}`, `
Edit
diff --git a/tests/atproto/routes.test.ts b/tests/atproto/routes.test.ts index e255007..ba30a9c 100644 --- a/tests/atproto/routes.test.ts +++ b/tests/atproto/routes.test.ts @@ -19,18 +19,14 @@ describe("atproto routes without OAuth configured", () => { }); test("GET /jwks.json returns 503", async () => { - const res = await app.handle( - new Request("http://localhost/jwks.json"), - ); + const res = await app.handle(new Request("http://localhost/jwks.json")); expect(res.status).toBe(503); const body = await res.text(); expect(body).toContain("OAuth not configured"); }); test("GET /login without handle returns 400", async () => { - const res = await app.handle( - new Request("http://localhost/login"), - ); + const res = await app.handle(new Request("http://localhost/login")); // When OAuth is not configured, returns 503 before checking handle expect(res.status).toBe(503); }); diff --git a/tests/atproto/session.test.ts b/tests/atproto/session.test.ts index 289eaff..f76d214 100644 --- a/tests/atproto/session.test.ts +++ b/tests/atproto/session.test.ts @@ -48,7 +48,10 @@ describe("getSession", () => { test("handles did as first cookie", async () => { const client = createMockClient((did) => ({ sub: did })); - const session = await getSession(client, "did=did%3Aplc%3Afirst; other=val"); + const session = await getSession( + client, + "did=did%3Aplc%3Afirst; other=val", + ); expect(session).not.toBeNull(); expect(session?.did).toBe("did:plc:first"); }); diff --git a/tests/lib/viz/plugin.test.ts b/tests/lib/viz/plugin.test.ts index 2ac30ab..e226438 100644 --- a/tests/lib/viz/plugin.test.ts +++ b/tests/lib/viz/plugin.test.ts @@ -51,9 +51,7 @@ describe("viz plugin", () => { }); test("does not interfere with normal code blocks", () => { - const { html, hasViz } = renderMarkdown( - "```js\nconsole.log('hi');\n```", - ); + const { html, hasViz } = renderMarkdown("```js\nconsole.log('hi');\n```"); expect(html).toContain("console.log"); expect(html).not.toContain("viz-container"); expect(hasViz).toBe(false); @@ -85,7 +83,7 @@ describe("viz plugin", () => { }); test("hasViz stays false for unknown viz type", () => { - const { hasViz } = renderMarkdown('```viz-unknown\n{}\n```'); + const { hasViz } = renderMarkdown("```viz-unknown\n{}\n```"); expect(hasViz).toBe(false); }); @@ -112,7 +110,7 @@ describe("viz plugin", () => { describe("viz plugin XSS prevention", () => { test("escapes HTML in unknown viz type name", () => { const { html } = renderMarkdown( - '```viz-\n{}\n```', + "```viz-\n{}\n```", ); expect(html).not.toContain("