"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.processMusicalNotation = processMusicalNotation; /** * Processes musical notation in HTML content * Wraps musical notation in appropriate HTML for rendering */ function processMusicalNotation(html) { // First, clean up any corrupted abc-notation divs with very long data-abc attributes // These were created by a buggy regex that matched the entire HTML document html = html.replace(/]*class="[^"]*abc-notation[^"]*"[^>]*data-abc="([^"]{500,})"[^>]*>([\s\S]*?)<\/div>/gi, (match, dataAbc, content) => { // This is corrupted - extract just the ABC notation from the beginning let decoded = dataAbc .replace(/</g, '<') .replace(/>/g, '>') .replace(/&/g, '&') .replace(/"/g, '"') .replace(/'/g, "'"); // Find the actual ABC notation (starts with X:) const abcMatch = decoded.match(/^(X:\s*\d+[\s\S]{0,2000}?)(?:\n[^XTCMALK]|<|<\/|sect|div|pre|code)/); if (abcMatch) { const cleanAbc = abcMatch[1].trim(); return `
${content}
`; } // If we can't extract clean ABC, remove the div entirely return content; }); // Clean up code blocks that contain corrupted abc-notation divs inside them // The corrupted structure is:
...
html = html.replace(/]*>]*class="[^"]*language-abc[^"]*"[^>]*>([\s\S]*?)<\/code><\/pre>/gi, (match, codeContent) => { // Check if codeContent contains an abc-notation div with a very long data-abc attribute (>500 chars = corrupted) const longDataAbcMatch = codeContent.match(/]*class="[^"]*abc-notation[^"]*"[^>]*data-abc="([^"]{500,})"/i); if (longDataAbcMatch) { // Extract just the ABC notation from the beginning of the corrupted data-abc value let decoded = longDataAbcMatch[1] .replace(/</g, '<') .replace(/>/g, '>') .replace(/&/g, '&') .replace(/"/g, '"') .replace(/'/g, "'"); // The ABC notation ends where the HTML document starts ( or ) // Extract everything from X: up to (but not including) </code> or </pre> const abcMatch = decoded.match(/^(X:\s*\d+[\s\S]*?)(?=<\/code>|<\/pre>)/); if (abcMatch) { let cleanAbc = abcMatch[1].trim(); // Remove any trailing HTML entities cleanAbc = cleanAbc.replace(/<.*$/, '').trim(); // Validate it's reasonable ABC notation if (cleanAbc.length > 10 && cleanAbc.length < 2000 && cleanAbc.match(/^X:\s*\d+/m)) { // Return clean code block - the processing step will wrap it in abc-notation div return `
${cleanAbc}
`; } } // If extraction fails, just remove the corrupted div and return empty code block // This prevents the corrupted data from being rendered return `
`; } return match; }); // Process ABC notation blocks - ONLY code blocks explicitly marked with language-abc class // These come from: [source,abc], [source, abc], [abc] in AsciiDoc, or ```abc in Markdown // We do NOT auto-detect ABC notation - it must be explicitly marked html = html.replace(/]*>]*class="[^"]*language-abc[^"]*"[^>]*>([\s\S]*?)<\/code><\/pre>/gi, (match, codeContent) => { // Skip if already processed or corrupted if (codeContent.includes('abc-notation') || codeContent.includes('class="abc-notation"') || codeContent.includes('') || codeContent.length > 5000) { return match; } // Extract ABC content from the code block let abcContent = codeContent .replace(/</g, '<') .replace(/>/g, '>') .replace(/&/g, '&') .replace(/"/g, '"') .replace(/'/g, "'") .replace(/'/g, "'") .replace(///g, '/'); // Remove any HTML tags abcContent = abcContent.replace(/<[^>]+>/g, '').trim(); // Only process if it looks like valid ABC notation (starts with X:) // Since this is explicitly marked as ABC, we trust it's ABC notation if (abcContent.match(/^X:\s*\d+/m) && abcContent.length < 3000 && !abcContent.includes(' 200) { break; } abcLines.push(line); if (abcLines.join('\n').length > 2000) { break; } } const cleanAbc = abcLines.join('\n').trim(); if (cleanAbc.match(/^X:\s*\d+/m) && cleanAbc.length > 10 && cleanAbc.length < 2000) { return `
${match}
`; } } return match; }); // Process LilyPond notation blocks const lilypondPattern = /(\\relative[^}]+})/gs; html = html.replace(lilypondPattern, (match) => { const lilypondContent = match.trim(); return `
${lilypondContent}
`; }); // Process inline chord notation: [C], [Am], [F#m7], etc. const chordPattern = /\[([A-G][#b]?m?[0-9]?[^\[\]]*)\]/g; html = html.replace(chordPattern, (match, chord) => { return `[${chord}]`; }); // Process MusicXML-like notation const musicxmlPattern = /(]*>.*?<\/music>)/gs; html = html.replace(musicxmlPattern, (match) => { const musicxmlContent = match.trim(); return `
${musicxmlContent}
`; }); return html; } /** * Escapes a string for use in HTML attributes */ function escapeForAttr(text) { return text .replace(/"/g, '"') .replace(/'/g, ''') .replace(//g, '>') .replace(/\n/g, ' ') .replace(/\r/g, ''); }