mirror of
https://github.com/kdnk/obsidian-automatic-linker.git
synced 2026-07-22 12:00:30 +00:00
fix: restore raw URL helper semantics
Why: Task 5 centralized URL formatting but accidentally changed shared Markdown segmentation and the legacy replaceURLs compatibility path. What: remove angle-bracket autolink protection from shared segmentation, keep angle-bracket and trailing-punctuation handling inside formatURLsInText, and restore replaceURLs to a direct regex replace with linear:// support.
This commit is contained in:
parent
621b15a7a1
commit
3ddcf08538
6 changed files with 122 additions and 16 deletions
|
|
@ -74,12 +74,12 @@ describe("mapMarkdownProse", () => {
|
|||
expect(result).toBe("TS `TypeScript` [[TypeScript]]")
|
||||
})
|
||||
|
||||
it("treats angle-bracket autolinks as protected segments", () => {
|
||||
it("does not globally protect angle-bracket autolinks", () => {
|
||||
const result = mapMarkdownProse(
|
||||
"<https://example.com> https://example.com",
|
||||
text => text.replace(/https:\/\/example\.com/g, "URL"),
|
||||
)
|
||||
|
||||
expect(result).toBe("<https://example.com> URL")
|
||||
expect(result).toBe("<URL> URL")
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -132,7 +132,6 @@ const collectFencedCodeRanges = (text: string): ProtectedRange[] => {
|
|||
const buildProtectedPattern = (protectUrls: boolean): RegExp => {
|
||||
const parts = [
|
||||
"`[^`]*`",
|
||||
"<(?:https?:\\/\\/|linear:\\/\\/)[^>]+>",
|
||||
"\\[\\[[^\\]]+\\]\\]",
|
||||
"\\[[^\\]]+\\]\\([^)]+\\)",
|
||||
"\\[[^\\]]+\\]",
|
||||
|
|
@ -197,7 +196,6 @@ export const segmentMarkdown = (
|
|||
): MarkdownSegment[] => {
|
||||
const mayContainProtectedMarkdown = text.includes("`")
|
||||
|| text.includes("~")
|
||||
|| text.includes("<")
|
||||
|| text.includes("[")
|
||||
|| (options.protectHeadings && text.includes("#"))
|
||||
|| (options.protectCallouts && text.includes(">"))
|
||||
|
|
|
|||
|
|
@ -14,8 +14,7 @@ describe("replace-urls", () => {
|
|||
}
|
||||
|
||||
it("should replace GitHub URLs", () => {
|
||||
const input
|
||||
= "[[github/kdnk/obsidian-automatic-linker]] [🔗](https://github.com/kdnk/obsidian-automatic-linker)"
|
||||
const input = "https://github.com/kdnk/obsidian-automatic-linker"
|
||||
const expected
|
||||
= "[[github/kdnk/obsidian-automatic-linker]] [🔗](https://github.com/kdnk/obsidian-automatic-linker)"
|
||||
expect(replaceURLs(input, baseSettings, formatGitHubURL)).toBe(
|
||||
|
|
@ -39,4 +38,24 @@ describe("replace-urls", () => {
|
|||
),
|
||||
).toBe(expected)
|
||||
})
|
||||
|
||||
it("keeps raw helper semantics inside Markdown links and angle autolinks", () => {
|
||||
const input = [
|
||||
"[label](https://github.com/kdnk/obsidian-automatic-linker)",
|
||||
"<linear://workspace/issue/ACME-123>",
|
||||
].join(" ")
|
||||
|
||||
const expected = [
|
||||
"[label](converted:https://github.com/kdnk/obsidian-automatic-linker)",
|
||||
"<converted:linear://workspace/issue/ACME-123>",
|
||||
].join(" ")
|
||||
|
||||
expect(
|
||||
replaceURLs(
|
||||
input,
|
||||
baseSettings,
|
||||
url => `converted:${url}`,
|
||||
),
|
||||
).toBe(expected)
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -60,6 +60,18 @@ describe("formatURLsInText", () => {
|
|||
].join("\n"))
|
||||
})
|
||||
|
||||
it("does not format GitHub URLs wrapped in angle brackets", () => {
|
||||
const result = formatURLsInText({
|
||||
text: "<https://github.com/owner/repo/issues/123>",
|
||||
settings: {
|
||||
...DEFAULT_SETTINGS,
|
||||
formatGitHubURLs: true,
|
||||
},
|
||||
})
|
||||
|
||||
expect(result).toBe("<https://github.com/owner/repo/issues/123>")
|
||||
})
|
||||
|
||||
it("leaves disabled adapter URLs unchanged", () => {
|
||||
const result = formatURLsInText({
|
||||
text: "https://linear.app/team/issue/BUG-789/title",
|
||||
|
|
@ -72,6 +84,35 @@ describe("formatURLsInText", () => {
|
|||
expect(result).toBe("https://linear.app/team/issue/BUG-789/title")
|
||||
})
|
||||
|
||||
it("leaves Jira URLs with query strings unchanged", () => {
|
||||
const result = formatURLsInText({
|
||||
text: "https://jira.company.com/browse/ABC-456?focusedCommentId=12345",
|
||||
settings: {
|
||||
...DEFAULT_SETTINGS,
|
||||
jiraURLs: ["jira.company.com"],
|
||||
formatJiraURLs: true,
|
||||
},
|
||||
})
|
||||
|
||||
expect(result).toBe(
|
||||
"https://jira.company.com/browse/ABC-456?focusedCommentId=12345",
|
||||
)
|
||||
})
|
||||
|
||||
it("keeps closing parens and trailing punctuation outside formatted URLs", () => {
|
||||
const result = formatURLsInText({
|
||||
text: "See (https://github.com/owner/repo/issues/123).",
|
||||
settings: {
|
||||
...DEFAULT_SETTINGS,
|
||||
formatGitHubURLs: true,
|
||||
},
|
||||
})
|
||||
|
||||
expect(result).toBe(
|
||||
"See ([[github/owner/repo/issues/123]] [🔗](https://github.com/owner/repo/issues/123)).",
|
||||
)
|
||||
})
|
||||
|
||||
it("does not format URLs inside protected Markdown segments", () => {
|
||||
const result = formatURLsInText({
|
||||
text: [
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import { mapMarkdownProse } from "../markdown-segments"
|
||||
import { AutomaticLinkerSettings } from "../settings/settings-info"
|
||||
|
||||
const URL_PATTERN = /(?:https?:\/\/|linear:\/\/)[^\s<>\]]+/g
|
||||
|
|
@ -7,8 +6,4 @@ export const replaceURLs = (
|
|||
fileContent: string,
|
||||
settings: AutomaticLinkerSettings,
|
||||
formatter: (url: string, settings: AutomaticLinkerSettings) => string,
|
||||
) =>
|
||||
mapMarkdownProse(
|
||||
fileContent,
|
||||
prose => prose.replace(URL_PATTERN, match => formatter(match, settings)),
|
||||
)
|
||||
) => fileContent.replace(URL_PATTERN, match => formatter(match, settings))
|
||||
|
|
|
|||
|
|
@ -26,6 +26,48 @@ const formatJiraURLIfEnabled: UrlFormatter = (url, settings) =>
|
|||
const formatLinearURLIfEnabled: UrlFormatter = (url, settings) =>
|
||||
settings.formatLinearURLs ? formatLinearURL(url, settings) : url
|
||||
|
||||
const TRAILING_PUNCTUATION = new Set([".", ",", ";", "!", "?", "]", "}"])
|
||||
|
||||
const countCharacter = (text: string, character: string): number => {
|
||||
let count = 0
|
||||
|
||||
for (const currentCharacter of text) {
|
||||
if (currentCharacter === character) {
|
||||
count += 1
|
||||
}
|
||||
}
|
||||
|
||||
return count
|
||||
}
|
||||
|
||||
const splitTrailingBoundary = (match: string): { url: string, suffix: string } => {
|
||||
let url = match
|
||||
let suffix = ""
|
||||
|
||||
while (url.length > 0) {
|
||||
const lastCharacter = url[url.length - 1]
|
||||
|
||||
if (TRAILING_PUNCTUATION.has(lastCharacter)) {
|
||||
suffix = lastCharacter + suffix
|
||||
url = url.slice(0, -1)
|
||||
continue
|
||||
}
|
||||
|
||||
if (
|
||||
lastCharacter === ")"
|
||||
&& countCharacter(url, "(") < countCharacter(url, ")")
|
||||
) {
|
||||
suffix = lastCharacter + suffix
|
||||
url = url.slice(0, -1)
|
||||
continue
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
return { url, suffix }
|
||||
}
|
||||
|
||||
export const DEFAULT_URL_FORMATTERS: readonly UrlFormatter[] = [
|
||||
formatGitHubURLIfEnabled,
|
||||
formatJiraURLIfEnabled,
|
||||
|
|
@ -54,8 +96,19 @@ export const formatURLsInText = ({
|
|||
}: FormatURLsInTextOptions): string =>
|
||||
mapMarkdownProse(
|
||||
text,
|
||||
prose =>
|
||||
prose.replace(URL_PATTERN, match =>
|
||||
formatURLWithAdapters(match, settings, formatters),
|
||||
),
|
||||
(prose, segment) =>
|
||||
prose.replace(URL_PATTERN, (match, offset) => {
|
||||
const precedingCharacter = offset > 0
|
||||
? segment.text[offset - 1]
|
||||
: undefined
|
||||
const followingCharacter = segment.text[offset + match.length]
|
||||
|
||||
if (precedingCharacter === "<" && followingCharacter === ">") {
|
||||
return match
|
||||
}
|
||||
|
||||
const { url, suffix } = splitTrailingBoundary(match)
|
||||
|
||||
return formatURLWithAdapters(url, settings, formatters) + suffix
|
||||
}),
|
||||
)
|
||||
|
|
|
|||
Loading…
Reference in a new issue