fix(markdown): preserve table context after wikilink rewrites

Why: resolved wikilink rewrites can shift segment offsets before the prose pass that decides whether a row is inside a markdown table, which breaks alias escaping in table links. Angle-bracket autolinks also need to stay untouched when URL titles are available.

What: use the rewritten body when checking table context in the second prose-mapping pass, and skip URL-title replacement when a matched URL is wrapped in angle brackets. Add regression tests for both cases.
This commit is contained in:
Kodai Nakamura 2026-06-22 03:13:34 +09:00
parent db05c2ee1f
commit 29582da575
4 changed files with 50 additions and 4 deletions

View file

@ -108,6 +108,35 @@ note1
| Test Item | |
| --- | --- |
| [[note1]] | |
`)
})
it("escapes table aliases after earlier resolved wikilinks change segment offsets", () => {
const settings = {
scoped: false,
baseDir: undefined,
proximityBasedLinking: true,
}
const { candidateMap, trie } = buildCandidateTrieForTest({
files: [{ path: "ns/note1" }],
settings,
})
const result = replaceLinks({
body: `[[note1]]
| note1 | |
`,
linkResolverContext: {
filePath: "journals/2022-01-01",
trie,
candidateMap,
},
settings,
resolvedAmbiguities: new Map([
["[[note1]]", "very/long/path/note1|note1"],
]),
})
expect(result).toBe(`[[very/long/path/note1|note1]]
| [[ns/note1\\|note1]] | |
`)
})
})

View file

@ -647,6 +647,7 @@ export const replaceLinks = ({
// Get the current namespace
const currentNamespace = getCurrentNamespace(filePath, settings.baseDir)
let bodyWithResolvedWikilinks = body
const markdownOptions = {
protectHeadings: settings.ignoreHeadings,
@ -723,7 +724,7 @@ export const replaceLinks = ({
): string => {
if (!text.includes("\n")) {
const isInTable = !settings.ignoreMarkdownTables
&& isIndexInsideMarkdownTable(body, segment.start)
&& isIndexInsideMarkdownTable(bodyWithResolvedWikilinks, segment.start)
return processTextSegment(text, isInTable)
}
@ -742,13 +743,12 @@ export const replaceLinks = ({
const absoluteIndex = segment.start + offset
const isInTable = !settings.ignoreMarkdownTables
&& isIndexInsideMarkdownTable(body, absoluteIndex)
&& isIndexInsideMarkdownTable(bodyWithResolvedWikilinks, absoluteIndex)
return processTextSegment(line, isInTable)
})
}
let bodyWithResolvedWikilinks = body
if (resolvedAmbiguities) {
bodyWithResolvedWikilinks = segmentMarkdown(body, markdownOptions)
.map((segment) => {

View file

@ -76,4 +76,17 @@ describe("replaceUrlWithTitle", () => {
})
expect(result).toBe("~~~\nhttps://example.com\n~~~")
})
it("should not replace angle-bracket autolinks", () => {
const body = "<https://example.com>"
const result = replaceUrlWithTitle({
body,
urlTitleMap: new Map(
Object.entries({
"https://example.com": "Example Title",
}),
),
})
expect(result).toBe("<https://example.com>")
})
})

View file

@ -50,8 +50,12 @@ export const replaceUrlWithTitle = ({
nextOccurrence - 2,
nextOccurrence,
)
const precedingChar = resultBody[nextOccurrence - 1]
const followingChar = resultBody[nextOccurrence + url.length]
if (precedingChars === "](" && followingChar === ")") {
if (
(precedingChars === "](" && followingChar === ")")
|| (precedingChar === "<" && followingChar === ">")
) {
shouldReplace = false
}