UNPKG

ai-knowledge-hub

Version:

MCP server that provides unified access to organizational knowledge across multiple platforms (local docs, Guru, Notion)

175 lines 5.7 kB
/** * High-Level Conversion Utilities * Main entry points for markdown <-> notion conversions plus helper utilities */ import { MarkdownParser } from './markdown-parser.js'; import { markdownASTToNotionBlocks } from './markdown-to-notion.js'; import { notionBlocksToMarkdown } from './notion-to-markdown.js'; import { DEFAULT_CONVERSION_OPTIONS, } from '../types/markdown.js'; /** * Convert markdown content to Notion blocks */ export function markdownToNotion(markdown, options = {}) { try { const conversionOptions = { ...DEFAULT_CONVERSION_OPTIONS, ...options, }; const parser = new MarkdownParser({ extractMetadata: true, validateSyntax: true, }); // Parse markdown to AST const ast = parser.parseToAST(markdown); // Convert AST to Notion blocks const result = markdownASTToNotionBlocks(ast, conversionOptions); return result; } catch (error) { throw new Error(`Markdown to Notion conversion failed: ${error instanceof Error ? error.message : String(error)}`); } } /** * Convert Notion blocks to markdown */ export function notionToMarkdown(blocks, options = {}) { try { const conversionOptions = { ...DEFAULT_CONVERSION_OPTIONS, ...options, }; const result = notionBlocksToMarkdown(blocks, conversionOptions); return result; } catch (error) { throw new Error(`Notion to Markdown conversion failed: ${error instanceof Error ? error.message : String(error)}`); } } // ======================================== // UTILITY FUNCTIONS // ======================================== /** * Parse markdown and extract title */ export function extractTitleFromMarkdown(markdown) { const parser = new MarkdownParser({ extractMetadata: true, validateSyntax: true, }); const doc = parser.parseDocument(markdown, 'temp.md'); return doc.metadata.title ?? null; } /** * Extract page title from Notion page properties */ export function extractPageTitle(page) { const properties = page.properties ?? {}; // Find the property with type "title" for (const [_propertyName, property] of Object.entries(properties)) { const typedProperty = property; if (typedProperty?.type === 'title') { const titleContent = typedProperty.title?.[0]?.text?.content; if (titleContent !== null && titleContent !== undefined && titleContent.length > 0) { return titleContent; } } } // Fallback to common property names const titleProperty = (properties.title ?? properties.Title ?? properties.Name); return titleProperty?.title?.[0]?.text?.content ?? 'Untitled'; } /** * Validate markdown content */ export function validateMarkdown(content) { try { const parser = new MarkdownParser({ extractMetadata: true, validateSyntax: true, }); const _document = parser.parseDocument(content, 'temp.md'); const errors = []; const warnings = []; // Basic validation if (!content || content.trim().length === 0) { errors.push('Content is empty'); } if (content.length > 100000) { // 100KB limit warnings.push('Content is very large and may cause performance issues'); } return { isValid: errors.length === 0, errors, warnings, }; } catch (error) { return { isValid: false, errors: [`Parsing failed: ${error instanceof Error ? error.message : String(error)}`], warnings: [], }; } } /** * Extract headings from markdown content */ export function extractHeadings(markdown) { const parser = new MarkdownParser({ extractMetadata: true, validateSyntax: true, }); const doc = parser.parseDocument(markdown, 'temp.md'); return (doc.metadata.headings ?? []).map(h => ({ ...h, anchor: h.anchor ?? '' })); } /** * Calculate word count from markdown content */ export function getWordCount(markdown) { return markdown .replace(/[#*`_[\]()]/g, '') // Remove markdown syntax .split(/\s+/) .filter(word => word.length > 0).length; } /** * Check if content contains frontmatter */ export function hasFrontmatter(markdown) { return /^---\s*\n[\s\S]*?\n---\s*\n/.test(markdown); } /** * Remove frontmatter from markdown content */ export function removeFrontmatter(markdown) { return markdown.replace(/^---\s*\n[\s\S]*?\n---\s*\n/, '').trim(); } /** * Extract frontmatter as object */ export function extractFrontmatter(markdown) { const frontMatterMatch = markdown.match(/^---\s*\n([\s\S]*?)\n---\s*\n/); if (!frontMatterMatch) { return {}; } const frontMatter = {}; const yamlContent = frontMatterMatch[1]; if (yamlContent) { yamlContent.split('\n').forEach(line => { const match = line.match(/^(\w+):\s*(.+)$/); if (match) { const [, key, value] = match; if (key && value) { // Handle arrays (simple case) if (value.startsWith('[') && value.endsWith(']')) { frontMatter[key] = value.slice(1, -1).split(',').map(s => s.trim().replace(/['"]/g, '')); } else { frontMatter[key] = value.replace(/['"]/g, ''); } } } }); } return frontMatter; } //# sourceMappingURL=converters.js.map