@noirmd/previewer 1.1.0 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/core.cjs CHANGED
@@ -124,7 +124,7 @@ function parseHtmlAttrs(attrsString) {
124
124
  // core/parser.ts
125
125
  function parseMarkdown(markdown) {
126
126
  if (!markdown) return [];
127
- const lines = markdown.split("\n");
127
+ const lines = markdown.replace(/\r\n/g, "\n").replace(/\r/g, "").split("\n");
128
128
  const result = [];
129
129
  let i = 0;
130
130
  while (i < lines.length) {
package/dist/core.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../core.ts","../core/utils.ts","../core/parser.ts"],"sourcesContent":["// ============================================================\r\n// @noirmd/previewer/core — Framework-agnostic entry point\r\n//\r\n// Usage:\r\n// import { parseMarkdown, Token } from '@noirmd/previewer/core';\r\n//\r\n// This module has ZERO dependency on React (or any UI framework).\r\n// ============================================================\r\n\r\nexport {\r\n parseMarkdown,\r\n type Token,\r\n type CSSProperties,\r\n type HeaderToken,\r\n type ParagraphToken,\r\n type CodeblockToken,\r\n type DirectiveToken,\r\n type HtmlToken,\r\n type HtmlBlockToken,\r\n type ImageToken,\r\n type TableToken,\r\n type ListToken,\r\n type BlockquoteToken,\r\n type HrToken,\r\n type TocToken,\r\n parseCssString,\r\n generateId,\r\n generateScopeId,\r\n resetScopeCounter,\r\n scrollToId,\r\n extractAttributes,\r\n parseProps,\r\n parseHtmlAttrs,\r\n} from './core/index';\r\n","import type { CSSProperties } from './types';\r\n\r\n/**\r\n * Parse an inline CSS string (e.g. \"color: red; padding: 1rem\") into a CSSProperties object.\r\n */\r\nexport function parseCssString(cssText: string): CSSProperties {\r\n if (!cssText) return {};\r\n return cssText\r\n .split(';')\r\n .filter(Boolean)\r\n .reduce<CSSProperties>((styleObj, styleString) => {\r\n const parts = styleString.split(':');\r\n if (parts.length < 2) return styleObj;\r\n const key = parts[0].trim().replace(/-([a-z])/g, (_, g) => g.toUpperCase());\r\n const value = parts.slice(1).join(':').trim();\r\n styleObj[key] = value;\r\n return styleObj;\r\n }, {});\r\n}\r\n\r\n/**\r\n * Generate a URL-safe slug from text (NFD decomposition, strip accents, lowercase, hyphenate).\r\n */\r\nexport function generateId(text: string): string {\r\n return text\r\n .normalize('NFD')\r\n .replace(/[\\u0300-\\u036f]/g, '')\r\n .toLowerCase()\r\n .replace(/[^\\w\\s-]/g, '')\r\n .replace(/\\s+/g, '-');\r\n}\r\n\r\n/**\r\n * Smooth-scroll to an element by its ID.\r\n */\r\nexport function scrollToId(id: string): void {\r\n if (typeof document === 'undefined') return;\r\n const element = document.getElementById(id);\r\n if (element) {\r\n element.scrollIntoView({ behavior: 'smooth', block: 'start' });\r\n }\r\n}\r\n\r\n/**\r\n * Parse attribute suffix like `##{.my-class #my-id}` from a text line.\r\n * Returns the cleaned text, extracted classes, and id.\r\n */\r\nexport function extractAttributes(text: string): { text: string; classes: string; id: string } {\r\n const match = text.match(/^(.*?)\\s*##\\{([^}]*)\\}\\s*$/);\r\n if (!match) return { text, classes: '', id: '' };\r\n\r\n const rawAttrs = match[2];\r\n const cleanedText = match[1];\r\n\r\n const classList: string[] = [];\r\n let id = '';\r\n\r\n // 1. Parse key=\"value\" attributes (e.g., class=\"mt-0 px-4\", id=\"section\")\r\n for (const [, key, value] of rawAttrs.matchAll(/([\\w-]+)=\"([^\"]*)\"/g)) {\r\n if (key === 'class') {\r\n classList.push(...value.split(/\\s+/).filter(Boolean));\r\n } else if (key === 'id') {\r\n id = value;\r\n }\r\n }\r\n\r\n // 2. Parse shorthand tokens: .className and #id (from remaining content)\r\n // Supports classes with / (opacity), ! (important), . (arbitrary values)\r\n const stripped = rawAttrs.replace(/[\\w-]+=\"[^\"]*\"/g, '');\r\n for (const token of stripped.split(/\\s+/).filter(Boolean)) {\r\n if (token.startsWith('.')) classList.push(token.slice(1));\r\n else if (token.startsWith('#') && !id) id = token.slice(1);\r\n }\r\n\r\n return { text: cleanedText, classes: classList.join(' '), id };\r\n}\r\n\r\nlet _scopeCounter = 0;\r\nexport function resetScopeCounter(): void {\r\n _scopeCounter = 0;\r\n}\r\n\r\n/**\r\n * Generate a unique scope ID for CSS isolation.\r\n */\r\nexport function generateScopeId(): string {\r\n return `scope-${++_scopeCounter}`;\r\n}\r\n\r\n/**\r\n * Parse props from a `{key=\"value\" key2=\"value2\"}` string.\r\n * Also supports `.className` shorthand → adds to `class` prop.\r\n * Also supports `#id` shorthand → adds to `id` prop.\r\n */\r\nexport function parseProps(propsString: string): Record<string, string> {\r\n const props: Record<string, string> = {};\r\n if (!propsString?.trim()) return props;\r\n\r\n // Match key=\"value\" or key='value' pairs\r\n const pairRegex = /(\\w[\\w-]*)=(?:\"([^\"]*)\"|'([^']*)')/g;\r\n let match;\r\n while ((match = pairRegex.exec(propsString)) !== null) {\r\n const key = match[1];\r\n const value = match[2] ?? match[3] ?? '';\r\n props[key] = value;\r\n }\r\n\r\n // Extract .className shorthand (supports / for opacity, ! for important, . for arbitrary values)\r\n const classMatches = propsString.match(/\\.([a-zA-Z0-9_!/.\\-]+)/g);\r\n if (classMatches) {\r\n const existing = props['class'] || '';\r\n const newClasses = classMatches.map(c => c.substring(1)).join(' ');\r\n props['class'] = existing ? `${existing} ${newClasses}` : newClasses;\r\n }\r\n\r\n // Extract #id shorthand (only if not inside a key=\"value\" pair)\r\n const idMatch = propsString.match(/#([a-zA-Z0-9_-]+)(?=\\s|}|$)/);\r\n if (idMatch && !props['id']) {\r\n props['id'] = idMatch[1];\r\n }\r\n\r\n return props;\r\n}\r\n\r\n/**\r\n * Parse raw HTML attributes string (e.g. `class=\"...\" style=\"...\" data-foo=\"...\"`)\r\n * into a plain props object.\r\n *\r\n * NOTE: This does NOT rename `class` → `className`. Framework adapters\r\n * (React, Vue, etc.) should handle their own attribute name mapping.\r\n */\r\nexport function parseHtmlAttrs(attrsString: string): Record<string, any> {\r\n const props: Record<string, any> = {};\r\n if (!attrsString?.trim()) return props;\r\n\r\n const pairRegex = /([a-zA-Z0-9_-]+)(?:=(?:\"([^\"]*)\"|'([^']*)'|([^\\s>]+)))?/g;\r\n let match;\r\n while ((match = pairRegex.exec(attrsString)) !== null) {\r\n const key = match[1];\r\n const value = match[2] ?? match[3] ?? match[4] ?? true;\r\n\r\n // Parse style strings into objects\r\n if (key === 'style' && typeof value === 'string') {\r\n props[key] = parseCssString(value);\r\n } else {\r\n props[key] = value;\r\n }\r\n }\r\n\r\n return props;\r\n}\r\n","import type { Token, DirectiveToken, HtmlBlockToken, CSSProperties } from './types';\r\nimport { generateId, generateScopeId, parseProps, extractAttributes } from './utils';\r\n\r\n/**\r\n * V2 Markdown Parser — line-by-line state machine (framework-agnostic).\r\n */\r\nexport function parseMarkdown(markdown: string): Token[] {\r\n if (!markdown) return [];\r\n const lines = markdown.split('\\n');\r\n const result: Token[] = [];\r\n let i = 0;\r\n\r\n while (i < lines.length) {\r\n const line = lines[i];\r\n const trimmed = line.trim();\r\n let match: RegExpMatchArray | null;\r\n\r\n // ── Headers: ## Title ──\r\n if ((match = trimmed.match(/^(#{1,6})\\s+(.+)$/))) {\r\n const level = match[1].length;\r\n const rawText = match[2];\r\n const { text, classes, id: customId } = extractAttributes(rawText);\r\n const id = customId || generateId(text.replace(/->|<-/g, ''));\r\n result.push({ type: 'header', level, text, id, classes: classes || undefined });\r\n i++;\r\n continue;\r\n }\r\n\r\n // ── Aligned paragraph: -> text <- or -> text -> ──\r\n if ((match = trimmed.match(/^->\\s*(.+?)\\s*(<-|->)\\s*$/))) {\r\n const content = match[1];\r\n const align = match[2] === '<-' ? 'center' : 'right';\r\n result.push({ type: 'paragraph', content, align });\r\n i++;\r\n continue;\r\n }\r\n\r\n // ── Code block: ```lang title=\"name\" ──\r\n if (trimmed.startsWith('```')) {\r\n const fenceHeader = trimmed.slice(3).trim();\r\n const titleMatch = fenceHeader.match(/title=[\"']([^\"']*)[\"']/);\r\n const lang = fenceHeader.replace(/title=[\"'][^\"']*[\"']/, '').trim();\r\n const title = titleMatch ? titleMatch[1] : undefined;\r\n const content: string[] = [];\r\n i++;\r\n while (i < lines.length && !lines[i].trim().startsWith('```')) {\r\n content.push(lines[i]);\r\n i++;\r\n }\r\n result.push({ type: 'codeblock', language: lang, title, content: content.join('\\n') });\r\n i++; // skip closing ```\r\n continue;\r\n }\r\n\r\n // ── Directive: :::type {props} ... ::: ──\r\n if (trimmed.startsWith(':::')) {\r\n const rest = trimmed.slice(3).trim();\r\n\r\n // Bare closing marker\r\n if (rest === '') {\r\n result.push({ type: 'paragraph', content: line });\r\n i++;\r\n continue;\r\n }\r\n\r\n const typeMatch = rest.match(/^([\\w-]+)/);\r\n const directiveType = typeMatch ? typeMatch[1] : 'custom';\r\n\r\n // Lookahead: find the matching closing :::\r\n let j = i + 1;\r\n let nestedLevel = 0;\r\n let foundClose = false;\r\n\r\n while (j < lines.length) {\r\n const currentTrimmed = lines[j].trim();\r\n if (currentTrimmed === ':::') {\r\n if (nestedLevel === 0) {\r\n foundClose = true;\r\n break;\r\n } else {\r\n nestedLevel--;\r\n }\r\n } else if (currentTrimmed.startsWith(':::')) {\r\n // Opening a nested directive\r\n nestedLevel++;\r\n }\r\n j++;\r\n }\r\n\r\n if (foundClose) {\r\n // Collect raw content lines (between opening and closing)\r\n const contentLines: string[] = [];\r\n for (let k = i + 1; k < j; k++) {\r\n contentLines.push(lines[k]);\r\n }\r\n const rawContent = contentLines.join('\\n');\r\n\r\n // Parse the directive header (everything after the type name)\r\n const headerRest = typeMatch ? rest.slice(directiveType.length).trim() : rest;\r\n\r\n // Extract {props} block\r\n let propsString = '';\r\n let shortForm = '';\r\n const propsBlockMatch = headerRest.match(/^\\{([^]*)\\}\\s*$/);\r\n if (propsBlockMatch) {\r\n propsString = propsBlockMatch[1];\r\n } else if (headerRest) {\r\n // Short-form: bare text after type → becomes title prop\r\n shortForm = headerRest;\r\n }\r\n\r\n const props = parseProps(propsString);\r\n if (shortForm && !props['title']) {\r\n props['title'] = shortForm;\r\n }\r\n\r\n // Split content into slots\r\n const slots = splitSlots(rawContent);\r\n\r\n result.push({\r\n type: 'directive',\r\n directiveType,\r\n props,\r\n slots,\r\n scopeId: generateScopeId(),\r\n } as DirectiveToken);\r\n\r\n i = j + 1;\r\n continue;\r\n } else {\r\n // Unclosed directive — render as plain text\r\n result.push({ type: 'paragraph', content: line });\r\n i++;\r\n continue;\r\n }\r\n }\r\n\r\n // ── Image: ![alt](src#float#3d){w:h} ──\r\n if ((match = trimmed.match(/^(.*?)!\\[([^\\]]*)\\]\\(([^)]+?)\\)(?:\\{([^}]+?)\\})?(.*)$/))) {\r\n const [, preText, alt, srcAndFloat, size, postText] = match;\r\n\r\n if (preText.trim()) {\r\n result.push({ type: 'paragraph', content: preText.trim() });\r\n }\r\n\r\n let src = srcAndFloat;\r\n const style: CSSProperties = {};\r\n if (src.includes('#left')) {\r\n src = src.replace('#left', '');\r\n style.float = 'left';\r\n style.margin = '0 1em 1em 0';\r\n } else if (src.includes('#right')) {\r\n src = src.replace('#right', '');\r\n style.float = 'right';\r\n style.margin = '0 0 1em 1em';\r\n } else if (src.includes('#center')) {\r\n src = src.replace('#center', '');\r\n style.display = 'block';\r\n style.margin = '0 auto 1em auto';\r\n }\r\n if (size) {\r\n const [width, height] = size.split(':');\r\n if (width) style.width = width.trim();\r\n if (height) style.height = height.trim();\r\n }\r\n result.push({ type: 'image', alt, src, style });\r\n\r\n if (postText.trim()) {\r\n result.push({ type: 'paragraph', content: postText.trim() });\r\n }\r\n i++;\r\n continue;\r\n }\r\n\r\n // ── Table: | cell | cell | ──\r\n if (trimmed.includes('|') && i + 1 < lines.length && lines[i + 1].includes('---')) {\r\n const tableLines = [line];\r\n i++;\r\n tableLines.push(lines[i]);\r\n i++;\r\n while (i < lines.length && lines[i].trim().includes('|')) {\r\n tableLines.push(lines[i]);\r\n i++;\r\n }\r\n result.push({ type: 'table', content: tableLines.join('\\n') });\r\n continue;\r\n }\r\n\r\n // ── List: - item or 1. item ──\r\n if ((match = trimmed.match(/^(\\s*)([-*+]|\\d+\\.)\\s+(.+)$/))) {\r\n const listItems = [line];\r\n i++;\r\n while (i < lines.length) {\r\n const nextLine = lines[i];\r\n const nextTrimmed = nextLine.trim();\r\n if (\r\n nextTrimmed.match(/^(\\s*)([-*+]|\\d+\\.)\\s+(.+)$/) ||\r\n nextTrimmed === '' ||\r\n nextLine.startsWith(' ')\r\n ) {\r\n listItems.push(nextLine);\r\n i++;\r\n } else {\r\n break;\r\n }\r\n }\r\n result.push({ type: 'list', content: listItems.join('\\n') });\r\n continue;\r\n }\r\n\r\n // ── Blockquote: > text ──\r\n if (trimmed.startsWith('>')) {\r\n const quoteLines = [line];\r\n i++;\r\n while (i < lines.length && (lines[i].trim().startsWith('>') || lines[i].trim() === '')) {\r\n quoteLines.push(lines[i]);\r\n i++;\r\n }\r\n const rawQuote = quoteLines.join('\\n').replace(/^>\\s?/gm, '');\r\n const { text, classes, id } = extractAttributes(rawQuote);\r\n result.push({ type: 'blockquote', content: text, classes: classes || undefined, id });\r\n continue;\r\n }\r\n\r\n // ── Horizontal rule: --- or ___ or *** ──\r\n if (/^(---|___|(\\*\\s*){3,})\\s*$/.test(trimmed)) {\r\n result.push({ type: 'hr' });\r\n i++;\r\n continue;\r\n }\r\n\r\n // ── TOC: [TOC] or [TOC2] ──\r\n if (/^\\[TOC\\d?\\]\\s*$/.test(trimmed)) {\r\n result.push({ type: 'toc' });\r\n i++;\r\n continue;\r\n }\r\n\r\n // ── Empty line ──\r\n if (trimmed === '') {\r\n i++;\r\n continue;\r\n }\r\n\r\n // ── HTML Block: <tag ...> ──\r\n let tagStartMatch = trimmed.match(/^<([a-zA-Z][\\w-]*)/);\r\n if (tagStartMatch) {\r\n const tagName = tagStartMatch[1].toLowerCase();\r\n\r\n const voidElements = new Set([\r\n 'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input',\r\n 'link', 'meta', 'param', 'source', 'track', 'wbr'\r\n ]);\r\n\r\n const remainingText = lines.slice(i).join('\\n');\r\n\r\n // Find the full opening tag even with multi-line attributes\r\n const openTagRegex = new RegExp(`^\\\\s*<${tagName}\\\\b([^>]*?)>`, 'i');\r\n const openTagMatch = remainingText.match(openTagRegex);\r\n\r\n if (openTagMatch) {\r\n const fullOpenTag = openTagMatch[0];\r\n const attrs = openTagMatch[1].replace(/\\s+/g, ' ').trim();\r\n\r\n const isSelfClosing = fullOpenTag.endsWith('/>') || voidElements.has(tagName);\r\n\r\n if (isSelfClosing) {\r\n const blockText = remainingText.substring(0, openTagMatch.index! + fullOpenTag.length);\r\n const consumedLines = blockText.split('\\n').length;\r\n\r\n result.push({\r\n type: 'html-block',\r\n tag: tagName,\r\n attrs: attrs,\r\n children: [] // No children\r\n } as HtmlBlockToken);\r\n\r\n i += consumedLines;\r\n continue;\r\n } else {\r\n // Tag with content — search for its closing tag\r\n let nestedLevel = 0;\r\n let closeIndex = -1;\r\n let closeTagLength = 0;\r\n\r\n const tagRegex = new RegExp(`</?${tagName}\\\\b[^>]*>`, 'gi');\r\n tagRegex.lastIndex = openTagMatch.index! + fullOpenTag.length;\r\n\r\n let execMatch;\r\n while ((execMatch = tagRegex.exec(remainingText)) !== null) {\r\n if (execMatch[0].startsWith('</')) {\r\n nestedLevel--;\r\n if (nestedLevel < 0) {\r\n closeIndex = execMatch.index;\r\n closeTagLength = execMatch[0].length;\r\n break;\r\n }\r\n } else {\r\n if (!execMatch[0].endsWith('/>')) {\r\n nestedLevel++;\r\n }\r\n }\r\n }\r\n\r\n if (closeIndex !== -1) {\r\n const fullBlock = remainingText.substring(0, closeIndex + closeTagLength);\r\n const consumedLines = fullBlock.split('\\n').length;\r\n\r\n // style/script blocks should not be parsed as Markdown\r\n if (tagName === 'style' || tagName === 'script') {\r\n result.push({\r\n type: 'html',\r\n content: fullBlock,\r\n scopeId: generateScopeId(),\r\n });\r\n } else {\r\n const innerContent = remainingText.substring(openTagMatch.index! + fullOpenTag.length, closeIndex);\r\n result.push({\r\n type: 'html-block',\r\n tag: tagName,\r\n attrs: attrs,\r\n children: parseMarkdown(innerContent)\r\n } as HtmlBlockToken);\r\n }\r\n\r\n i += consumedLines;\r\n continue;\r\n } else {\r\n // Fallback: unclosed tag → treat as self-closing to avoid consuming the whole document\r\n const blockText = remainingText.substring(0, openTagMatch.index! + fullOpenTag.length);\r\n const consumedLines = blockText.split('\\n').length;\r\n\r\n result.push({\r\n type: 'html-block',\r\n tag: tagName,\r\n attrs: attrs,\r\n children: []\r\n } as HtmlBlockToken);\r\n\r\n i += consumedLines;\r\n continue;\r\n }\r\n }\r\n }\r\n }\r\n\r\n // ── Paragraph (default) ──\r\n const paragraphLines = [line];\r\n i++;\r\n while (i < lines.length) {\r\n const nextLine = lines[i];\r\n const nextTrimmed = nextLine.trim();\r\n if (\r\n nextTrimmed === '' ||\r\n nextTrimmed.startsWith('#') ||\r\n nextTrimmed.startsWith(':::') ||\r\n nextTrimmed.includes('|') ||\r\n nextTrimmed.match(/^(\\s*)([-*+]|\\d+\\.)\\s+/) ||\r\n nextTrimmed.startsWith('>') ||\r\n nextTrimmed.startsWith('```') ||\r\n nextTrimmed.startsWith('->') ||\r\n nextTrimmed.match(/^<([a-zA-Z][\\w-]*)\\b/)\r\n ) {\r\n break;\r\n }\r\n paragraphLines.push(nextLine);\r\n i++;\r\n }\r\n const rawParagraph = paragraphLines.join('\\n').trim();\r\n const { text, classes, id } = extractAttributes(rawParagraph);\r\n result.push({ type: 'paragraph', content: text, classes: classes || undefined, id });\r\n }\r\n\r\n return result;\r\n}\r\n\r\n// ─────────────────────────────────────────────\r\n// Slot splitting\r\n// ─────────────────────────────────────────────\r\n\r\n/**\r\n * Split directive content into named slots.\r\n * A line that is exactly `#slotname` starts a new slot.\r\n * Content before any `#slotname` goes into the \"default\" slot.\r\n *\r\n * IMPORTANT: This is nesting-aware — `#slotname` markers inside nested\r\n * directives (:::child ... :::) are NOT treated as slot boundaries of\r\n * the outer directive. Only `#slotname` at depth 0 are considered.\r\n */\r\nfunction splitSlots(rawContent: string): Record<string, string> {\r\n const slots: Record<string, string> = {};\r\n const lines = rawContent.split('\\n');\r\n let currentSlot = 'default';\r\n let buffer: string[] = [];\r\n let nestingDepth = 0;\r\n\r\n for (const line of lines) {\r\n const trimmed = line.trim();\r\n\r\n // Track nesting of directives\r\n if (trimmed.startsWith(':::')) {\r\n const rest = trimmed.slice(3).trim();\r\n if (rest === '') {\r\n // Closing marker (bare :::)\r\n nestingDepth = Math.max(0, nestingDepth - 1);\r\n } else {\r\n nestingDepth++;\r\n }\r\n }\r\n\r\n // Only consider slot boundaries at depth 0\r\n if (nestingDepth === 0 && trimmed.match(/^#([\\w-]+)$/)) {\r\n // Save previous slot\r\n if (buffer.length > 0 || currentSlot !== 'default') {\r\n slots[currentSlot] = buffer.join('\\n').trim();\r\n }\r\n currentSlot = trimmed.slice(1);\r\n buffer = [];\r\n } else {\r\n buffer.push(line);\r\n }\r\n }\r\n\r\n // Save last slot\r\n slots[currentSlot] = buffer.join('\\n').trim();\r\n\r\n return slots;\r\n}\r\n"],"mappings":"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","names":["text","classes","id"]}
1
+ {"version":3,"sources":["../core.ts","../core/utils.ts","../core/parser.ts"],"sourcesContent":["// ============================================================\r\n// @noirmd/previewer/core — Framework-agnostic entry point\r\n//\r\n// Usage:\r\n// import { parseMarkdown, Token } from '@noirmd/previewer/core';\r\n//\r\n// This module has ZERO dependency on React (or any UI framework).\r\n// ============================================================\r\n\r\nexport {\r\n parseMarkdown,\r\n type Token,\r\n type CSSProperties,\r\n type HeaderToken,\r\n type ParagraphToken,\r\n type CodeblockToken,\r\n type DirectiveToken,\r\n type HtmlToken,\r\n type HtmlBlockToken,\r\n type ImageToken,\r\n type TableToken,\r\n type ListToken,\r\n type BlockquoteToken,\r\n type HrToken,\r\n type TocToken,\r\n parseCssString,\r\n generateId,\r\n generateScopeId,\r\n resetScopeCounter,\r\n scrollToId,\r\n extractAttributes,\r\n parseProps,\r\n parseHtmlAttrs,\r\n} from './core/index';\r\n","import type { CSSProperties } from './types';\r\n\r\n/**\r\n * Parse an inline CSS string (e.g. \"color: red; padding: 1rem\") into a CSSProperties object.\r\n */\r\nexport function parseCssString(cssText: string): CSSProperties {\r\n if (!cssText) return {};\r\n return cssText\r\n .split(';')\r\n .filter(Boolean)\r\n .reduce<CSSProperties>((styleObj, styleString) => {\r\n const parts = styleString.split(':');\r\n if (parts.length < 2) return styleObj;\r\n const key = parts[0].trim().replace(/-([a-z])/g, (_, g) => g.toUpperCase());\r\n const value = parts.slice(1).join(':').trim();\r\n styleObj[key] = value;\r\n return styleObj;\r\n }, {});\r\n}\r\n\r\n/**\r\n * Generate a URL-safe slug from text (NFD decomposition, strip accents, lowercase, hyphenate).\r\n */\r\nexport function generateId(text: string): string {\r\n return text\r\n .normalize('NFD')\r\n .replace(/[\\u0300-\\u036f]/g, '')\r\n .toLowerCase()\r\n .replace(/[^\\w\\s-]/g, '')\r\n .replace(/\\s+/g, '-');\r\n}\r\n\r\n/**\r\n * Smooth-scroll to an element by its ID.\r\n */\r\nexport function scrollToId(id: string): void {\r\n if (typeof document === 'undefined') return;\r\n const element = document.getElementById(id);\r\n if (element) {\r\n element.scrollIntoView({ behavior: 'smooth', block: 'start' });\r\n }\r\n}\r\n\r\n/**\r\n * Parse attribute suffix like `##{.my-class #my-id}` from a text line.\r\n * Returns the cleaned text, extracted classes, and id.\r\n */\r\nexport function extractAttributes(text: string): { text: string; classes: string; id: string } {\r\n const match = text.match(/^(.*?)\\s*##\\{([^}]*)\\}\\s*$/);\r\n if (!match) return { text, classes: '', id: '' };\r\n\r\n const rawAttrs = match[2];\r\n const cleanedText = match[1];\r\n\r\n const classList: string[] = [];\r\n let id = '';\r\n\r\n // 1. Parse key=\"value\" attributes (e.g., class=\"mt-0 px-4\", id=\"section\")\r\n for (const [, key, value] of rawAttrs.matchAll(/([\\w-]+)=\"([^\"]*)\"/g)) {\r\n if (key === 'class') {\r\n classList.push(...value.split(/\\s+/).filter(Boolean));\r\n } else if (key === 'id') {\r\n id = value;\r\n }\r\n }\r\n\r\n // 2. Parse shorthand tokens: .className and #id (from remaining content)\r\n // Supports classes with / (opacity), ! (important), . (arbitrary values)\r\n const stripped = rawAttrs.replace(/[\\w-]+=\"[^\"]*\"/g, '');\r\n for (const token of stripped.split(/\\s+/).filter(Boolean)) {\r\n if (token.startsWith('.')) classList.push(token.slice(1));\r\n else if (token.startsWith('#') && !id) id = token.slice(1);\r\n }\r\n\r\n return { text: cleanedText, classes: classList.join(' '), id };\r\n}\r\n\r\nlet _scopeCounter = 0;\r\nexport function resetScopeCounter(): void {\r\n _scopeCounter = 0;\r\n}\r\n\r\n/**\r\n * Generate a unique scope ID for CSS isolation.\r\n */\r\nexport function generateScopeId(): string {\r\n return `scope-${++_scopeCounter}`;\r\n}\r\n\r\n/**\r\n * Parse props from a `{key=\"value\" key2=\"value2\"}` string.\r\n * Also supports `.className` shorthand → adds to `class` prop.\r\n * Also supports `#id` shorthand → adds to `id` prop.\r\n */\r\nexport function parseProps(propsString: string): Record<string, string> {\r\n const props: Record<string, string> = {};\r\n if (!propsString?.trim()) return props;\r\n\r\n // Match key=\"value\" or key='value' pairs\r\n const pairRegex = /(\\w[\\w-]*)=(?:\"([^\"]*)\"|'([^']*)')/g;\r\n let match;\r\n while ((match = pairRegex.exec(propsString)) !== null) {\r\n const key = match[1];\r\n const value = match[2] ?? match[3] ?? '';\r\n props[key] = value;\r\n }\r\n\r\n // Extract .className shorthand (supports / for opacity, ! for important, . for arbitrary values)\r\n const classMatches = propsString.match(/\\.([a-zA-Z0-9_!/.\\-]+)/g);\r\n if (classMatches) {\r\n const existing = props['class'] || '';\r\n const newClasses = classMatches.map(c => c.substring(1)).join(' ');\r\n props['class'] = existing ? `${existing} ${newClasses}` : newClasses;\r\n }\r\n\r\n // Extract #id shorthand (only if not inside a key=\"value\" pair)\r\n const idMatch = propsString.match(/#([a-zA-Z0-9_-]+)(?=\\s|}|$)/);\r\n if (idMatch && !props['id']) {\r\n props['id'] = idMatch[1];\r\n }\r\n\r\n return props;\r\n}\r\n\r\n/**\r\n * Parse raw HTML attributes string (e.g. `class=\"...\" style=\"...\" data-foo=\"...\"`)\r\n * into a plain props object.\r\n *\r\n * NOTE: This does NOT rename `class` → `className`. Framework adapters\r\n * (React, Vue, etc.) should handle their own attribute name mapping.\r\n */\r\nexport function parseHtmlAttrs(attrsString: string): Record<string, any> {\r\n const props: Record<string, any> = {};\r\n if (!attrsString?.trim()) return props;\r\n\r\n const pairRegex = /([a-zA-Z0-9_-]+)(?:=(?:\"([^\"]*)\"|'([^']*)'|([^\\s>]+)))?/g;\r\n let match;\r\n while ((match = pairRegex.exec(attrsString)) !== null) {\r\n const key = match[1];\r\n const value = match[2] ?? match[3] ?? match[4] ?? true;\r\n\r\n // Parse style strings into objects\r\n if (key === 'style' && typeof value === 'string') {\r\n props[key] = parseCssString(value);\r\n } else {\r\n props[key] = value;\r\n }\r\n }\r\n\r\n return props;\r\n}\r\n","import type { Token, DirectiveToken, HtmlBlockToken, CSSProperties } from './types';\r\nimport { generateId, generateScopeId, parseProps, extractAttributes } from './utils';\r\n\r\n/**\r\n * V2 Markdown Parser — line-by-line state machine (framework-agnostic).\r\n */\r\nexport function parseMarkdown(markdown: string): Token[] {\r\n if (!markdown) return [];\r\n const lines = markdown.replace(/\\r\\n/g, '\\n').replace(/\\r/g, '').split('\\n');\r\n const result: Token[] = [];\r\n let i = 0;\r\n\r\n while (i < lines.length) {\r\n const line = lines[i];\r\n const trimmed = line.trim();\r\n let match: RegExpMatchArray | null;\r\n\r\n // ── Headers: ## Title ──\r\n if ((match = trimmed.match(/^(#{1,6})\\s+(.+)$/))) {\r\n const level = match[1].length;\r\n const rawText = match[2];\r\n const { text, classes, id: customId } = extractAttributes(rawText);\r\n const id = customId || generateId(text.replace(/->|<-/g, ''));\r\n result.push({ type: 'header', level, text, id, classes: classes || undefined });\r\n i++;\r\n continue;\r\n }\r\n\r\n // ── Aligned paragraph: -> text <- or -> text -> ──\r\n if ((match = trimmed.match(/^->\\s*(.+?)\\s*(<-|->)\\s*$/))) {\r\n const content = match[1];\r\n const align = match[2] === '<-' ? 'center' : 'right';\r\n result.push({ type: 'paragraph', content, align });\r\n i++;\r\n continue;\r\n }\r\n\r\n // ── Code block: ```lang title=\"name\" ──\r\n if (trimmed.startsWith('```')) {\r\n const fenceHeader = trimmed.slice(3).trim();\r\n const titleMatch = fenceHeader.match(/title=[\"']([^\"']*)[\"']/);\r\n const lang = fenceHeader.replace(/title=[\"'][^\"']*[\"']/, '').trim();\r\n const title = titleMatch ? titleMatch[1] : undefined;\r\n const content: string[] = [];\r\n i++;\r\n while (i < lines.length && !lines[i].trim().startsWith('```')) {\r\n content.push(lines[i]);\r\n i++;\r\n }\r\n result.push({ type: 'codeblock', language: lang, title, content: content.join('\\n') });\r\n i++; // skip closing ```\r\n continue;\r\n }\r\n\r\n // ── Directive: :::type {props} ... ::: ──\r\n if (trimmed.startsWith(':::')) {\r\n const rest = trimmed.slice(3).trim();\r\n\r\n // Bare closing marker\r\n if (rest === '') {\r\n result.push({ type: 'paragraph', content: line });\r\n i++;\r\n continue;\r\n }\r\n\r\n const typeMatch = rest.match(/^([\\w-]+)/);\r\n const directiveType = typeMatch ? typeMatch[1] : 'custom';\r\n\r\n // Lookahead: find the matching closing :::\r\n let j = i + 1;\r\n let nestedLevel = 0;\r\n let foundClose = false;\r\n\r\n while (j < lines.length) {\r\n const currentTrimmed = lines[j].trim();\r\n if (currentTrimmed === ':::') {\r\n if (nestedLevel === 0) {\r\n foundClose = true;\r\n break;\r\n } else {\r\n nestedLevel--;\r\n }\r\n } else if (currentTrimmed.startsWith(':::')) {\r\n // Opening a nested directive\r\n nestedLevel++;\r\n }\r\n j++;\r\n }\r\n\r\n if (foundClose) {\r\n // Collect raw content lines (between opening and closing)\r\n const contentLines: string[] = [];\r\n for (let k = i + 1; k < j; k++) {\r\n contentLines.push(lines[k]);\r\n }\r\n const rawContent = contentLines.join('\\n');\r\n\r\n // Parse the directive header (everything after the type name)\r\n const headerRest = typeMatch ? rest.slice(directiveType.length).trim() : rest;\r\n\r\n // Extract {props} block\r\n let propsString = '';\r\n let shortForm = '';\r\n const propsBlockMatch = headerRest.match(/^\\{([^]*)\\}\\s*$/);\r\n if (propsBlockMatch) {\r\n propsString = propsBlockMatch[1];\r\n } else if (headerRest) {\r\n // Short-form: bare text after type → becomes title prop\r\n shortForm = headerRest;\r\n }\r\n\r\n const props = parseProps(propsString);\r\n if (shortForm && !props['title']) {\r\n props['title'] = shortForm;\r\n }\r\n\r\n // Split content into slots\r\n const slots = splitSlots(rawContent);\r\n\r\n result.push({\r\n type: 'directive',\r\n directiveType,\r\n props,\r\n slots,\r\n scopeId: generateScopeId(),\r\n } as DirectiveToken);\r\n\r\n i = j + 1;\r\n continue;\r\n } else {\r\n // Unclosed directive — render as plain text\r\n result.push({ type: 'paragraph', content: line });\r\n i++;\r\n continue;\r\n }\r\n }\r\n\r\n // ── Image: ![alt](src#float#3d){w:h} ──\r\n if ((match = trimmed.match(/^(.*?)!\\[([^\\]]*)\\]\\(([^)]+?)\\)(?:\\{([^}]+?)\\})?(.*)$/))) {\r\n const [, preText, alt, srcAndFloat, size, postText] = match;\r\n\r\n if (preText.trim()) {\r\n result.push({ type: 'paragraph', content: preText.trim() });\r\n }\r\n\r\n let src = srcAndFloat;\r\n const style: CSSProperties = {};\r\n if (src.includes('#left')) {\r\n src = src.replace('#left', '');\r\n style.float = 'left';\r\n style.margin = '0 1em 1em 0';\r\n } else if (src.includes('#right')) {\r\n src = src.replace('#right', '');\r\n style.float = 'right';\r\n style.margin = '0 0 1em 1em';\r\n } else if (src.includes('#center')) {\r\n src = src.replace('#center', '');\r\n style.display = 'block';\r\n style.margin = '0 auto 1em auto';\r\n }\r\n if (size) {\r\n const [width, height] = size.split(':');\r\n if (width) style.width = width.trim();\r\n if (height) style.height = height.trim();\r\n }\r\n result.push({ type: 'image', alt, src, style });\r\n\r\n if (postText.trim()) {\r\n result.push({ type: 'paragraph', content: postText.trim() });\r\n }\r\n i++;\r\n continue;\r\n }\r\n\r\n // ── Table: | cell | cell | ──\r\n if (trimmed.includes('|') && i + 1 < lines.length && lines[i + 1].includes('---')) {\r\n const tableLines = [line];\r\n i++;\r\n tableLines.push(lines[i]);\r\n i++;\r\n while (i < lines.length && lines[i].trim().includes('|')) {\r\n tableLines.push(lines[i]);\r\n i++;\r\n }\r\n result.push({ type: 'table', content: tableLines.join('\\n') });\r\n continue;\r\n }\r\n\r\n // ── List: - item or 1. item ──\r\n if ((match = trimmed.match(/^(\\s*)([-*+]|\\d+\\.)\\s+(.+)$/))) {\r\n const listItems = [line];\r\n i++;\r\n while (i < lines.length) {\r\n const nextLine = lines[i];\r\n const nextTrimmed = nextLine.trim();\r\n if (\r\n nextTrimmed.match(/^(\\s*)([-*+]|\\d+\\.)\\s+(.+)$/) ||\r\n nextTrimmed === '' ||\r\n nextLine.startsWith(' ')\r\n ) {\r\n listItems.push(nextLine);\r\n i++;\r\n } else {\r\n break;\r\n }\r\n }\r\n result.push({ type: 'list', content: listItems.join('\\n') });\r\n continue;\r\n }\r\n\r\n // ── Blockquote: > text ──\r\n if (trimmed.startsWith('>')) {\r\n const quoteLines = [line];\r\n i++;\r\n while (i < lines.length && (lines[i].trim().startsWith('>') || lines[i].trim() === '')) {\r\n quoteLines.push(lines[i]);\r\n i++;\r\n }\r\n const rawQuote = quoteLines.join('\\n').replace(/^>\\s?/gm, '');\r\n const { text, classes, id } = extractAttributes(rawQuote);\r\n result.push({ type: 'blockquote', content: text, classes: classes || undefined, id });\r\n continue;\r\n }\r\n\r\n // ── Horizontal rule: --- or ___ or *** ──\r\n if (/^(---|___|(\\*\\s*){3,})\\s*$/.test(trimmed)) {\r\n result.push({ type: 'hr' });\r\n i++;\r\n continue;\r\n }\r\n\r\n // ── TOC: [TOC] or [TOC2] ──\r\n if (/^\\[TOC\\d?\\]\\s*$/.test(trimmed)) {\r\n result.push({ type: 'toc' });\r\n i++;\r\n continue;\r\n }\r\n\r\n // ── Empty line ──\r\n if (trimmed === '') {\r\n i++;\r\n continue;\r\n }\r\n\r\n // ── HTML Block: <tag ...> ──\r\n let tagStartMatch = trimmed.match(/^<([a-zA-Z][\\w-]*)/);\r\n if (tagStartMatch) {\r\n const tagName = tagStartMatch[1].toLowerCase();\r\n\r\n const voidElements = new Set([\r\n 'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input',\r\n 'link', 'meta', 'param', 'source', 'track', 'wbr'\r\n ]);\r\n\r\n const remainingText = lines.slice(i).join('\\n');\r\n\r\n // Find the full opening tag even with multi-line attributes\r\n const openTagRegex = new RegExp(`^\\\\s*<${tagName}\\\\b([^>]*?)>`, 'i');\r\n const openTagMatch = remainingText.match(openTagRegex);\r\n\r\n if (openTagMatch) {\r\n const fullOpenTag = openTagMatch[0];\r\n const attrs = openTagMatch[1].replace(/\\s+/g, ' ').trim();\r\n\r\n const isSelfClosing = fullOpenTag.endsWith('/>') || voidElements.has(tagName);\r\n\r\n if (isSelfClosing) {\r\n const blockText = remainingText.substring(0, openTagMatch.index! + fullOpenTag.length);\r\n const consumedLines = blockText.split('\\n').length;\r\n\r\n result.push({\r\n type: 'html-block',\r\n tag: tagName,\r\n attrs: attrs,\r\n children: [] // No children\r\n } as HtmlBlockToken);\r\n\r\n i += consumedLines;\r\n continue;\r\n } else {\r\n // Tag with content — search for its closing tag\r\n let nestedLevel = 0;\r\n let closeIndex = -1;\r\n let closeTagLength = 0;\r\n\r\n const tagRegex = new RegExp(`</?${tagName}\\\\b[^>]*>`, 'gi');\r\n tagRegex.lastIndex = openTagMatch.index! + fullOpenTag.length;\r\n\r\n let execMatch;\r\n while ((execMatch = tagRegex.exec(remainingText)) !== null) {\r\n if (execMatch[0].startsWith('</')) {\r\n nestedLevel--;\r\n if (nestedLevel < 0) {\r\n closeIndex = execMatch.index;\r\n closeTagLength = execMatch[0].length;\r\n break;\r\n }\r\n } else {\r\n if (!execMatch[0].endsWith('/>')) {\r\n nestedLevel++;\r\n }\r\n }\r\n }\r\n\r\n if (closeIndex !== -1) {\r\n const fullBlock = remainingText.substring(0, closeIndex + closeTagLength);\r\n const consumedLines = fullBlock.split('\\n').length;\r\n\r\n // style/script blocks should not be parsed as Markdown\r\n if (tagName === 'style' || tagName === 'script') {\r\n result.push({\r\n type: 'html',\r\n content: fullBlock,\r\n scopeId: generateScopeId(),\r\n });\r\n } else {\r\n const innerContent = remainingText.substring(openTagMatch.index! + fullOpenTag.length, closeIndex);\r\n result.push({\r\n type: 'html-block',\r\n tag: tagName,\r\n attrs: attrs,\r\n children: parseMarkdown(innerContent)\r\n } as HtmlBlockToken);\r\n }\r\n\r\n i += consumedLines;\r\n continue;\r\n } else {\r\n // Fallback: unclosed tag → treat as self-closing to avoid consuming the whole document\r\n const blockText = remainingText.substring(0, openTagMatch.index! + fullOpenTag.length);\r\n const consumedLines = blockText.split('\\n').length;\r\n\r\n result.push({\r\n type: 'html-block',\r\n tag: tagName,\r\n attrs: attrs,\r\n children: []\r\n } as HtmlBlockToken);\r\n\r\n i += consumedLines;\r\n continue;\r\n }\r\n }\r\n }\r\n }\r\n\r\n // ── Paragraph (default) ──\r\n const paragraphLines = [line];\r\n i++;\r\n while (i < lines.length) {\r\n const nextLine = lines[i];\r\n const nextTrimmed = nextLine.trim();\r\n if (\r\n nextTrimmed === '' ||\r\n nextTrimmed.startsWith('#') ||\r\n nextTrimmed.startsWith(':::') ||\r\n nextTrimmed.includes('|') ||\r\n nextTrimmed.match(/^(\\s*)([-*+]|\\d+\\.)\\s+/) ||\r\n nextTrimmed.startsWith('>') ||\r\n nextTrimmed.startsWith('```') ||\r\n nextTrimmed.startsWith('->') ||\r\n nextTrimmed.match(/^<([a-zA-Z][\\w-]*)\\b/)\r\n ) {\r\n break;\r\n }\r\n paragraphLines.push(nextLine);\r\n i++;\r\n }\r\n const rawParagraph = paragraphLines.join('\\n').trim();\r\n const { text, classes, id } = extractAttributes(rawParagraph);\r\n result.push({ type: 'paragraph', content: text, classes: classes || undefined, id });\r\n }\r\n\r\n return result;\r\n}\r\n\r\n// ─────────────────────────────────────────────\r\n// Slot splitting\r\n// ─────────────────────────────────────────────\r\n\r\n/**\r\n * Split directive content into named slots.\r\n * A line that is exactly `#slotname` starts a new slot.\r\n * Content before any `#slotname` goes into the \"default\" slot.\r\n *\r\n * IMPORTANT: This is nesting-aware — `#slotname` markers inside nested\r\n * directives (:::child ... :::) are NOT treated as slot boundaries of\r\n * the outer directive. Only `#slotname` at depth 0 are considered.\r\n */\r\nfunction splitSlots(rawContent: string): Record<string, string> {\r\n const slots: Record<string, string> = {};\r\n const lines = rawContent.split('\\n');\r\n let currentSlot = 'default';\r\n let buffer: string[] = [];\r\n let nestingDepth = 0;\r\n\r\n for (const line of lines) {\r\n const trimmed = line.trim();\r\n\r\n // Track nesting of directives\r\n if (trimmed.startsWith(':::')) {\r\n const rest = trimmed.slice(3).trim();\r\n if (rest === '') {\r\n // Closing marker (bare :::)\r\n nestingDepth = Math.max(0, nestingDepth - 1);\r\n } else {\r\n nestingDepth++;\r\n }\r\n }\r\n\r\n // Only consider slot boundaries at depth 0\r\n if (nestingDepth === 0 && trimmed.match(/^#([\\w-]+)$/)) {\r\n // Save previous slot\r\n if (buffer.length > 0 || currentSlot !== 'default') {\r\n slots[currentSlot] = buffer.join('\\n').trim();\r\n }\r\n currentSlot = trimmed.slice(1);\r\n buffer = [];\r\n } else {\r\n buffer.push(line);\r\n }\r\n }\r\n\r\n // Save last slot\r\n slots[currentSlot] = buffer.join('\\n').trim();\r\n\r\n return slots;\r\n}\r\n"],"mappings":"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","names":["text","classes","id"]}
package/dist/core.js CHANGED
@@ -90,7 +90,7 @@ function parseHtmlAttrs(attrsString) {
90
90
  // core/parser.ts
91
91
  function parseMarkdown(markdown) {
92
92
  if (!markdown) return [];
93
- const lines = markdown.split("\n");
93
+ const lines = markdown.replace(/\r\n/g, "\n").replace(/\r/g, "").split("\n");
94
94
  const result = [];
95
95
  let i = 0;
96
96
  while (i < lines.length) {
package/dist/core.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../core/utils.ts","../core/parser.ts"],"sourcesContent":["import type { CSSProperties } from './types';\r\n\r\n/**\r\n * Parse an inline CSS string (e.g. \"color: red; padding: 1rem\") into a CSSProperties object.\r\n */\r\nexport function parseCssString(cssText: string): CSSProperties {\r\n if (!cssText) return {};\r\n return cssText\r\n .split(';')\r\n .filter(Boolean)\r\n .reduce<CSSProperties>((styleObj, styleString) => {\r\n const parts = styleString.split(':');\r\n if (parts.length < 2) return styleObj;\r\n const key = parts[0].trim().replace(/-([a-z])/g, (_, g) => g.toUpperCase());\r\n const value = parts.slice(1).join(':').trim();\r\n styleObj[key] = value;\r\n return styleObj;\r\n }, {});\r\n}\r\n\r\n/**\r\n * Generate a URL-safe slug from text (NFD decomposition, strip accents, lowercase, hyphenate).\r\n */\r\nexport function generateId(text: string): string {\r\n return text\r\n .normalize('NFD')\r\n .replace(/[\\u0300-\\u036f]/g, '')\r\n .toLowerCase()\r\n .replace(/[^\\w\\s-]/g, '')\r\n .replace(/\\s+/g, '-');\r\n}\r\n\r\n/**\r\n * Smooth-scroll to an element by its ID.\r\n */\r\nexport function scrollToId(id: string): void {\r\n if (typeof document === 'undefined') return;\r\n const element = document.getElementById(id);\r\n if (element) {\r\n element.scrollIntoView({ behavior: 'smooth', block: 'start' });\r\n }\r\n}\r\n\r\n/**\r\n * Parse attribute suffix like `##{.my-class #my-id}` from a text line.\r\n * Returns the cleaned text, extracted classes, and id.\r\n */\r\nexport function extractAttributes(text: string): { text: string; classes: string; id: string } {\r\n const match = text.match(/^(.*?)\\s*##\\{([^}]*)\\}\\s*$/);\r\n if (!match) return { text, classes: '', id: '' };\r\n\r\n const rawAttrs = match[2];\r\n const cleanedText = match[1];\r\n\r\n const classList: string[] = [];\r\n let id = '';\r\n\r\n // 1. Parse key=\"value\" attributes (e.g., class=\"mt-0 px-4\", id=\"section\")\r\n for (const [, key, value] of rawAttrs.matchAll(/([\\w-]+)=\"([^\"]*)\"/g)) {\r\n if (key === 'class') {\r\n classList.push(...value.split(/\\s+/).filter(Boolean));\r\n } else if (key === 'id') {\r\n id = value;\r\n }\r\n }\r\n\r\n // 2. Parse shorthand tokens: .className and #id (from remaining content)\r\n // Supports classes with / (opacity), ! (important), . (arbitrary values)\r\n const stripped = rawAttrs.replace(/[\\w-]+=\"[^\"]*\"/g, '');\r\n for (const token of stripped.split(/\\s+/).filter(Boolean)) {\r\n if (token.startsWith('.')) classList.push(token.slice(1));\r\n else if (token.startsWith('#') && !id) id = token.slice(1);\r\n }\r\n\r\n return { text: cleanedText, classes: classList.join(' '), id };\r\n}\r\n\r\nlet _scopeCounter = 0;\r\nexport function resetScopeCounter(): void {\r\n _scopeCounter = 0;\r\n}\r\n\r\n/**\r\n * Generate a unique scope ID for CSS isolation.\r\n */\r\nexport function generateScopeId(): string {\r\n return `scope-${++_scopeCounter}`;\r\n}\r\n\r\n/**\r\n * Parse props from a `{key=\"value\" key2=\"value2\"}` string.\r\n * Also supports `.className` shorthand → adds to `class` prop.\r\n * Also supports `#id` shorthand → adds to `id` prop.\r\n */\r\nexport function parseProps(propsString: string): Record<string, string> {\r\n const props: Record<string, string> = {};\r\n if (!propsString?.trim()) return props;\r\n\r\n // Match key=\"value\" or key='value' pairs\r\n const pairRegex = /(\\w[\\w-]*)=(?:\"([^\"]*)\"|'([^']*)')/g;\r\n let match;\r\n while ((match = pairRegex.exec(propsString)) !== null) {\r\n const key = match[1];\r\n const value = match[2] ?? match[3] ?? '';\r\n props[key] = value;\r\n }\r\n\r\n // Extract .className shorthand (supports / for opacity, ! for important, . for arbitrary values)\r\n const classMatches = propsString.match(/\\.([a-zA-Z0-9_!/.\\-]+)/g);\r\n if (classMatches) {\r\n const existing = props['class'] || '';\r\n const newClasses = classMatches.map(c => c.substring(1)).join(' ');\r\n props['class'] = existing ? `${existing} ${newClasses}` : newClasses;\r\n }\r\n\r\n // Extract #id shorthand (only if not inside a key=\"value\" pair)\r\n const idMatch = propsString.match(/#([a-zA-Z0-9_-]+)(?=\\s|}|$)/);\r\n if (idMatch && !props['id']) {\r\n props['id'] = idMatch[1];\r\n }\r\n\r\n return props;\r\n}\r\n\r\n/**\r\n * Parse raw HTML attributes string (e.g. `class=\"...\" style=\"...\" data-foo=\"...\"`)\r\n * into a plain props object.\r\n *\r\n * NOTE: This does NOT rename `class` → `className`. Framework adapters\r\n * (React, Vue, etc.) should handle their own attribute name mapping.\r\n */\r\nexport function parseHtmlAttrs(attrsString: string): Record<string, any> {\r\n const props: Record<string, any> = {};\r\n if (!attrsString?.trim()) return props;\r\n\r\n const pairRegex = /([a-zA-Z0-9_-]+)(?:=(?:\"([^\"]*)\"|'([^']*)'|([^\\s>]+)))?/g;\r\n let match;\r\n while ((match = pairRegex.exec(attrsString)) !== null) {\r\n const key = match[1];\r\n const value = match[2] ?? match[3] ?? match[4] ?? true;\r\n\r\n // Parse style strings into objects\r\n if (key === 'style' && typeof value === 'string') {\r\n props[key] = parseCssString(value);\r\n } else {\r\n props[key] = value;\r\n }\r\n }\r\n\r\n return props;\r\n}\r\n","import type { Token, DirectiveToken, HtmlBlockToken, CSSProperties } from './types';\r\nimport { generateId, generateScopeId, parseProps, extractAttributes } from './utils';\r\n\r\n/**\r\n * V2 Markdown Parser — line-by-line state machine (framework-agnostic).\r\n */\r\nexport function parseMarkdown(markdown: string): Token[] {\r\n if (!markdown) return [];\r\n const lines = markdown.split('\\n');\r\n const result: Token[] = [];\r\n let i = 0;\r\n\r\n while (i < lines.length) {\r\n const line = lines[i];\r\n const trimmed = line.trim();\r\n let match: RegExpMatchArray | null;\r\n\r\n // ── Headers: ## Title ──\r\n if ((match = trimmed.match(/^(#{1,6})\\s+(.+)$/))) {\r\n const level = match[1].length;\r\n const rawText = match[2];\r\n const { text, classes, id: customId } = extractAttributes(rawText);\r\n const id = customId || generateId(text.replace(/->|<-/g, ''));\r\n result.push({ type: 'header', level, text, id, classes: classes || undefined });\r\n i++;\r\n continue;\r\n }\r\n\r\n // ── Aligned paragraph: -> text <- or -> text -> ──\r\n if ((match = trimmed.match(/^->\\s*(.+?)\\s*(<-|->)\\s*$/))) {\r\n const content = match[1];\r\n const align = match[2] === '<-' ? 'center' : 'right';\r\n result.push({ type: 'paragraph', content, align });\r\n i++;\r\n continue;\r\n }\r\n\r\n // ── Code block: ```lang title=\"name\" ──\r\n if (trimmed.startsWith('```')) {\r\n const fenceHeader = trimmed.slice(3).trim();\r\n const titleMatch = fenceHeader.match(/title=[\"']([^\"']*)[\"']/);\r\n const lang = fenceHeader.replace(/title=[\"'][^\"']*[\"']/, '').trim();\r\n const title = titleMatch ? titleMatch[1] : undefined;\r\n const content: string[] = [];\r\n i++;\r\n while (i < lines.length && !lines[i].trim().startsWith('```')) {\r\n content.push(lines[i]);\r\n i++;\r\n }\r\n result.push({ type: 'codeblock', language: lang, title, content: content.join('\\n') });\r\n i++; // skip closing ```\r\n continue;\r\n }\r\n\r\n // ── Directive: :::type {props} ... ::: ──\r\n if (trimmed.startsWith(':::')) {\r\n const rest = trimmed.slice(3).trim();\r\n\r\n // Bare closing marker\r\n if (rest === '') {\r\n result.push({ type: 'paragraph', content: line });\r\n i++;\r\n continue;\r\n }\r\n\r\n const typeMatch = rest.match(/^([\\w-]+)/);\r\n const directiveType = typeMatch ? typeMatch[1] : 'custom';\r\n\r\n // Lookahead: find the matching closing :::\r\n let j = i + 1;\r\n let nestedLevel = 0;\r\n let foundClose = false;\r\n\r\n while (j < lines.length) {\r\n const currentTrimmed = lines[j].trim();\r\n if (currentTrimmed === ':::') {\r\n if (nestedLevel === 0) {\r\n foundClose = true;\r\n break;\r\n } else {\r\n nestedLevel--;\r\n }\r\n } else if (currentTrimmed.startsWith(':::')) {\r\n // Opening a nested directive\r\n nestedLevel++;\r\n }\r\n j++;\r\n }\r\n\r\n if (foundClose) {\r\n // Collect raw content lines (between opening and closing)\r\n const contentLines: string[] = [];\r\n for (let k = i + 1; k < j; k++) {\r\n contentLines.push(lines[k]);\r\n }\r\n const rawContent = contentLines.join('\\n');\r\n\r\n // Parse the directive header (everything after the type name)\r\n const headerRest = typeMatch ? rest.slice(directiveType.length).trim() : rest;\r\n\r\n // Extract {props} block\r\n let propsString = '';\r\n let shortForm = '';\r\n const propsBlockMatch = headerRest.match(/^\\{([^]*)\\}\\s*$/);\r\n if (propsBlockMatch) {\r\n propsString = propsBlockMatch[1];\r\n } else if (headerRest) {\r\n // Short-form: bare text after type → becomes title prop\r\n shortForm = headerRest;\r\n }\r\n\r\n const props = parseProps(propsString);\r\n if (shortForm && !props['title']) {\r\n props['title'] = shortForm;\r\n }\r\n\r\n // Split content into slots\r\n const slots = splitSlots(rawContent);\r\n\r\n result.push({\r\n type: 'directive',\r\n directiveType,\r\n props,\r\n slots,\r\n scopeId: generateScopeId(),\r\n } as DirectiveToken);\r\n\r\n i = j + 1;\r\n continue;\r\n } else {\r\n // Unclosed directive — render as plain text\r\n result.push({ type: 'paragraph', content: line });\r\n i++;\r\n continue;\r\n }\r\n }\r\n\r\n // ── Image: ![alt](src#float#3d){w:h} ──\r\n if ((match = trimmed.match(/^(.*?)!\\[([^\\]]*)\\]\\(([^)]+?)\\)(?:\\{([^}]+?)\\})?(.*)$/))) {\r\n const [, preText, alt, srcAndFloat, size, postText] = match;\r\n\r\n if (preText.trim()) {\r\n result.push({ type: 'paragraph', content: preText.trim() });\r\n }\r\n\r\n let src = srcAndFloat;\r\n const style: CSSProperties = {};\r\n if (src.includes('#left')) {\r\n src = src.replace('#left', '');\r\n style.float = 'left';\r\n style.margin = '0 1em 1em 0';\r\n } else if (src.includes('#right')) {\r\n src = src.replace('#right', '');\r\n style.float = 'right';\r\n style.margin = '0 0 1em 1em';\r\n } else if (src.includes('#center')) {\r\n src = src.replace('#center', '');\r\n style.display = 'block';\r\n style.margin = '0 auto 1em auto';\r\n }\r\n if (size) {\r\n const [width, height] = size.split(':');\r\n if (width) style.width = width.trim();\r\n if (height) style.height = height.trim();\r\n }\r\n result.push({ type: 'image', alt, src, style });\r\n\r\n if (postText.trim()) {\r\n result.push({ type: 'paragraph', content: postText.trim() });\r\n }\r\n i++;\r\n continue;\r\n }\r\n\r\n // ── Table: | cell | cell | ──\r\n if (trimmed.includes('|') && i + 1 < lines.length && lines[i + 1].includes('---')) {\r\n const tableLines = [line];\r\n i++;\r\n tableLines.push(lines[i]);\r\n i++;\r\n while (i < lines.length && lines[i].trim().includes('|')) {\r\n tableLines.push(lines[i]);\r\n i++;\r\n }\r\n result.push({ type: 'table', content: tableLines.join('\\n') });\r\n continue;\r\n }\r\n\r\n // ── List: - item or 1. item ──\r\n if ((match = trimmed.match(/^(\\s*)([-*+]|\\d+\\.)\\s+(.+)$/))) {\r\n const listItems = [line];\r\n i++;\r\n while (i < lines.length) {\r\n const nextLine = lines[i];\r\n const nextTrimmed = nextLine.trim();\r\n if (\r\n nextTrimmed.match(/^(\\s*)([-*+]|\\d+\\.)\\s+(.+)$/) ||\r\n nextTrimmed === '' ||\r\n nextLine.startsWith(' ')\r\n ) {\r\n listItems.push(nextLine);\r\n i++;\r\n } else {\r\n break;\r\n }\r\n }\r\n result.push({ type: 'list', content: listItems.join('\\n') });\r\n continue;\r\n }\r\n\r\n // ── Blockquote: > text ──\r\n if (trimmed.startsWith('>')) {\r\n const quoteLines = [line];\r\n i++;\r\n while (i < lines.length && (lines[i].trim().startsWith('>') || lines[i].trim() === '')) {\r\n quoteLines.push(lines[i]);\r\n i++;\r\n }\r\n const rawQuote = quoteLines.join('\\n').replace(/^>\\s?/gm, '');\r\n const { text, classes, id } = extractAttributes(rawQuote);\r\n result.push({ type: 'blockquote', content: text, classes: classes || undefined, id });\r\n continue;\r\n }\r\n\r\n // ── Horizontal rule: --- or ___ or *** ──\r\n if (/^(---|___|(\\*\\s*){3,})\\s*$/.test(trimmed)) {\r\n result.push({ type: 'hr' });\r\n i++;\r\n continue;\r\n }\r\n\r\n // ── TOC: [TOC] or [TOC2] ──\r\n if (/^\\[TOC\\d?\\]\\s*$/.test(trimmed)) {\r\n result.push({ type: 'toc' });\r\n i++;\r\n continue;\r\n }\r\n\r\n // ── Empty line ──\r\n if (trimmed === '') {\r\n i++;\r\n continue;\r\n }\r\n\r\n // ── HTML Block: <tag ...> ──\r\n let tagStartMatch = trimmed.match(/^<([a-zA-Z][\\w-]*)/);\r\n if (tagStartMatch) {\r\n const tagName = tagStartMatch[1].toLowerCase();\r\n\r\n const voidElements = new Set([\r\n 'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input',\r\n 'link', 'meta', 'param', 'source', 'track', 'wbr'\r\n ]);\r\n\r\n const remainingText = lines.slice(i).join('\\n');\r\n\r\n // Find the full opening tag even with multi-line attributes\r\n const openTagRegex = new RegExp(`^\\\\s*<${tagName}\\\\b([^>]*?)>`, 'i');\r\n const openTagMatch = remainingText.match(openTagRegex);\r\n\r\n if (openTagMatch) {\r\n const fullOpenTag = openTagMatch[0];\r\n const attrs = openTagMatch[1].replace(/\\s+/g, ' ').trim();\r\n\r\n const isSelfClosing = fullOpenTag.endsWith('/>') || voidElements.has(tagName);\r\n\r\n if (isSelfClosing) {\r\n const blockText = remainingText.substring(0, openTagMatch.index! + fullOpenTag.length);\r\n const consumedLines = blockText.split('\\n').length;\r\n\r\n result.push({\r\n type: 'html-block',\r\n tag: tagName,\r\n attrs: attrs,\r\n children: [] // No children\r\n } as HtmlBlockToken);\r\n\r\n i += consumedLines;\r\n continue;\r\n } else {\r\n // Tag with content — search for its closing tag\r\n let nestedLevel = 0;\r\n let closeIndex = -1;\r\n let closeTagLength = 0;\r\n\r\n const tagRegex = new RegExp(`</?${tagName}\\\\b[^>]*>`, 'gi');\r\n tagRegex.lastIndex = openTagMatch.index! + fullOpenTag.length;\r\n\r\n let execMatch;\r\n while ((execMatch = tagRegex.exec(remainingText)) !== null) {\r\n if (execMatch[0].startsWith('</')) {\r\n nestedLevel--;\r\n if (nestedLevel < 0) {\r\n closeIndex = execMatch.index;\r\n closeTagLength = execMatch[0].length;\r\n break;\r\n }\r\n } else {\r\n if (!execMatch[0].endsWith('/>')) {\r\n nestedLevel++;\r\n }\r\n }\r\n }\r\n\r\n if (closeIndex !== -1) {\r\n const fullBlock = remainingText.substring(0, closeIndex + closeTagLength);\r\n const consumedLines = fullBlock.split('\\n').length;\r\n\r\n // style/script blocks should not be parsed as Markdown\r\n if (tagName === 'style' || tagName === 'script') {\r\n result.push({\r\n type: 'html',\r\n content: fullBlock,\r\n scopeId: generateScopeId(),\r\n });\r\n } else {\r\n const innerContent = remainingText.substring(openTagMatch.index! + fullOpenTag.length, closeIndex);\r\n result.push({\r\n type: 'html-block',\r\n tag: tagName,\r\n attrs: attrs,\r\n children: parseMarkdown(innerContent)\r\n } as HtmlBlockToken);\r\n }\r\n\r\n i += consumedLines;\r\n continue;\r\n } else {\r\n // Fallback: unclosed tag → treat as self-closing to avoid consuming the whole document\r\n const blockText = remainingText.substring(0, openTagMatch.index! + fullOpenTag.length);\r\n const consumedLines = blockText.split('\\n').length;\r\n\r\n result.push({\r\n type: 'html-block',\r\n tag: tagName,\r\n attrs: attrs,\r\n children: []\r\n } as HtmlBlockToken);\r\n\r\n i += consumedLines;\r\n continue;\r\n }\r\n }\r\n }\r\n }\r\n\r\n // ── Paragraph (default) ──\r\n const paragraphLines = [line];\r\n i++;\r\n while (i < lines.length) {\r\n const nextLine = lines[i];\r\n const nextTrimmed = nextLine.trim();\r\n if (\r\n nextTrimmed === '' ||\r\n nextTrimmed.startsWith('#') ||\r\n nextTrimmed.startsWith(':::') ||\r\n nextTrimmed.includes('|') ||\r\n nextTrimmed.match(/^(\\s*)([-*+]|\\d+\\.)\\s+/) ||\r\n nextTrimmed.startsWith('>') ||\r\n nextTrimmed.startsWith('```') ||\r\n nextTrimmed.startsWith('->') ||\r\n nextTrimmed.match(/^<([a-zA-Z][\\w-]*)\\b/)\r\n ) {\r\n break;\r\n }\r\n paragraphLines.push(nextLine);\r\n i++;\r\n }\r\n const rawParagraph = paragraphLines.join('\\n').trim();\r\n const { text, classes, id } = extractAttributes(rawParagraph);\r\n result.push({ type: 'paragraph', content: text, classes: classes || undefined, id });\r\n }\r\n\r\n return result;\r\n}\r\n\r\n// ─────────────────────────────────────────────\r\n// Slot splitting\r\n// ─────────────────────────────────────────────\r\n\r\n/**\r\n * Split directive content into named slots.\r\n * A line that is exactly `#slotname` starts a new slot.\r\n * Content before any `#slotname` goes into the \"default\" slot.\r\n *\r\n * IMPORTANT: This is nesting-aware — `#slotname` markers inside nested\r\n * directives (:::child ... :::) are NOT treated as slot boundaries of\r\n * the outer directive. Only `#slotname` at depth 0 are considered.\r\n */\r\nfunction splitSlots(rawContent: string): Record<string, string> {\r\n const slots: Record<string, string> = {};\r\n const lines = rawContent.split('\\n');\r\n let currentSlot = 'default';\r\n let buffer: string[] = [];\r\n let nestingDepth = 0;\r\n\r\n for (const line of lines) {\r\n const trimmed = line.trim();\r\n\r\n // Track nesting of directives\r\n if (trimmed.startsWith(':::')) {\r\n const rest = trimmed.slice(3).trim();\r\n if (rest === '') {\r\n // Closing marker (bare :::)\r\n nestingDepth = Math.max(0, nestingDepth - 1);\r\n } else {\r\n nestingDepth++;\r\n }\r\n }\r\n\r\n // Only consider slot boundaries at depth 0\r\n if (nestingDepth === 0 && trimmed.match(/^#([\\w-]+)$/)) {\r\n // Save previous slot\r\n if (buffer.length > 0 || currentSlot !== 'default') {\r\n slots[currentSlot] = buffer.join('\\n').trim();\r\n }\r\n currentSlot = trimmed.slice(1);\r\n buffer = [];\r\n } else {\r\n buffer.push(line);\r\n }\r\n }\r\n\r\n // Save last slot\r\n slots[currentSlot] = buffer.join('\\n').trim();\r\n\r\n return slots;\r\n}\r\n"],"mappings":"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","names":["text","classes","id"]}
1
+ {"version":3,"sources":["../core/utils.ts","../core/parser.ts"],"sourcesContent":["import type { CSSProperties } from './types';\r\n\r\n/**\r\n * Parse an inline CSS string (e.g. \"color: red; padding: 1rem\") into a CSSProperties object.\r\n */\r\nexport function parseCssString(cssText: string): CSSProperties {\r\n if (!cssText) return {};\r\n return cssText\r\n .split(';')\r\n .filter(Boolean)\r\n .reduce<CSSProperties>((styleObj, styleString) => {\r\n const parts = styleString.split(':');\r\n if (parts.length < 2) return styleObj;\r\n const key = parts[0].trim().replace(/-([a-z])/g, (_, g) => g.toUpperCase());\r\n const value = parts.slice(1).join(':').trim();\r\n styleObj[key] = value;\r\n return styleObj;\r\n }, {});\r\n}\r\n\r\n/**\r\n * Generate a URL-safe slug from text (NFD decomposition, strip accents, lowercase, hyphenate).\r\n */\r\nexport function generateId(text: string): string {\r\n return text\r\n .normalize('NFD')\r\n .replace(/[\\u0300-\\u036f]/g, '')\r\n .toLowerCase()\r\n .replace(/[^\\w\\s-]/g, '')\r\n .replace(/\\s+/g, '-');\r\n}\r\n\r\n/**\r\n * Smooth-scroll to an element by its ID.\r\n */\r\nexport function scrollToId(id: string): void {\r\n if (typeof document === 'undefined') return;\r\n const element = document.getElementById(id);\r\n if (element) {\r\n element.scrollIntoView({ behavior: 'smooth', block: 'start' });\r\n }\r\n}\r\n\r\n/**\r\n * Parse attribute suffix like `##{.my-class #my-id}` from a text line.\r\n * Returns the cleaned text, extracted classes, and id.\r\n */\r\nexport function extractAttributes(text: string): { text: string; classes: string; id: string } {\r\n const match = text.match(/^(.*?)\\s*##\\{([^}]*)\\}\\s*$/);\r\n if (!match) return { text, classes: '', id: '' };\r\n\r\n const rawAttrs = match[2];\r\n const cleanedText = match[1];\r\n\r\n const classList: string[] = [];\r\n let id = '';\r\n\r\n // 1. Parse key=\"value\" attributes (e.g., class=\"mt-0 px-4\", id=\"section\")\r\n for (const [, key, value] of rawAttrs.matchAll(/([\\w-]+)=\"([^\"]*)\"/g)) {\r\n if (key === 'class') {\r\n classList.push(...value.split(/\\s+/).filter(Boolean));\r\n } else if (key === 'id') {\r\n id = value;\r\n }\r\n }\r\n\r\n // 2. Parse shorthand tokens: .className and #id (from remaining content)\r\n // Supports classes with / (opacity), ! (important), . (arbitrary values)\r\n const stripped = rawAttrs.replace(/[\\w-]+=\"[^\"]*\"/g, '');\r\n for (const token of stripped.split(/\\s+/).filter(Boolean)) {\r\n if (token.startsWith('.')) classList.push(token.slice(1));\r\n else if (token.startsWith('#') && !id) id = token.slice(1);\r\n }\r\n\r\n return { text: cleanedText, classes: classList.join(' '), id };\r\n}\r\n\r\nlet _scopeCounter = 0;\r\nexport function resetScopeCounter(): void {\r\n _scopeCounter = 0;\r\n}\r\n\r\n/**\r\n * Generate a unique scope ID for CSS isolation.\r\n */\r\nexport function generateScopeId(): string {\r\n return `scope-${++_scopeCounter}`;\r\n}\r\n\r\n/**\r\n * Parse props from a `{key=\"value\" key2=\"value2\"}` string.\r\n * Also supports `.className` shorthand → adds to `class` prop.\r\n * Also supports `#id` shorthand → adds to `id` prop.\r\n */\r\nexport function parseProps(propsString: string): Record<string, string> {\r\n const props: Record<string, string> = {};\r\n if (!propsString?.trim()) return props;\r\n\r\n // Match key=\"value\" or key='value' pairs\r\n const pairRegex = /(\\w[\\w-]*)=(?:\"([^\"]*)\"|'([^']*)')/g;\r\n let match;\r\n while ((match = pairRegex.exec(propsString)) !== null) {\r\n const key = match[1];\r\n const value = match[2] ?? match[3] ?? '';\r\n props[key] = value;\r\n }\r\n\r\n // Extract .className shorthand (supports / for opacity, ! for important, . for arbitrary values)\r\n const classMatches = propsString.match(/\\.([a-zA-Z0-9_!/.\\-]+)/g);\r\n if (classMatches) {\r\n const existing = props['class'] || '';\r\n const newClasses = classMatches.map(c => c.substring(1)).join(' ');\r\n props['class'] = existing ? `${existing} ${newClasses}` : newClasses;\r\n }\r\n\r\n // Extract #id shorthand (only if not inside a key=\"value\" pair)\r\n const idMatch = propsString.match(/#([a-zA-Z0-9_-]+)(?=\\s|}|$)/);\r\n if (idMatch && !props['id']) {\r\n props['id'] = idMatch[1];\r\n }\r\n\r\n return props;\r\n}\r\n\r\n/**\r\n * Parse raw HTML attributes string (e.g. `class=\"...\" style=\"...\" data-foo=\"...\"`)\r\n * into a plain props object.\r\n *\r\n * NOTE: This does NOT rename `class` → `className`. Framework adapters\r\n * (React, Vue, etc.) should handle their own attribute name mapping.\r\n */\r\nexport function parseHtmlAttrs(attrsString: string): Record<string, any> {\r\n const props: Record<string, any> = {};\r\n if (!attrsString?.trim()) return props;\r\n\r\n const pairRegex = /([a-zA-Z0-9_-]+)(?:=(?:\"([^\"]*)\"|'([^']*)'|([^\\s>]+)))?/g;\r\n let match;\r\n while ((match = pairRegex.exec(attrsString)) !== null) {\r\n const key = match[1];\r\n const value = match[2] ?? match[3] ?? match[4] ?? true;\r\n\r\n // Parse style strings into objects\r\n if (key === 'style' && typeof value === 'string') {\r\n props[key] = parseCssString(value);\r\n } else {\r\n props[key] = value;\r\n }\r\n }\r\n\r\n return props;\r\n}\r\n","import type { Token, DirectiveToken, HtmlBlockToken, CSSProperties } from './types';\r\nimport { generateId, generateScopeId, parseProps, extractAttributes } from './utils';\r\n\r\n/**\r\n * V2 Markdown Parser — line-by-line state machine (framework-agnostic).\r\n */\r\nexport function parseMarkdown(markdown: string): Token[] {\r\n if (!markdown) return [];\r\n const lines = markdown.replace(/\\r\\n/g, '\\n').replace(/\\r/g, '').split('\\n');\r\n const result: Token[] = [];\r\n let i = 0;\r\n\r\n while (i < lines.length) {\r\n const line = lines[i];\r\n const trimmed = line.trim();\r\n let match: RegExpMatchArray | null;\r\n\r\n // ── Headers: ## Title ──\r\n if ((match = trimmed.match(/^(#{1,6})\\s+(.+)$/))) {\r\n const level = match[1].length;\r\n const rawText = match[2];\r\n const { text, classes, id: customId } = extractAttributes(rawText);\r\n const id = customId || generateId(text.replace(/->|<-/g, ''));\r\n result.push({ type: 'header', level, text, id, classes: classes || undefined });\r\n i++;\r\n continue;\r\n }\r\n\r\n // ── Aligned paragraph: -> text <- or -> text -> ──\r\n if ((match = trimmed.match(/^->\\s*(.+?)\\s*(<-|->)\\s*$/))) {\r\n const content = match[1];\r\n const align = match[2] === '<-' ? 'center' : 'right';\r\n result.push({ type: 'paragraph', content, align });\r\n i++;\r\n continue;\r\n }\r\n\r\n // ── Code block: ```lang title=\"name\" ──\r\n if (trimmed.startsWith('```')) {\r\n const fenceHeader = trimmed.slice(3).trim();\r\n const titleMatch = fenceHeader.match(/title=[\"']([^\"']*)[\"']/);\r\n const lang = fenceHeader.replace(/title=[\"'][^\"']*[\"']/, '').trim();\r\n const title = titleMatch ? titleMatch[1] : undefined;\r\n const content: string[] = [];\r\n i++;\r\n while (i < lines.length && !lines[i].trim().startsWith('```')) {\r\n content.push(lines[i]);\r\n i++;\r\n }\r\n result.push({ type: 'codeblock', language: lang, title, content: content.join('\\n') });\r\n i++; // skip closing ```\r\n continue;\r\n }\r\n\r\n // ── Directive: :::type {props} ... ::: ──\r\n if (trimmed.startsWith(':::')) {\r\n const rest = trimmed.slice(3).trim();\r\n\r\n // Bare closing marker\r\n if (rest === '') {\r\n result.push({ type: 'paragraph', content: line });\r\n i++;\r\n continue;\r\n }\r\n\r\n const typeMatch = rest.match(/^([\\w-]+)/);\r\n const directiveType = typeMatch ? typeMatch[1] : 'custom';\r\n\r\n // Lookahead: find the matching closing :::\r\n let j = i + 1;\r\n let nestedLevel = 0;\r\n let foundClose = false;\r\n\r\n while (j < lines.length) {\r\n const currentTrimmed = lines[j].trim();\r\n if (currentTrimmed === ':::') {\r\n if (nestedLevel === 0) {\r\n foundClose = true;\r\n break;\r\n } else {\r\n nestedLevel--;\r\n }\r\n } else if (currentTrimmed.startsWith(':::')) {\r\n // Opening a nested directive\r\n nestedLevel++;\r\n }\r\n j++;\r\n }\r\n\r\n if (foundClose) {\r\n // Collect raw content lines (between opening and closing)\r\n const contentLines: string[] = [];\r\n for (let k = i + 1; k < j; k++) {\r\n contentLines.push(lines[k]);\r\n }\r\n const rawContent = contentLines.join('\\n');\r\n\r\n // Parse the directive header (everything after the type name)\r\n const headerRest = typeMatch ? rest.slice(directiveType.length).trim() : rest;\r\n\r\n // Extract {props} block\r\n let propsString = '';\r\n let shortForm = '';\r\n const propsBlockMatch = headerRest.match(/^\\{([^]*)\\}\\s*$/);\r\n if (propsBlockMatch) {\r\n propsString = propsBlockMatch[1];\r\n } else if (headerRest) {\r\n // Short-form: bare text after type → becomes title prop\r\n shortForm = headerRest;\r\n }\r\n\r\n const props = parseProps(propsString);\r\n if (shortForm && !props['title']) {\r\n props['title'] = shortForm;\r\n }\r\n\r\n // Split content into slots\r\n const slots = splitSlots(rawContent);\r\n\r\n result.push({\r\n type: 'directive',\r\n directiveType,\r\n props,\r\n slots,\r\n scopeId: generateScopeId(),\r\n } as DirectiveToken);\r\n\r\n i = j + 1;\r\n continue;\r\n } else {\r\n // Unclosed directive — render as plain text\r\n result.push({ type: 'paragraph', content: line });\r\n i++;\r\n continue;\r\n }\r\n }\r\n\r\n // ── Image: ![alt](src#float#3d){w:h} ──\r\n if ((match = trimmed.match(/^(.*?)!\\[([^\\]]*)\\]\\(([^)]+?)\\)(?:\\{([^}]+?)\\})?(.*)$/))) {\r\n const [, preText, alt, srcAndFloat, size, postText] = match;\r\n\r\n if (preText.trim()) {\r\n result.push({ type: 'paragraph', content: preText.trim() });\r\n }\r\n\r\n let src = srcAndFloat;\r\n const style: CSSProperties = {};\r\n if (src.includes('#left')) {\r\n src = src.replace('#left', '');\r\n style.float = 'left';\r\n style.margin = '0 1em 1em 0';\r\n } else if (src.includes('#right')) {\r\n src = src.replace('#right', '');\r\n style.float = 'right';\r\n style.margin = '0 0 1em 1em';\r\n } else if (src.includes('#center')) {\r\n src = src.replace('#center', '');\r\n style.display = 'block';\r\n style.margin = '0 auto 1em auto';\r\n }\r\n if (size) {\r\n const [width, height] = size.split(':');\r\n if (width) style.width = width.trim();\r\n if (height) style.height = height.trim();\r\n }\r\n result.push({ type: 'image', alt, src, style });\r\n\r\n if (postText.trim()) {\r\n result.push({ type: 'paragraph', content: postText.trim() });\r\n }\r\n i++;\r\n continue;\r\n }\r\n\r\n // ── Table: | cell | cell | ──\r\n if (trimmed.includes('|') && i + 1 < lines.length && lines[i + 1].includes('---')) {\r\n const tableLines = [line];\r\n i++;\r\n tableLines.push(lines[i]);\r\n i++;\r\n while (i < lines.length && lines[i].trim().includes('|')) {\r\n tableLines.push(lines[i]);\r\n i++;\r\n }\r\n result.push({ type: 'table', content: tableLines.join('\\n') });\r\n continue;\r\n }\r\n\r\n // ── List: - item or 1. item ──\r\n if ((match = trimmed.match(/^(\\s*)([-*+]|\\d+\\.)\\s+(.+)$/))) {\r\n const listItems = [line];\r\n i++;\r\n while (i < lines.length) {\r\n const nextLine = lines[i];\r\n const nextTrimmed = nextLine.trim();\r\n if (\r\n nextTrimmed.match(/^(\\s*)([-*+]|\\d+\\.)\\s+(.+)$/) ||\r\n nextTrimmed === '' ||\r\n nextLine.startsWith(' ')\r\n ) {\r\n listItems.push(nextLine);\r\n i++;\r\n } else {\r\n break;\r\n }\r\n }\r\n result.push({ type: 'list', content: listItems.join('\\n') });\r\n continue;\r\n }\r\n\r\n // ── Blockquote: > text ──\r\n if (trimmed.startsWith('>')) {\r\n const quoteLines = [line];\r\n i++;\r\n while (i < lines.length && (lines[i].trim().startsWith('>') || lines[i].trim() === '')) {\r\n quoteLines.push(lines[i]);\r\n i++;\r\n }\r\n const rawQuote = quoteLines.join('\\n').replace(/^>\\s?/gm, '');\r\n const { text, classes, id } = extractAttributes(rawQuote);\r\n result.push({ type: 'blockquote', content: text, classes: classes || undefined, id });\r\n continue;\r\n }\r\n\r\n // ── Horizontal rule: --- or ___ or *** ──\r\n if (/^(---|___|(\\*\\s*){3,})\\s*$/.test(trimmed)) {\r\n result.push({ type: 'hr' });\r\n i++;\r\n continue;\r\n }\r\n\r\n // ── TOC: [TOC] or [TOC2] ──\r\n if (/^\\[TOC\\d?\\]\\s*$/.test(trimmed)) {\r\n result.push({ type: 'toc' });\r\n i++;\r\n continue;\r\n }\r\n\r\n // ── Empty line ──\r\n if (trimmed === '') {\r\n i++;\r\n continue;\r\n }\r\n\r\n // ── HTML Block: <tag ...> ──\r\n let tagStartMatch = trimmed.match(/^<([a-zA-Z][\\w-]*)/);\r\n if (tagStartMatch) {\r\n const tagName = tagStartMatch[1].toLowerCase();\r\n\r\n const voidElements = new Set([\r\n 'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input',\r\n 'link', 'meta', 'param', 'source', 'track', 'wbr'\r\n ]);\r\n\r\n const remainingText = lines.slice(i).join('\\n');\r\n\r\n // Find the full opening tag even with multi-line attributes\r\n const openTagRegex = new RegExp(`^\\\\s*<${tagName}\\\\b([^>]*?)>`, 'i');\r\n const openTagMatch = remainingText.match(openTagRegex);\r\n\r\n if (openTagMatch) {\r\n const fullOpenTag = openTagMatch[0];\r\n const attrs = openTagMatch[1].replace(/\\s+/g, ' ').trim();\r\n\r\n const isSelfClosing = fullOpenTag.endsWith('/>') || voidElements.has(tagName);\r\n\r\n if (isSelfClosing) {\r\n const blockText = remainingText.substring(0, openTagMatch.index! + fullOpenTag.length);\r\n const consumedLines = blockText.split('\\n').length;\r\n\r\n result.push({\r\n type: 'html-block',\r\n tag: tagName,\r\n attrs: attrs,\r\n children: [] // No children\r\n } as HtmlBlockToken);\r\n\r\n i += consumedLines;\r\n continue;\r\n } else {\r\n // Tag with content — search for its closing tag\r\n let nestedLevel = 0;\r\n let closeIndex = -1;\r\n let closeTagLength = 0;\r\n\r\n const tagRegex = new RegExp(`</?${tagName}\\\\b[^>]*>`, 'gi');\r\n tagRegex.lastIndex = openTagMatch.index! + fullOpenTag.length;\r\n\r\n let execMatch;\r\n while ((execMatch = tagRegex.exec(remainingText)) !== null) {\r\n if (execMatch[0].startsWith('</')) {\r\n nestedLevel--;\r\n if (nestedLevel < 0) {\r\n closeIndex = execMatch.index;\r\n closeTagLength = execMatch[0].length;\r\n break;\r\n }\r\n } else {\r\n if (!execMatch[0].endsWith('/>')) {\r\n nestedLevel++;\r\n }\r\n }\r\n }\r\n\r\n if (closeIndex !== -1) {\r\n const fullBlock = remainingText.substring(0, closeIndex + closeTagLength);\r\n const consumedLines = fullBlock.split('\\n').length;\r\n\r\n // style/script blocks should not be parsed as Markdown\r\n if (tagName === 'style' || tagName === 'script') {\r\n result.push({\r\n type: 'html',\r\n content: fullBlock,\r\n scopeId: generateScopeId(),\r\n });\r\n } else {\r\n const innerContent = remainingText.substring(openTagMatch.index! + fullOpenTag.length, closeIndex);\r\n result.push({\r\n type: 'html-block',\r\n tag: tagName,\r\n attrs: attrs,\r\n children: parseMarkdown(innerContent)\r\n } as HtmlBlockToken);\r\n }\r\n\r\n i += consumedLines;\r\n continue;\r\n } else {\r\n // Fallback: unclosed tag → treat as self-closing to avoid consuming the whole document\r\n const blockText = remainingText.substring(0, openTagMatch.index! + fullOpenTag.length);\r\n const consumedLines = blockText.split('\\n').length;\r\n\r\n result.push({\r\n type: 'html-block',\r\n tag: tagName,\r\n attrs: attrs,\r\n children: []\r\n } as HtmlBlockToken);\r\n\r\n i += consumedLines;\r\n continue;\r\n }\r\n }\r\n }\r\n }\r\n\r\n // ── Paragraph (default) ──\r\n const paragraphLines = [line];\r\n i++;\r\n while (i < lines.length) {\r\n const nextLine = lines[i];\r\n const nextTrimmed = nextLine.trim();\r\n if (\r\n nextTrimmed === '' ||\r\n nextTrimmed.startsWith('#') ||\r\n nextTrimmed.startsWith(':::') ||\r\n nextTrimmed.includes('|') ||\r\n nextTrimmed.match(/^(\\s*)([-*+]|\\d+\\.)\\s+/) ||\r\n nextTrimmed.startsWith('>') ||\r\n nextTrimmed.startsWith('```') ||\r\n nextTrimmed.startsWith('->') ||\r\n nextTrimmed.match(/^<([a-zA-Z][\\w-]*)\\b/)\r\n ) {\r\n break;\r\n }\r\n paragraphLines.push(nextLine);\r\n i++;\r\n }\r\n const rawParagraph = paragraphLines.join('\\n').trim();\r\n const { text, classes, id } = extractAttributes(rawParagraph);\r\n result.push({ type: 'paragraph', content: text, classes: classes || undefined, id });\r\n }\r\n\r\n return result;\r\n}\r\n\r\n// ─────────────────────────────────────────────\r\n// Slot splitting\r\n// ─────────────────────────────────────────────\r\n\r\n/**\r\n * Split directive content into named slots.\r\n * A line that is exactly `#slotname` starts a new slot.\r\n * Content before any `#slotname` goes into the \"default\" slot.\r\n *\r\n * IMPORTANT: This is nesting-aware — `#slotname` markers inside nested\r\n * directives (:::child ... :::) are NOT treated as slot boundaries of\r\n * the outer directive. Only `#slotname` at depth 0 are considered.\r\n */\r\nfunction splitSlots(rawContent: string): Record<string, string> {\r\n const slots: Record<string, string> = {};\r\n const lines = rawContent.split('\\n');\r\n let currentSlot = 'default';\r\n let buffer: string[] = [];\r\n let nestingDepth = 0;\r\n\r\n for (const line of lines) {\r\n const trimmed = line.trim();\r\n\r\n // Track nesting of directives\r\n if (trimmed.startsWith(':::')) {\r\n const rest = trimmed.slice(3).trim();\r\n if (rest === '') {\r\n // Closing marker (bare :::)\r\n nestingDepth = Math.max(0, nestingDepth - 1);\r\n } else {\r\n nestingDepth++;\r\n }\r\n }\r\n\r\n // Only consider slot boundaries at depth 0\r\n if (nestingDepth === 0 && trimmed.match(/^#([\\w-]+)$/)) {\r\n // Save previous slot\r\n if (buffer.length > 0 || currentSlot !== 'default') {\r\n slots[currentSlot] = buffer.join('\\n').trim();\r\n }\r\n currentSlot = trimmed.slice(1);\r\n buffer = [];\r\n } else {\r\n buffer.push(line);\r\n }\r\n }\r\n\r\n // Save last slot\r\n slots[currentSlot] = buffer.join('\\n').trim();\r\n\r\n return slots;\r\n}\r\n"],"mappings":"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","names":["text","classes","id"]}
package/dist/index.cjs CHANGED
@@ -1688,7 +1688,7 @@ function parseHtmlAttrs(attrsString) {
1688
1688
  // core/parser.ts
1689
1689
  function parseMarkdown(markdown2) {
1690
1690
  if (!markdown2) return [];
1691
- const lines = markdown2.split("\n");
1691
+ const lines = markdown2.replace(/\r\n/g, "\n").replace(/\r/g, "").split("\n");
1692
1692
  const result = [];
1693
1693
  let i = 0;
1694
1694
  while (i < lines.length) {