Browse Source

Fix wikilink parsing: use placeholder format to prevent AsciiDoc interference

- Changed wikilink format from wikilink:dtag[display] to WIKILINK:dtag|display
- This prevents AsciiDoc from misinterpreting the brackets
- Updated HTML post-processing to generate proper wikilink HTML with correct classes and URLs
- Added linkBaseURL support to post-processing for proper URL generation
master
Silberengel 2 weeks ago
parent
commit
80087046be
  1. 7
      src/converters/to-asciidoc.ts
  2. 2
      src/processors/asciidoc.ts
  3. 23
      src/processors/html-postprocess.ts

7
src/converters/to-asciidoc.ts

@ -233,7 +233,7 @@ function normalizeDtag(text: string): string {
/** /**
* Processes wikilinks: [[target]] or [[target|display text]] * Processes wikilinks: [[target]] or [[target|display text]]
* Converts to wikilink:dtag[display] format * Converts to WIKILINK: placeholder format to protect from AsciiDoc processing
*/ */
function processWikilinks(content: string, linkBaseURL: string): string { function processWikilinks(content: string, linkBaseURL: string): string {
// Process bookstr macro wikilinks: [[book::...]] // Process bookstr macro wikilinks: [[book::...]]
@ -243,12 +243,15 @@ function processWikilinks(content: string, linkBaseURL: string): string {
}); });
// Process standard wikilinks: [[Target Page]] or [[target page|see this]] // Process standard wikilinks: [[Target Page]] or [[target page|see this]]
// Use placeholder format to prevent AsciiDoc from processing the brackets
content = content.replace(/\[\[([^|\]]+)(?:\|([^\]]+))?\]\]/g, (_match, target, displayText) => { content = content.replace(/\[\[([^|\]]+)(?:\|([^\]]+))?\]\]/g, (_match, target, displayText) => {
const cleanTarget = target.trim(); const cleanTarget = target.trim();
const cleanDisplay = displayText ? displayText.trim() : cleanTarget; const cleanDisplay = displayText ? displayText.trim() : cleanTarget;
const dTag = normalizeDtag(cleanTarget); const dTag = normalizeDtag(cleanTarget);
return `wikilink:${dTag}[${cleanDisplay}]`; // Use placeholder format: WIKILINK:dtag|display
// This prevents AsciiDoc from interpreting the brackets
return `WIKILINK:${dTag}|${cleanDisplay}`;
}); });
return content; return content;

2
src/processors/asciidoc.ts

@ -92,6 +92,7 @@ export async function processAsciidoc(
// Post-process HTML: convert macros to HTML, add styling, etc. // Post-process HTML: convert macros to HTML, add styling, etc.
const processed = postProcessHtml(sanitized, { const processed = postProcessHtml(sanitized, {
enableMusicalNotation, enableMusicalNotation,
linkBaseURL: options.linkBaseURL,
}); });
// Process links: add target="_blank" to external links // Process links: add target="_blank" to external links
@ -103,6 +104,7 @@ export async function processAsciidoc(
const tocSanitized = sanitizeHTML(toc); const tocSanitized = sanitizeHTML(toc);
const tocProcessed = postProcessHtml(tocSanitized, { const tocProcessed = postProcessHtml(tocSanitized, {
enableMusicalNotation: false, // Don't process music in TOC enableMusicalNotation: false, // Don't process music in TOC
linkBaseURL: options.linkBaseURL,
}); });
// Process links in TOC as well // Process links in TOC as well

23
src/processors/html-postprocess.ts

@ -2,6 +2,7 @@ import { processMusicalNotation } from './music';
export interface PostProcessOptions { export interface PostProcessOptions {
enableMusicalNotation?: boolean; enableMusicalNotation?: boolean;
linkBaseURL?: string;
} }
/** /**
@ -31,11 +32,23 @@ export function postProcessHtml(html: string, options: PostProcessOptions = {}):
return `<a href="/notes?t=${encodedHashtag}" class="hashtag-link text-green-600 dark:text-green-400 hover:text-green-700 dark:hover:text-green-300 hover:underline">${escapedDisplay}</a>`; return `<a href="/notes?t=${encodedHashtag}" class="hashtag-link text-green-600 dark:text-green-400 hover:text-green-700 dark:hover:text-green-300 hover:underline">${escapedDisplay}</a>`;
}); });
// Convert wikilink:dtag[display] format to HTML // Convert WIKILINK:dtag|display placeholder format to HTML
processed = processed.replace(/wikilink:([^[]+)\[([^\]]+)\]/g, (_match, dTag, displayText) => { // Match WIKILINK:dtag|display, ensuring we don't match across HTML tags
const escapedDtag = dTag.replace(/"/g, '&quot;'); processed = processed.replace(/WIKILINK:([^|<>]+)\|([^<>\s]+)/g, (_match, dTag, displayText) => {
const escapedDisplay = displayText.replace(/"/g, '&quot;'); const escapedDtag = dTag.trim().replace(/"/g, '&quot;');
return `<span class="wikilink cursor-pointer text-blue-600 hover:text-blue-800 hover:underline border-b border-dotted border-blue-300" data-dtag="${escapedDtag}" data-display="${escapedDisplay}">${displayText}</span>`; const escapedDisplay = displayText.trim()
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;');
// Generate the proper URL using linkBaseURL if available
const url = options.linkBaseURL
? `${options.linkBaseURL}/events?d=${escapedDtag}`
: `#${escapedDtag}`;
return `<a class="wikilink text-primary-600 dark:text-primary-500 hover:underline" data-dtag="${escapedDtag}" data-url="${url}" href="${url}">${escapedDisplay}</a>`;
}); });
// Convert nostr: links to HTML // Convert nostr: links to HTML

Loading…
Cancel
Save