Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -74,4 +74,23 @@ describe("sanitizeChangelogEntry", () => {
const expected = "Added `Optional<String>` support.\nAlso changed `Map<String, Object>` handling.";
expect(sanitizeChangelogEntry(input)).toBe(expected);
});

it("does not double-wrap types inside backtick spans after a fenced code block", () => {
const input =
"Intro text.\n\n```java\nws.connect();\n```\n\n**Generic `onMessage(Consumer<String>)` handler** fires.";
const expected =
"Intro text.\n\n```java\nws.connect();\n```\n\n**Generic `onMessage(Consumer<String>)` handler** fires.";
expect(sanitizeChangelogEntry(input)).toBe(expected);
});

it("preserves fenced code blocks verbatim", () => {
const input = "Before.\n\n```java\nList<String> items = new ArrayList<String>();\n```\n\nAfter.";
expect(sanitizeChangelogEntry(input)).toBe(input);
});

it("wraps types outside a code fence but not inside", () => {
const input = "Use Optional<String>.\n\n```java\nOptional<String> x;\n```\n\nAlso Map<String, Object>.";
const expected = "Use `Optional<String>`.\n\n```java\nOptional<String> x;\n```\n\nAlso `Map<String, Object>`.";
expect(sanitizeChangelogEntry(input)).toBe(expected);
});
});
23 changes: 22 additions & 1 deletion packages/commons/core-utils/src/sanitizeChangelogEntry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,30 @@
* Already-backticked spans are left untouched.
*/
export function sanitizeChangelogEntry(entry: string): string {
// First, split on triple-backtick fenced code blocks so they are never
// processed by the inline-backtick logic (which only understands single
// backtick pairs and gets confused by the three-backtick delimiters).
const fenceParts = entry.split(/(```[^\n]*\n[\s\S]*?\n```)/g);
return fenceParts
.map((part) => {
// Fenced code blocks are preserved verbatim.
if (part.startsWith("```") && part.endsWith("```")) {
return part;
}
return sanitizeInlinePart(part);
})
.join("");
}

/**
* Processes a text segment that is outside any fenced code block.
* Splits on single-backtick inline code spans and only applies
* angle-bracket wrapping to plain-text segments.
*/
function sanitizeInlinePart(text: string): string {
// Split the text into alternating segments: plain text and backtick-delimited code spans.
// Odd-indexed segments are inside backticks and must be preserved as-is.
const parts = entry.split(/(`[^`]+`)/g);
const parts = text.split(/(`[^`]+`)/g);
return parts
.map((part) => {
// If this part is a code span, leave it as-is
Expand Down
Loading