diff --git a/Core.js b/Core.js index e2df6d8..131320e 100644 --- a/Core.js +++ b/Core.js @@ -1,5 +1,5 @@ /** - * SimonUp Core Compiler (Core.js) - Version 1.2b.001 + * SimonUp Core Compiler (Core.js) - Version 1.2.3 * Eine moderne, fluss- und blockorientierte Auszeichnungssprache. */ class SimonUp { @@ -34,7 +34,7 @@ class SimonUp { } } - // Phase 1: Blöcke und Inline-Strukturen parsen (sammelt alle Überschriften) + // Phase 1: Blöcke und Inline-Strukturen parsen html = this._parseBlocks(html); // Phase 2: Das Inhaltsverzeichnis nachträglich in die vorbereitete Box einsetzen @@ -82,7 +82,7 @@ class SimonUp { continue; } - // Block-Ende erkennen mit /& (Spezifikation V1.2b) + // Block-Ende erkennen mit /& if (inBlock && line.trim().replace(/\u00A0/g, ' ') === '/&') { result.push(this._renderBlock(blockType, blockMeta, blockBuffer)); inBlock = false; @@ -111,6 +111,11 @@ class SimonUp { } } + // Automatischer Schutz: Falls am Dateiende ein Block nicht geschlossen wurde + if (inBlock && blockBuffer.length > 0) { + result.push(this._renderBlock(blockType, blockMeta, blockBuffer)); + } + return this._processParagraphsAndLists(result); } @@ -168,7 +173,7 @@ class SimonUp { } /** - * INTERN: Robustes Rendern von Multi-line-Tabellen und Galerien (V1.2b) + * INTERN: Robustes Rendern von Multi-line-Tabellen und Galerien */ _renderTable(meta, lines) { let tableHtml = '\n'; @@ -213,7 +218,7 @@ class SimonUp { } /** - * INTERN: Verarbeitet Fluss-Formatierungen (Inline) + * INTERN: Verarbeitet Fluss-Formatierungen (Inline) ohne HTML-Zerstörung */ _parseInline(text) { if (!text) return ''; @@ -225,9 +230,7 @@ class SimonUp { return `__ESCAPED_CHAR_${escapes.length - 1}__`; }); - html = html.replace(/\/\/(( \s|$))/g, '$1'); - - // Überschriften-Parsing via .replace() zur Verhinderung von Index-Shifts + // 1. Überschriften ERST parsen (bevor HTML-Tags im Fluss entstehen) html = html.replace(/^([1-6])x#\s*(.*)/gm, (match, level, titleAndRest) => { let { title, rest } = this._extractHeadingRest(titleAndRest); const numStr = this._getAutoNumber(parseInt(level)); @@ -249,15 +252,40 @@ class SimonUp { return `${title}${rest}`; }); - // Kritische Doppel-Sterne (fett) - html = html.replace(/\*\*(.+?)\\\*\*/g, '$1'); - html = html.replace(/\*\*(.+?)(?=\*\*|$)/g, '$1'); + // Medien & Links verarbeiten + html = html.replace(/!\[([^\]]+)\s+w:(\d+)\]\(([^)]+)\)/g, '$1'); + html = html.replace(/!\[([^\]]+)\]\(([^)]+)\)/g, '$1'); + html = html.replace(/\[([^\]]+)\]\{([^}]+)\}/g, '$1'); + html = html.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '$1'); - // Einzelne Sternchen (medium) - html = html.replace(/\*(.+?)\\\*/g, '$1'); - html = html.replace(/\*(.+?)(?=\*|$)/g, '$1'); + // Hilfsfunktion: Führt Ersetzungen nur AUSSERHALB von HTML-Tags <...> aus + const replaceOutsideTags = (regex, replacement) => { + const masterRegex = new RegExp(/(<[^>]+>)/g.source + '|' + regex.source, 'g'); + html = html.replace(masterRegex, (match, p1) => { + if (p1) return p1; // HTML-Tags überspringen + + const innerMatch = regex.exec(match); + if (innerMatch) { + if (typeof replacement === 'function') { + return replacement(...innerMatch); + } + let res = replacement; + for (let idx = 1; idx < innerMatch.length; idx++) { + res = res.replace(new RegExp('\\$' + idx, 'g'), innerMatch[idx]); + } + return res; + } + return match; + }); + }; - // Standard Text-Inline-Rules + // 2. Formatierung für FETT (**text/** oder **text/) + replaceOutsideTags(/\*\*(.+?)(?:\/\*\*|\/|\*\*|$)/, '$1'); + + // 3. Formatierung für MEDIUM (*text/* oder *text/) + replaceOutsideTags(/\*(.+?)(?:\/\*|\/|\*|$)/, '$1'); + + // 4. Standard Text-Inline-Rules via Symbol-Paar/Slash-Abschluss const inlineRules = [ { tag: 'em', symbol: '%' }, { tag: 'u', symbol: '_' }, @@ -272,24 +300,16 @@ class SimonUp { let rule = inlineRules[k]; let tagSimple = rule.tag.split(' ')[0]; - let regex = new RegExp(rule.symbol + '(.+?)\\\\' + rule.symbol, 'g'); - html = html.replace(regex, `<${rule.tag}>$1`); - - let resetRegex = new RegExp(rule.symbol + '(.+?)(?=' + rule.symbol + '|$)', 'g'); - html = html.replace(resetRegex, `<${rule.tag}>$1`); + // Unterstützt %text/% sowie das Fallback %text am Zeilenende + replaceOutsideTags(new RegExp(rule.symbol + '(.+?)(?:\\/' + rule.symbol + '|\\/|' + rule.symbol + '|$)'), `<${rule.tag}>$1`); } - // Ausrichtungen, Links, Medien + // Ausrichtungen & Fußnoten const alignMap = { 'l': 'left', 'r': 'right', 'c': 'center', 'j': 'justify' }; html = html.replace(/>([lrcj])\s+(.+?)\s*\/>/g, function(m, dir, content) { return `
${content}
`; }); - html = html.replace(/!\[([^\]]+)\s+w:(\d+)\]\(([^)]+)\)/g, '$1'); - html = html.replace(/!\[([^\]]+)\]\(([^)]+)\)/g, '$1'); - html = html.replace(/\[([^\]]+)\]\{([^}]+)\}/g, '$1'); - html = html.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '$1'); - html = html.replace(/\^x\[([^\]]+)\]\^x/g, '[*]'); html = html.replace(/\^(\d+)\[([^\]]+)\]\^x/g, '[$1]'); @@ -418,7 +438,7 @@ class SimonUp { } currentListType = type; listBuffer.push(content); - } else if (element.startsWith("<") && !/^(||||||||||||||||||||||