From e848828ebdc8c3fe2ff997d16920782fa299232f Mon Sep 17 00:00:00 2001 From: Heath Stewart Date: Mon, 25 May 2026 14:16:40 -0700 Subject: [PATCH] Fix lints in tangled spindle This runs the biome installed by bun instead of the older version in the nixery image. That should suppress the warning about the schema being mismatched. Also fixes a number of lint issues along with tests for markdown, which also found a bug where links were processed before images, so "!alt text" was left behind. --- .tangled/workflows/lint.yml | 4 +- packages/cli/src/commands/inject.ts | 2 +- packages/cli/src/commands/publish.ts | 1 - .../cli/src/components/sequoia-subscribe.js | 4 +- packages/cli/src/lib/markdown.ts | 29 ++++--- packages/cli/test/markdown.test.ts | 79 ++++++++++++++++++- 6 files changed, 100 insertions(+), 19 deletions(-) diff --git a/.tangled/workflows/lint.yml b/.tangled/workflows/lint.yml index 32ae1c9..a686c14 100644 --- a/.tangled/workflows/lint.yml +++ b/.tangled/workflows/lint.yml @@ -17,6 +17,6 @@ steps: - name: "Install dependencies" command: "bun install" - name: "Lint check" - command: "cd packages/cli && biome lint ." + command: "cd packages/cli && bun run biome lint ." - name: "Format check" - command: "cd packages/cli && biome format ." + command: "cd packages/cli && bun run biome format ." diff --git a/packages/cli/src/commands/inject.ts b/packages/cli/src/commands/inject.ts index 19e1684..0fea3dc 100644 --- a/packages/cli/src/commands/inject.ts +++ b/packages/cli/src/commands/inject.ts @@ -131,7 +131,7 @@ export const injectCommand = command({ let content = await fs.readFile(htmlPath, "utf-8"); // Inject the tags - let injected = injectLinkTags( + const injected = injectLinkTags( dryRun, relativePath, content, diff --git a/packages/cli/src/commands/publish.ts b/packages/cli/src/commands/publish.ts index c2e417d..6295237 100644 --- a/packages/cli/src/commands/publish.ts +++ b/packages/cli/src/commands/publish.ts @@ -24,7 +24,6 @@ import { createBlueskyPost, addBskyPostRefToDocument, COVER_IMAGE_MAX_SIZE, - getPublication, } from "../lib/atproto"; import { scanContentDirectory, diff --git a/packages/cli/src/components/sequoia-subscribe.js b/packages/cli/src/components/sequoia-subscribe.js index f5f2f0a..5e46ec7 100644 --- a/packages/cli/src/components/sequoia-subscribe.js +++ b/packages/cli/src/components/sequoia-subscribe.js @@ -161,6 +161,7 @@ function storeSubscriberDid(did) { const expires = new Date( Date.now() + 365 * 24 * 60 * 60 * 1000, ).toUTCString(); + // biome-ignore lint/suspicious/noDocumentCookie: back-compat with older browsers document.cookie = `sequoia_did=${encodeURIComponent(did)}; Expires=${expires}; Path=/; SameSite=Lax; Secure`; } catch { // Cookie write may fail in some embedded contexts @@ -200,6 +201,7 @@ function getStoredSubscriberDid() { */ function clearSubscriberDid() { try { + // biome-ignore lint/suspicious/noDocumentCookie: back-compat with older browsers document.cookie = "sequoia_did=; Expires=Thu, 01 Jan 1970 00:00:00 GMT; Path=/; SameSite=Lax; Secure"; } catch { @@ -229,7 +231,7 @@ function consumeReturnParams() { changed = true; } - if (did && did.startsWith("did:")) { + if (did?.startsWith("did:")) { storeSubscriberDid(did); url.searchParams.delete("sequoia_did"); changed = true; diff --git a/packages/cli/src/lib/markdown.ts b/packages/cli/src/lib/markdown.ts index 1cfaed5..b9ece3b 100644 --- a/packages/cli/src/lib/markdown.ts +++ b/packages/cli/src/lib/markdown.ts @@ -379,17 +379,20 @@ export function updateFrontmatterWithAtUri( } export function stripMarkdownForText(markdown: string): string { - return markdown - .replace(/#{1,6}\s/g, "") // Remove headers - .replace(/\*\*([^*]+)\*\*/g, "$1") // Remove bold - .replace(/\*([^*]+)\*/g, "$1") // Remove italic - .replace(/\[([^\]]+)\]\([^)]+\)/g, "$1") // Remove links, keep text - .replace(/`{3}[\s\S]*?`{3}/g, "") // Remove code blocks - .replace(/`([^`]+)`/g, "$1") // Remove inline code formatting - .replace(/!\[.*?\]\(.*?\)/g, "") // Remove images - .replace(/\n{3,}/g, "\n\n") // Normalize multiple newlines - .replace(/(~{1,2})([^~]+?)\1/g, "$2") // Remove strikethrough for ~text~ and ~~text~~ - .replace(//g, "") // Remove any html comments - .replace(/^\s*\[\^[^\]]+\]:[^\r\n]*(?:\r?\n[ \t]+[^\r\n]*)*/gm, "") // Remove any footnotes - .trim(); + return ( + markdown + .replace(/#{1,6}\s/g, "") // Remove headers + .replace(/\*\*([^*]+)\*\*/g, "$1") // Remove bold + .replace(/\*([^*]+)\*/g, "$1") // Remove italic + // Must run before link regex: image syntax ![alt](url) shares [alt](url) with links + .replace(/!\[.*?\]\(.*?\)/g, "") // Remove images + .replace(/\[([^\]]+)\]\([^)]+\)/g, "$1") // Remove links, keep text + .replace(/`{3}[\s\S]*?`{3}/g, "") // Remove code blocks + .replace(/`([^`]+)`/g, "$1") // Remove inline code formatting + .replace(/\n{3,}/g, "\n\n") // Normalize multiple newlines + .replace(/(~{1,2})([^~]+?)\1/g, "$2") // Remove strikethrough for ~text~ and ~~text~~ + .replace(//g, "") // Remove any html comments + .replace(/^\s*\[\^[^\]]+\]:[^\r\n]*(?:\r?\n[ \t]+[^\r\n]*)*/gm, "") // Remove any footnotes + .trim() + ); } diff --git a/packages/cli/test/markdown.test.ts b/packages/cli/test/markdown.test.ts index 905df9d..2e50fe7 100644 --- a/packages/cli/test/markdown.test.ts +++ b/packages/cli/test/markdown.test.ts @@ -1,5 +1,9 @@ import { describe, expect, it } from "bun:test"; -import { parseFrontmatter, resolvePostPath } from "../src/lib/markdown"; +import { + parseFrontmatter, + resolvePostPath, + stripMarkdownForText, +} from "../src/lib/markdown"; import type { BlogPost } from "../src/lib/types"; describe("parseFrontmatter", () => { @@ -415,3 +419,76 @@ describe("resolvePostPath", () => { ); }); }); + +describe("stripMarkdownForText", () => { + it("removes h1 through h6 headers", () => { + expect( + stripMarkdownForText("# H1\n## H2\n### H3\n#### H4\n##### H5\n###### H6"), + ).toBe("H1\nH2\nH3\nH4\nH5\nH6"); + }); + + it("removes bold formatting", () => { + expect(stripMarkdownForText("This is **bold** text.")).toBe( + "This is bold text.", + ); + }); + + it("removes italic formatting", () => { + expect(stripMarkdownForText("This is *italic* text.")).toBe( + "This is italic text.", + ); + }); + + it("removes links but keeps link text", () => { + expect(stripMarkdownForText("[click here](https://example.com)")).toBe( + "click here", + ); + }); + + it("removes fenced code blocks", () => { + const input = "before\n```\nconst x = 1;\n```\nafter"; + expect(stripMarkdownForText(input)).toBe("before\n\nafter"); + }); + + it("removes inline code formatting", () => { + expect(stripMarkdownForText("Run `npm install` to install.")).toBe( + "Run npm install to install.", + ); + }); + + it("removes images", () => { + expect(stripMarkdownForText("before ![alt text](image.png) after")).toBe( + "before after", + ); + }); + + it("normalizes three or more consecutive newlines to two", () => { + expect(stripMarkdownForText("line 1\n\n\n\nline 2")).toBe( + "line 1\n\nline 2", + ); + }); + + it("removes single tilde strikethrough", () => { + expect(stripMarkdownForText("~strikethrough~")).toBe("strikethrough"); + }); + + it("removes double tilde strikethrough", () => { + expect(stripMarkdownForText("~~strikethrough~~")).toBe("strikethrough"); + }); + + it("removes HTML comments but preserves -- outside comments", () => { + expect(stripMarkdownForText("a -- b e -- f")).toBe( + "a -- b e -- f", + ); + }); + + it("removes footnote definitions but not inline references", () => { + const input = + "Text with[^1] a reference.\n\n[^1]: The footnote definition."; + expect(stripMarkdownForText(input)).toBe("Text with[^1] a reference."); + }); + + it("trims leading and trailing whitespace", () => { + expect(stripMarkdownForText("\n\nhello\n\n")).toBe("hello"); + }); +}); -- 2.54.0