{"version":3,"file":"kolkov-angular-editor-markdown.mjs","names":[],"sources":["../../../projects/angular-editor/markdown/src/types.ts","../../../projects/angular-editor/markdown/src/html-preprocessor.ts","../../../projects/angular-editor/markdown/src/markdown-postprocessor.ts","../../../projects/angular-editor/markdown/src/default-markdown-converter.ts","../../../projects/angular-editor/markdown/src/adapters/turndown-adapter.ts","../../../projects/angular-editor/markdown/src/adapters/marked-adapter.ts","../../../projects/angular-editor/markdown/src/provide.ts"],"sourcesContent":["export interface HtmlToMarkdownRenderer {\n  render(html: string): string;\n}\n\nexport interface MarkdownToHtmlRenderer {\n  render(markdown: string): string;\n}\n\nexport interface MarkdownConversionConfig {\n  gfm?: boolean;\n  headingStyle?: 'atx' | 'setext';\n  bulletListMarker?: '-' | '*' | '+';\n  codeBlockStyle?: 'fenced' | 'indented';\n  emDelimiter?: '*' | '_';\n  strongDelimiter?: '**' | '__';\n  linkStyle?: 'inlined' | 'referenced';\n}\n\nexport const DEFAULT_CONVERSION_CONFIG: MarkdownConversionConfig = {\n  gfm: true,\n  headingStyle: 'atx',\n  bulletListMarker: '-',\n  codeBlockStyle: 'fenced',\n  emDelimiter: '*',\n  strongDelimiter: '**',\n  linkStyle: 'inlined',\n};\n\nexport type { MarkdownConverter } from '@kolkov/angular-editor';\n","export function preprocessHtml(html: string): string {\n  if (!html || html === '<br>' || html.trim() === '') {\n    return '';\n  }\n\n  let result = html;\n\n  // Normalize &nbsp; to regular space\n  result = result.replace(/&nbsp;/g, ' ');\n\n  // Remove zero-width spaces\n  result = result.replace(/[\\u200B\\uFEFF]/g, '');\n\n  // Normalize <br> variants\n  result = result.replace(/<br\\s*\\/?>/gi, '<br>');\n\n  // Remove empty spans (execCommand artifacts)\n  result = result.replace(/<span[^>]*>\\s*<\\/span>/gi, '');\n\n  // Remove font tags but keep content (legacy execCommand output)\n  result = result.replace(/<\\/?font[^>]*>/gi, '');\n\n  // Collapse multiple consecutive <br> into paragraph breaks\n  result = result.replace(/(<br>\\s*){3,}/gi, '<br><br>');\n\n  return result.trim();\n}\n","export function postprocessMarkdown(markdown: string): string {\n  if (!markdown) {\n    return '';\n  }\n\n  let result = markdown;\n\n  // Trim trailing whitespace from each line\n  result = result.replace(/[ \\t]+$/gm, '');\n\n  // Normalize line endings\n  result = result.replace(/\\r\\n/g, '\\n');\n\n  // Collapse 3+ consecutive blank lines into 2\n  result = result.replace(/\\n{3,}/g, '\\n\\n');\n\n  // Ensure single trailing newline\n  result = result.trimEnd() + '\\n';\n\n  // But if result is only whitespace, return empty\n  if (result.trim() === '') {\n    return '';\n  }\n\n  return result;\n}\n","import type { MarkdownConverter } from '@kolkov/angular-editor';\nimport {\n  MarkdownConversionConfig,\n  HtmlToMarkdownRenderer,\n  MarkdownToHtmlRenderer,\n  DEFAULT_CONVERSION_CONFIG,\n} from './types';\nimport { preprocessHtml } from './html-preprocessor';\nimport { postprocessMarkdown } from './markdown-postprocessor';\n\nexport class DefaultMarkdownConverter implements MarkdownConverter {\n  constructor(\n    private htmlToMd: HtmlToMarkdownRenderer,\n    private mdToHtml: MarkdownToHtmlRenderer,\n    private config: MarkdownConversionConfig = DEFAULT_CONVERSION_CONFIG,\n  ) {}\n\n  toMarkdown(html: string): string {\n    const preprocessed = preprocessHtml(html);\n    if (!preprocessed) {\n      return '';\n    }\n    const raw = this.htmlToMd.render(preprocessed);\n    return postprocessMarkdown(raw);\n  }\n\n  toHtml(markdown: string): string {\n    if (!markdown || markdown.trim() === '') {\n      return '';\n    }\n    return this.mdToHtml.render(markdown);\n  }\n}\n","import TurndownService from 'turndown';\nimport { HtmlToMarkdownRenderer, MarkdownConversionConfig, DEFAULT_CONVERSION_CONFIG } from '../types';\n\nexport class TurndownAdapter implements HtmlToMarkdownRenderer {\n  private turndown: TurndownService;\n\n  constructor(config: MarkdownConversionConfig = DEFAULT_CONVERSION_CONFIG) {\n    this.turndown = new TurndownService({\n      headingStyle: config.headingStyle || 'atx',\n      bulletListMarker: config.bulletListMarker || '-',\n      codeBlockStyle: config.codeBlockStyle || 'fenced',\n      emDelimiter: config.emDelimiter || '*',\n      strongDelimiter: config.strongDelimiter || '**',\n      linkStyle: config.linkStyle || 'inlined',\n    });\n\n    if (config.gfm !== false) {\n      this.addGfmRules();\n    }\n\n    this.addCleanupRules();\n  }\n\n  render(html: string): string {\n    return this.turndown.turndown(html);\n  }\n\n  private addCleanupRules(): void {\n    this.turndown.addRule('preWithoutCode', {\n      filter: (node) => {\n        return node.nodeName === 'PRE' &&\n          !(node.firstChild && node.firstChild.nodeName === 'CODE');\n      },\n      replacement: (_content, node) => {\n        const code = (node as HTMLElement).textContent || '';\n        return '\\n\\n```\\n' + code.replace(/\\n$/, '') + '\\n```\\n\\n';\n      },\n    });\n  }\n\n  private addGfmRules(): void {\n    this.turndown.addRule('strikethrough', {\n      filter: ['del', 's'],\n      replacement: (content) => `~~${content}~~`,\n    });\n\n    this.turndown.addRule('taskListItem', {\n      filter: (node) => {\n        return node.nodeName === 'LI' &&\n          node.firstElementChild?.nodeName === 'INPUT' &&\n          (node.firstElementChild as HTMLInputElement).type === 'checkbox';\n      },\n      replacement: (content, node) => {\n        const checkbox = (node as HTMLElement).firstElementChild as HTMLInputElement;\n        const checked = checkbox.checked ? 'x' : ' ';\n        const text = content.replace(/^\\s*\\[[ x]\\]\\s*/, '').trim();\n        return `- [${checked}] ${text}\\n`;\n      },\n    });\n  }\n}\n","import { marked } from 'marked';\nimport { MarkdownToHtmlRenderer, MarkdownConversionConfig, DEFAULT_CONVERSION_CONFIG } from '../types';\n\nexport class MarkedAdapter implements MarkdownToHtmlRenderer {\n  constructor(config: MarkdownConversionConfig = DEFAULT_CONVERSION_CONFIG) {\n    marked.setOptions({\n      gfm: config.gfm !== false,\n      breaks: true,\n    });\n  }\n\n  render(markdown: string): string {\n    const result = marked.parse(markdown, { async: false });\n    return (typeof result === 'string' ? result : '').trim();\n  }\n}\n","import { Provider } from '@angular/core';\nimport { AE_MARKDOWN_CONVERTER } from './token';\nimport { DefaultMarkdownConverter } from './default-markdown-converter';\nimport { TurndownAdapter } from './adapters/turndown-adapter';\nimport { MarkedAdapter } from './adapters/marked-adapter';\nimport { MarkdownConversionConfig, DEFAULT_CONVERSION_CONFIG } from './types';\n\nexport function provideMarkdownConverter(config?: MarkdownConversionConfig): Provider {\n  return {\n    provide: AE_MARKDOWN_CONVERTER,\n    useFactory: () => {\n      const mergedConfig = { ...DEFAULT_CONVERSION_CONFIG, ...config };\n      return new DefaultMarkdownConverter(\n        new TurndownAdapter(mergedConfig),\n        new MarkedAdapter(mergedConfig),\n        mergedConfig,\n      );\n    },\n  };\n}\n"],"mappings":"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"}