UNPKG

md2hwp

Version:

Convert Markdown to HWP (Hangul Word Processor) format

242 lines (241 loc) 8.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.MarkdownParser = void 0; const marked_1 = require("marked"); class MarkdownParser { parse(markdown) { const tokens = marked_1.marked.lexer(markdown); return this.tokensToContent(tokens); } tokensToContent(tokens) { const contents = []; for (const token of tokens) { const content = this.tokenToContent(token); if (content) { if (Array.isArray(content)) { contents.push(...content); } else { contents.push(content); } } } return contents; } tokenToContent(token) { switch (token.type) { case 'heading': return this.parseHeading(token); case 'paragraph': return this.parseParagraph(token); case 'list': return this.parseList(token); case 'table': return this.parseTable(token); case 'code': return this.parseCode(token); case 'space': return null; default: if ('text' in token) { return { type: 'paragraph', content: token.text }; } return null; } } parseHeading(token) { return { type: 'heading', level: token.depth, content: this.extractText(token.text) }; } parseParagraph(token) { const children = this.parseInlineTokens(token.text); if (children.length === 1 && !children[0].style) { return { type: 'paragraph', content: children[0].content }; } return { type: 'paragraph', children }; } parseInlineTokens(text) { const tokens = marked_1.marked.lexer(text, { breaks: true }); const inlineTokens = []; for (const token of tokens) { if ('tokens' in token && Array.isArray(token.tokens)) { inlineTokens.push(...token.tokens); } } if (inlineTokens.length === 0) { return [{ type: 'paragraph', content: text }]; } const contents = []; for (const token of inlineTokens) { if (token.type === 'text') { contents.push({ type: 'paragraph', content: token.text }); } else if (token.type === 'strong') { contents.push({ type: 'paragraph', content: this.extractText(token.text), style: { bold: true } }); } else if (token.type === 'em') { contents.push({ type: 'paragraph', content: this.extractText(token.text), style: { italic: true } }); } else if (token.type === 'codespan') { contents.push({ type: 'paragraph', content: token.text, style: {} }); } else if (token.type === 'link') { contents.push({ type: 'paragraph', content: `${token.text} (${token.href})` }); } else if (token.type === 'image') { contents.push({ type: 'image', src: token.href, alt: token.text }); } } return contents.length > 0 ? contents : [{ type: 'paragraph', content: text }]; } parseList(token) { const children = []; for (const item of token.items) { // Check if item has nested tokens (including nested lists) if ('tokens' in item && Array.isArray(item.tokens) && item.tokens.length > 0) { // Parse each token in the item (text, nested lists, etc.) for (const subToken of item.tokens) { // For text tokens within lists, parse inline elements if (subToken.type === 'text' && 'text' in subToken) { const inlineElements = this.parseInlineTokens(subToken.text); if (inlineElements.length > 1) { children.push({ type: 'paragraph', children: inlineElements }); } else if (inlineElements.length === 1) { children.push(inlineElements[0]); } } else { // For other tokens (lists, etc.), parse normally const parsed = this.tokenToContent(subToken); if (parsed) { if (Array.isArray(parsed)) { children.push(...parsed); } else { children.push(parsed); } } } } } else { // Fallback: Parse inline elements (bold, italic, etc.) within list items const inlineElements = this.parseInlineTokens(item.text); // Handle list items with mixed content (bold + normal text) if (inlineElements.length > 1) { // Create a paragraph with children for mixed content children.push({ type: 'paragraph', children: inlineElements }); } else if (inlineElements.length === 1 && !inlineElements[0].style) { // Single plain text element - add as simple paragraph children.push({ type: 'paragraph', content: inlineElements[0].content }); } else if (inlineElements.length === 1) { // Single styled element - keep children structure children.push({ type: 'paragraph', children: inlineElements }); } else { // Fallback to plain text const text = this.extractText(item.text); children.push({ type: 'paragraph', content: text }); } } } return { type: 'list', children }; } parseTable(token) { const rows = []; if (token.header && token.header.length > 0) { const headerCells = token.header.map(cell => ({ content: this.extractText(cell.text) })); rows.push({ cells: headerCells }); } for (const row of token.rows) { const cells = row.map(cell => ({ content: this.extractText(cell.text) })); rows.push({ cells }); } return { type: 'table', rows }; } parseCode(token) { return { type: 'code', content: token.text, language: token.lang || undefined }; } extractText(input) { if (typeof input === 'string') { return input; } if (input && typeof input === 'object' && 'text' in input) { return this.extractText(input.text); } return String(input); } } exports.MarkdownParser = MarkdownParser;