From 53286798194ded3d4df46d137249b66066424b6d Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sun, 20 Sep 2026 08:12:55 +0200 Subject: [PATCH 1/2] Fix bug in local cheatsheet when injecting cheatsheet info --- packages/lib-cheatsheet-local/src/app.tsx | 3 ++ packages/lib-node-common/package.json | 1 + packages/lib-node-common/src/Cheatsheet.ts | 11 +++-- .../src/injectCheatsheetInfo.ts | 21 ++++++++++ .../lib-node-common/test/Cheatsheet.test.ts | 41 +++++++++++++++++++ pnpm-lock.yaml | 3 ++ 6 files changed, 74 insertions(+), 6 deletions(-) create mode 100644 packages/lib-node-common/src/injectCheatsheetInfo.ts create mode 100644 packages/lib-node-common/test/Cheatsheet.test.ts diff --git a/packages/lib-cheatsheet-local/src/app.tsx b/packages/lib-cheatsheet-local/src/app.tsx index 3e05ee56ef..cecfae869c 100644 --- a/packages/lib-cheatsheet-local/src/app.tsx +++ b/packages/lib-cheatsheet-local/src/app.tsx @@ -16,5 +16,8 @@ declare global { } export function App() { + if (document.cheatsheetInfo == null) { + throw new Error("Cheatsheet info is not available on the document."); + } return ; } diff --git a/packages/lib-node-common/package.json b/packages/lib-node-common/package.json index ed84af279b..51c9ee9267 100644 --- a/packages/lib-node-common/package.json +++ b/packages/lib-node-common/package.json @@ -21,6 +21,7 @@ "devDependencies": { "@types/js-yaml": "^4.0.9", "@types/lodash-es": "^4.17.12", + "@types/node": "^24.13.4", "js-yaml": "^5.4.1" } } diff --git a/packages/lib-node-common/src/Cheatsheet.ts b/packages/lib-node-common/src/Cheatsheet.ts index 9b7295b71d..a28d67c8d4 100644 --- a/packages/lib-node-common/src/Cheatsheet.ts +++ b/packages/lib-node-common/src/Cheatsheet.ts @@ -1,6 +1,5 @@ import { readFile, writeFile } from "node:fs/promises"; import path from "node:path"; -import { parse } from "node-html-parser"; import type { CheatsheetInfo, IDE } from "@cursorless/lib-common"; import { getCheatsheetInfo, @@ -9,6 +8,7 @@ import { showWarning, } from "@cursorless/lib-common"; import type { FileSystemTalonSpokenForms } from "./FileSystemTalonSpokenForms"; +import { injectCheatsheetInfo } from "./injectCheatsheetInfo"; interface CheatSheetCommandArgV0 { version: 0; @@ -47,12 +47,11 @@ export async function showCheatsheet( ); const cheatsheetPath = path.join(ide.assetsRoot, "cheatsheet.html"); const cheatsheetContent = await readFile(cheatsheetPath, "utf8"); - const root = parse(cheatsheetContent); - root.getElementById("cheatsheet-data")!.textContent = - `document.cheatsheetInfo = ${JSON.stringify(cheatsheetInfo)};`; - - await writeFile(arg.outputPath, root.toString()); + await writeFile( + arg.outputPath, + injectCheatsheetInfo(cheatsheetContent, cheatsheetInfo), + ); } async function getCheatsheetInfoForCommand( diff --git a/packages/lib-node-common/src/injectCheatsheetInfo.ts b/packages/lib-node-common/src/injectCheatsheetInfo.ts new file mode 100644 index 0000000000..69a3f9a228 --- /dev/null +++ b/packages/lib-node-common/src/injectCheatsheetInfo.ts @@ -0,0 +1,21 @@ +import { parse, TextNode } from "node-html-parser"; +import type { CheatsheetInfo } from "@cursorless/lib-common"; + +export function injectCheatsheetInfo( + cheatsheetContent: string, + cheatsheetInfo: CheatsheetInfo, +): string { + const root = parse(cheatsheetContent); + const serializedCheatsheetInfo = JSON.stringify(cheatsheetInfo).replaceAll( + "<", + String.raw`\\u003c`, + ); + + root + .getElementById("cheatsheet-data")! + .set_content( + new TextNode(`document.cheatsheetInfo = ${serializedCheatsheetInfo};`), + ); + + return root.toString(); +} diff --git a/packages/lib-node-common/test/Cheatsheet.test.ts b/packages/lib-node-common/test/Cheatsheet.test.ts new file mode 100644 index 0000000000..1f79f0db4c --- /dev/null +++ b/packages/lib-node-common/test/Cheatsheet.test.ts @@ -0,0 +1,41 @@ +import assert from "node:assert/strict"; +import { parse } from "node-html-parser"; +import type { CheatsheetInfo } from "@cursorless/lib-common"; +import { injectCheatsheetInfo } from "../src/injectCheatsheetInfo"; + +suite("Cheatsheet", () => { + test("injects cheatsheet info as executable script text", () => { + const cheatsheetInfo: CheatsheetInfo = { + sections: [ + { + id: "actions", + name: "Actions", + items: [ + { + id: "test-action", + type: "action", + variations: [ + { + spokenForm: "take ", + description: "Select A & B ", + }, + ], + }, + ], + }, + ], + }; + + const output = injectCheatsheetInfo( + '', + cheatsheetInfo, + ); + const script = parse(output).getElementById("cheatsheet-data")!; + + assert.equal( + script.rawText, + `document.cheatsheetInfo = ${JSON.stringify(cheatsheetInfo).replaceAll("<", String.raw`\\u003c`)};`, + ); + assert.doesNotMatch(script.rawText, /&(?:amp|lt|quot);/u); + }); +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 514d1da9e3..b0fb903c63 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -515,6 +515,9 @@ importers: '@types/lodash-es': specifier: ^4.17.12 version: 4.17.12 + '@types/node': + specifier: ^24.13.4 + version: 24.13.4 js-yaml: specifier: ^5.4.1 version: 5.4.1 From 8706611422f2f2a3ca3e114d4cd388bffb18adc8 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sun, 20 Sep 2026 08:15:05 +0200 Subject: [PATCH 2/2] Small fix --- packages/lib-node-common/src/injectCheatsheetInfo.ts | 2 +- packages/lib-node-common/test/Cheatsheet.test.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/lib-node-common/src/injectCheatsheetInfo.ts b/packages/lib-node-common/src/injectCheatsheetInfo.ts index 69a3f9a228..1f853dfa35 100644 --- a/packages/lib-node-common/src/injectCheatsheetInfo.ts +++ b/packages/lib-node-common/src/injectCheatsheetInfo.ts @@ -8,7 +8,7 @@ export function injectCheatsheetInfo( const root = parse(cheatsheetContent); const serializedCheatsheetInfo = JSON.stringify(cheatsheetInfo).replaceAll( "<", - String.raw`\\u003c`, + String.raw`\u003c`, ); root diff --git a/packages/lib-node-common/test/Cheatsheet.test.ts b/packages/lib-node-common/test/Cheatsheet.test.ts index 1f79f0db4c..ced3beaf07 100644 --- a/packages/lib-node-common/test/Cheatsheet.test.ts +++ b/packages/lib-node-common/test/Cheatsheet.test.ts @@ -34,7 +34,7 @@ suite("Cheatsheet", () => { assert.equal( script.rawText, - `document.cheatsheetInfo = ${JSON.stringify(cheatsheetInfo).replaceAll("<", String.raw`\\u003c`)};`, + `document.cheatsheetInfo = ${JSON.stringify(cheatsheetInfo).replaceAll("<", String.raw`\u003c`)};`, ); assert.doesNotMatch(script.rawText, /&(?:amp|lt|quot);/u); });