* fix: Signal and markdown formatting improvements Markdown IR fixes: - Fix list-paragraph spacing (extra newline between list items and following paragraphs) - Fix nested list indentation and newline handling - Fix blockquote_close emitting redundant newline (inner content handles spacing) - Render horizontal rules as visible ─── separator instead of silent drop - Strip inner cell styles in code-mode tables to prevent overlapping with code_block span Signal formatting fixes: - Normalize URLs for dedup comparison (strip protocol, www., trailing slash) - Render headings as bold text (headingStyle: 'bold') - Add '> ' prefix to blockquotes for visual distinction - Re-chunk after link expansion to respect chunk size limits Tests: - 51 new tests for markdown IR (spacing, lists, blockquotes, tables, HR) - 18 new tests for Signal formatting (URL dedup, headings, blockquotes, HR, chunking) - Update Slack nested list test expectation to match corrected IR output * refactor: style-aware Signal text chunker Replace indexOf-based chunk position tracking with deterministic cursor tracking. The new splitSignalFormattedText: - Splits at whitespace/newline boundaries within the limit - Avoids breaking inside parentheses (preserves expanded link URLs) - Slices style ranges at chunk boundaries with correct local offsets - Tracks position via offset arithmetic instead of fragile indexOf Removes dependency on chunkText from auto-reply/chunk. Tests: 19 new tests covering style preservation across chunk boundaries, edge cases (empty text, under limit, exact split points), and integration with link expansion. * fix: correct Signal style offsets with multiple link expansions applyInsertionsToStyles() was using original coordinates for each insertion without tracking cumulative shift from prior insertions. This caused bold/italic/etc styles to drift to wrong text positions when multiple markdown links expanded in a single message. Added cumulative shift tracking and a regression test. * test: clean up test noise and fix ineffective assertions - Remove console.log from ir.list-spacing and ir.hr-spacing tests - Fix ir.nested-lists.test.ts: remove ineffective regex assertion - Fix ir.hr-spacing.test.ts: add actual assertions to edge case test * refactor: split Signal formatting tests (#9781) (thanks @heyhudson) --------- Co-authored-by: Hudson <258693705+hudson-rivera@users.noreply.github.com> Co-authored-by: Peter Steinberger <steipete@gmail.com>
100 lines
3.2 KiB
TypeScript
100 lines
3.2 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { markdownToSlackMrkdwn } from "./format.js";
|
|
|
|
describe("markdownToSlackMrkdwn", () => {
|
|
it("converts bold from double asterisks to single", () => {
|
|
const res = markdownToSlackMrkdwn("**bold text**");
|
|
expect(res).toBe("*bold text*");
|
|
});
|
|
|
|
it("preserves italic underscore format", () => {
|
|
const res = markdownToSlackMrkdwn("_italic text_");
|
|
expect(res).toBe("_italic text_");
|
|
});
|
|
|
|
it("converts strikethrough from double tilde to single", () => {
|
|
const res = markdownToSlackMrkdwn("~~strikethrough~~");
|
|
expect(res).toBe("~strikethrough~");
|
|
});
|
|
|
|
it("renders basic inline formatting together", () => {
|
|
const res = markdownToSlackMrkdwn("hi _there_ **boss** `code`");
|
|
expect(res).toBe("hi _there_ *boss* `code`");
|
|
});
|
|
|
|
it("renders inline code", () => {
|
|
const res = markdownToSlackMrkdwn("use `npm install`");
|
|
expect(res).toBe("use `npm install`");
|
|
});
|
|
|
|
it("renders fenced code blocks", () => {
|
|
const res = markdownToSlackMrkdwn("```js\nconst x = 1;\n```");
|
|
expect(res).toBe("```\nconst x = 1;\n```");
|
|
});
|
|
|
|
it("renders links with Slack mrkdwn syntax", () => {
|
|
const res = markdownToSlackMrkdwn("see [docs](https://example.com)");
|
|
expect(res).toBe("see <https://example.com|docs>");
|
|
});
|
|
|
|
it("does not duplicate bare URLs", () => {
|
|
const res = markdownToSlackMrkdwn("see https://example.com");
|
|
expect(res).toBe("see https://example.com");
|
|
});
|
|
|
|
it("escapes unsafe characters", () => {
|
|
const res = markdownToSlackMrkdwn("a & b < c > d");
|
|
expect(res).toBe("a & b < c > d");
|
|
});
|
|
|
|
it("preserves Slack angle-bracket markup (mentions/links)", () => {
|
|
const res = markdownToSlackMrkdwn("hi <@U123> see <https://example.com|docs> and <!here>");
|
|
expect(res).toBe("hi <@U123> see <https://example.com|docs> and <!here>");
|
|
});
|
|
|
|
it("escapes raw HTML", () => {
|
|
const res = markdownToSlackMrkdwn("<b>nope</b>");
|
|
expect(res).toBe("<b>nope</b>");
|
|
});
|
|
|
|
it("renders paragraphs with blank lines", () => {
|
|
const res = markdownToSlackMrkdwn("first\n\nsecond");
|
|
expect(res).toBe("first\n\nsecond");
|
|
});
|
|
|
|
it("renders bullet lists", () => {
|
|
const res = markdownToSlackMrkdwn("- one\n- two");
|
|
expect(res).toBe("• one\n• two");
|
|
});
|
|
|
|
it("renders ordered lists with numbering", () => {
|
|
const res = markdownToSlackMrkdwn("2. two\n3. three");
|
|
expect(res).toBe("2. two\n3. three");
|
|
});
|
|
|
|
it("renders headings as bold text", () => {
|
|
const res = markdownToSlackMrkdwn("# Title");
|
|
expect(res).toBe("*Title*");
|
|
});
|
|
|
|
it("renders blockquotes", () => {
|
|
const res = markdownToSlackMrkdwn("> Quote");
|
|
expect(res).toBe("> Quote");
|
|
});
|
|
|
|
it("handles nested list items", () => {
|
|
const res = markdownToSlackMrkdwn("- item\n - nested");
|
|
// markdown-it correctly parses this as a nested list
|
|
expect(res).toBe("• item\n • nested");
|
|
});
|
|
|
|
it("handles complex message with multiple elements", () => {
|
|
const res = markdownToSlackMrkdwn(
|
|
"**Important:** Check the _docs_ at [link](https://example.com)\n\n- first\n- second",
|
|
);
|
|
expect(res).toBe(
|
|
"*Important:* Check the _docs_ at <https://example.com|link>\n\n• first\n• second",
|
|
);
|
|
});
|
|
});
|