@sigx/ssg 0.1.6

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.
Files changed (70) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +358 -0
  3. package/dist/build.d.ts +17 -0
  4. package/dist/build.d.ts.map +1 -0
  5. package/dist/build.js +309 -0
  6. package/dist/build.js.map +1 -0
  7. package/dist/cli.d.ts +3 -0
  8. package/dist/cli.d.ts.map +1 -0
  9. package/dist/cli.js +62 -0
  10. package/dist/cli.js.map +1 -0
  11. package/dist/client.d.ts +28 -0
  12. package/dist/client.d.ts.map +1 -0
  13. package/dist/client.js +38 -0
  14. package/dist/client.js.map +1 -0
  15. package/dist/config.d.ts +33 -0
  16. package/dist/config.d.ts.map +1 -0
  17. package/dist/dev.d.ts +43 -0
  18. package/dist/dev.d.ts.map +1 -0
  19. package/dist/dev.js +71 -0
  20. package/dist/dev.js.map +1 -0
  21. package/dist/errors.d.ts +58 -0
  22. package/dist/errors.d.ts.map +1 -0
  23. package/dist/index.d.ts +14 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +58 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/layouts/index.d.ts +7 -0
  28. package/dist/layouts/index.d.ts.map +1 -0
  29. package/dist/layouts/resolver.d.ts +49 -0
  30. package/dist/layouts/resolver.d.ts.map +1 -0
  31. package/dist/layouts/virtual.d.ts +34 -0
  32. package/dist/layouts/virtual.d.ts.map +1 -0
  33. package/dist/mdx/frontmatter.d.ts +42 -0
  34. package/dist/mdx/frontmatter.d.ts.map +1 -0
  35. package/dist/mdx/index.d.ts +9 -0
  36. package/dist/mdx/index.d.ts.map +1 -0
  37. package/dist/mdx/plugin.d.ts +32 -0
  38. package/dist/mdx/plugin.d.ts.map +1 -0
  39. package/dist/mdx/rehype-headings.d.ts +39 -0
  40. package/dist/mdx/rehype-headings.d.ts.map +1 -0
  41. package/dist/mdx/shiki.d.ts +32 -0
  42. package/dist/mdx/shiki.d.ts.map +1 -0
  43. package/dist/plugin-DxH1VUGC.js +547 -0
  44. package/dist/plugin-DxH1VUGC.js.map +1 -0
  45. package/dist/routing/index.d.ts +12 -0
  46. package/dist/routing/index.d.ts.map +1 -0
  47. package/dist/routing/navigation.d.ts +44 -0
  48. package/dist/routing/navigation.d.ts.map +1 -0
  49. package/dist/routing/resolver.d.ts +66 -0
  50. package/dist/routing/resolver.d.ts.map +1 -0
  51. package/dist/routing/scanner.d.ts +60 -0
  52. package/dist/routing/scanner.d.ts.map +1 -0
  53. package/dist/routing/virtual-navigation.d.ts +39 -0
  54. package/dist/routing/virtual-navigation.d.ts.map +1 -0
  55. package/dist/routing/virtual.d.ts +28 -0
  56. package/dist/routing/virtual.d.ts.map +1 -0
  57. package/dist/sitemap.d.ts +55 -0
  58. package/dist/sitemap.d.ts.map +1 -0
  59. package/dist/types.d.ts +562 -0
  60. package/dist/types.d.ts.map +1 -0
  61. package/dist/virtual-entries-Bz97SKQ0.js +1053 -0
  62. package/dist/virtual-entries-Bz97SKQ0.js.map +1 -0
  63. package/dist/vite/index.d.ts +6 -0
  64. package/dist/vite/index.d.ts.map +1 -0
  65. package/dist/vite/plugin.d.ts +35 -0
  66. package/dist/vite/plugin.d.ts.map +1 -0
  67. package/dist/vite/plugin.js +3 -0
  68. package/dist/vite/virtual-entries.d.ts +59 -0
  69. package/dist/vite/virtual-entries.d.ts.map +1 -0
  70. package/package.json +92 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin-DxH1VUGC.js","names":[],"sources":["../src/mdx/shiki.ts","../src/mdx/rehype-headings.ts","../src/mdx/plugin.ts","../src/vite/plugin.ts"],"sourcesContent":["/**\r\n * Shiki syntax highlighting integration\r\n *\r\n * Provides code block highlighting for Markdown/MDX content.\r\n */\r\n\r\nimport { createHighlighter, type Highlighter, type BundledLanguage, type BundledTheme } from 'shiki';\r\nimport type { ShikiConfig } from '../types';\r\n\r\n/**\r\n * Cached highlighter instance\r\n */\r\nlet highlighterPromise: Promise<Highlighter> | null = null;\r\n\r\n/**\r\n * Default Shiki configuration\r\n */\r\nconst DEFAULT_CONFIG: Required<ShikiConfig> = {\r\n light: 'github-light',\r\n dark: 'github-dark',\r\n langs: ['javascript', 'typescript', 'jsx', 'tsx', 'json', 'css', 'html', 'markdown', 'bash', 'shell'],\r\n};\r\n\r\n/**\r\n * Initialize or get the Shiki highlighter\r\n */\r\nexport async function getHighlighter(config?: ShikiConfig): Promise<Highlighter> {\r\n if (!highlighterPromise) {\r\n const mergedConfig = { ...DEFAULT_CONFIG, ...config };\r\n\r\n highlighterPromise = createHighlighter({\r\n themes: [mergedConfig.light as BundledTheme, mergedConfig.dark as BundledTheme],\r\n langs: mergedConfig.langs as BundledLanguage[],\r\n });\r\n }\r\n\r\n return highlighterPromise;\r\n}\r\n\r\n/**\r\n * Tab types for preview blocks\r\n */\r\nexport type TabType = 'preview' | 'code' | 'console';\r\n\r\n/**\r\n * Highlight code with Shiki\r\n */\r\nexport async function highlightCode(\r\n code: string,\r\n lang: string,\r\n config?: ShikiConfig,\r\n meta?: { filename?: string; live?: boolean; tabs?: TabType[] }\r\n): Promise<string> {\r\n const highlighter = await getHighlighter(config);\r\n const mergedConfig = { ...DEFAULT_CONFIG, ...config };\r\n\r\n // Check if language is loaded\r\n const loadedLangs = highlighter.getLoadedLanguages();\r\n const effectiveLang = loadedLangs.includes(lang as BundledLanguage) ? lang : 'text';\r\n\r\n // Generate HTML with both themes for CSS-based switching\r\n const codeHtml = highlighter.codeToHtml(code, {\r\n lang: effectiveLang as BundledLanguage,\r\n themes: {\r\n light: mergedConfig.light as BundledTheme,\r\n dark: mergedConfig.dark as BundledTheme,\r\n },\r\n });\r\n\r\n // Wrap in code-window structure\r\n const filename = meta?.filename ?? '';\r\n const isLive = meta?.live ?? false;\r\n const tabs = meta?.tabs; // undefined means no tabbed view, just code\r\n const hasTabs = tabs && tabs.length > 0;\r\n \r\n const filenameHtml = filename \r\n ? `<span class=\"code-window-filename\">${escapeHtml(filename)}</span>`\r\n : `<span class=\"code-window-lang\">${getLanguageLabel(effectiveLang)}</span>`;\r\n\r\n // For preview blocks (has tabs), render a LivePreview island component\r\n if (hasTabs) {\r\n const base64Code = encodeBase64(code);\r\n \r\n // Generate tab buttons HTML based on tabs array\r\n const firstTab = tabs[0];\r\n const tabButtonsHtml = tabs.map((tab, i) => {\r\n const label = tab.charAt(0).toUpperCase() + tab.slice(1);\r\n const isActive = i === 0;\r\n return `<button class=\"code-window-tab${isActive ? ' code-window-tab-active' : ''}\">${label}</button>`;\r\n }).join('\\n ');\r\n \r\n // Return an island marker that will be hydrated on the client\r\n // Use code-window styling for consistency with the nice terminal look\r\n const html = `<div \r\n class=\"live-preview-island\" \r\n data-island=\"LivePreview\" \r\n data-island-strategy=\"visible\"\r\n data-island-props=\"${escapeHtml(JSON.stringify({\r\n code: base64Code,\r\n highlightedCode: codeHtml,\r\n language: effectiveLang,\r\n filename: filename,\r\n tabs: tabs,\r\n live: isLive\r\n }))}\"\r\n>\r\n <div class=\"code-window code-window-live code-window-preview\">\r\n <div class=\"code-window-header\">\r\n <div class=\"code-window-header-left\">\r\n <div class=\"code-window-dots\">\r\n <span class=\"code-window-dot dot-red\"></span>\r\n <span class=\"code-window-dot dot-yellow\"></span>\r\n <span class=\"code-window-dot dot-green\"></span>\r\n </div>\r\n ${filenameHtml}\r\n </div>\r\n <div class=\"code-window-tabs\">\r\n ${tabButtonsHtml}\r\n </div>\r\n <button class=\"code-window-try-live\" disabled>⚡ Try Live</button>\r\n </div>\r\n <div class=\"code-window-preview-pane\"${firstTab !== 'preview' ? ' style=\"display:none;\"' : ''}>\r\n <div class=\"code-window-preview-loading\">\r\n <span class=\"code-window-spinner\"></span>\r\n Loading preview...\r\n </div>\r\n </div>\r\n <div class=\"code-window-console-pane\"${firstTab !== 'console' ? ' style=\"display:none;\"' : ''}>\r\n <div class=\"code-window-console-empty\">No console output</div>\r\n </div>\r\n <div class=\"code-window-content\"${firstTab !== 'code' ? ' style=\"display:none;\"' : ''}>\r\n ${codeHtml}\r\n </div>\r\n </div>\r\n</div>`;\r\n return html;\r\n }\r\n\r\n // Add \"Try Live\" button for live code blocks\r\n const tryLiveButton = isLive \r\n ? `<button class=\"code-window-try-live\" data-live-code=\"${escapeHtml(encodeBase64(code))}\" data-lang=\"${effectiveLang}\" data-filename=\"${escapeHtml(filename)}\" title=\"Open in Live Playground\">⚡ Try Live</button>`\r\n : '';\r\n\r\n const html = `<div class=\"code-window${isLive ? ' code-window-live' : ''}\">\r\n <div class=\"code-window-header\">\r\n <div class=\"code-window-header-left\">\r\n <div class=\"code-window-dots\">\r\n <span class=\"code-window-dot dot-red\"></span>\r\n <span class=\"code-window-dot dot-yellow\"></span>\r\n <span class=\"code-window-dot dot-green\"></span>\r\n </div>\r\n ${filenameHtml}\r\n </div>\r\n ${tryLiveButton}\r\n </div>\r\n <div class=\"code-window-content\">\r\n ${codeHtml}\r\n </div>\r\n </div>`;\r\n\r\n return html;\r\n}\r\n\r\n/**\r\n * Encode string to base64 (works in both Node.js and browser)\r\n */\r\nfunction encodeBase64(str: string): string {\r\n // Use Buffer in Node.js\r\n if (typeof Buffer !== 'undefined') {\r\n return Buffer.from(str, 'utf-8').toString('base64');\r\n }\r\n // Fallback for browser (shouldn't be needed during SSG build)\r\n return btoa(unescape(encodeURIComponent(str)));\r\n}\r\n\r\n/**\r\n * Get a display label for a language\r\n */\r\nfunction getLanguageLabel(lang: string): string {\r\n const labels: Record<string, string> = {\r\n 'tsx': 'TSX',\r\n 'jsx': 'JSX',\r\n 'ts': 'TypeScript',\r\n 'typescript': 'TypeScript',\r\n 'js': 'JavaScript',\r\n 'javascript': 'JavaScript',\r\n 'css': 'CSS',\r\n 'html': 'HTML',\r\n 'json': 'JSON',\r\n 'bash': 'Terminal',\r\n 'shell': 'Terminal',\r\n 'sh': 'Terminal',\r\n 'md': 'Markdown',\r\n 'markdown': 'Markdown',\r\n 'python': 'Python',\r\n 'py': 'Python',\r\n 'rust': 'Rust',\r\n 'go': 'Go',\r\n 'text': '',\r\n };\r\n return labels[lang.toLowerCase()] ?? lang.toUpperCase();\r\n}\r\n\r\n/**\r\n * Escape HTML special characters\r\n */\r\nfunction escapeHtml(str: string): string {\r\n return str\r\n .replace(/&/g, '&amp;')\r\n .replace(/</g, '&lt;')\r\n .replace(/>/g, '&gt;')\r\n .replace(/\"/g, '&quot;')\r\n .replace(/'/g, '&#39;');\r\n}\r\n\r\n/**\r\n * Create a rehype plugin for Shiki\r\n */\r\nexport function rehypeShiki(config?: ShikiConfig) {\r\n return async (tree: any) => {\r\n const { visit } = await import('unist-util-visit');\r\n const { fromHtml } = await import('hast-util-from-html');\r\n\r\n const nodesToProcess: Array<{ node: any; parent: any; index: number }> = [];\r\n\r\n visit(tree, 'element', (node: any, index: number | undefined, parent: any) => {\r\n // Look for <pre><code> elements\r\n if (\r\n node.tagName === 'pre' &&\r\n node.children?.[0]?.tagName === 'code'\r\n ) {\r\n nodesToProcess.push({ node, parent, index: index ?? 0 });\r\n }\r\n });\r\n\r\n // Process nodes in parallel\r\n await Promise.all(\r\n nodesToProcess.map(async ({ node, parent, index }) => {\r\n const codeNode = node.children[0];\r\n\r\n // Extract language from class (e.g., \"language-typescript\")\r\n const className = codeNode.properties?.className?.[0] || '';\r\n const lang = className.replace(/^language-/, '') || 'text';\r\n\r\n // Extract filename from meta string if present\r\n // Supports: ```tsx filename=\"Counter.tsx\" or ```tsx title=\"Counter.tsx\"\r\n const metaString = codeNode.data?.meta || codeNode.properties?.metastring || '';\r\n const filename = extractMeta(metaString, 'filename') || extractMeta(metaString, 'title') || '';\r\n \r\n // Check for \"live\" flag in meta string (e.g., ```tsx live)\r\n const isLive = /\\blive\\b/i.test(metaString);\r\n \r\n // Parse tabs from meta string - order determines tab order\r\n // Supported keywords: preview, code, console\r\n // Example: ```tsx code preview console live -> tabs: [code, preview, console], with live button\r\n const tabKeywords = ['preview', 'code', 'console'] as const;\r\n const tabs: TabType[] = [];\r\n \r\n // Find all tab keywords and their positions\r\n const tabPositions: Array<{ tab: TabType; index: number }> = [];\r\n for (const keyword of tabKeywords) {\r\n const regex = new RegExp(`\\\\b${keyword}\\\\b`, 'i');\r\n const match = metaString.match(regex);\r\n if (match && match.index !== undefined) {\r\n tabPositions.push({ tab: keyword, index: match.index });\r\n }\r\n }\r\n \r\n // Sort by position (order of appearance in meta string)\r\n tabPositions.sort((a, b) => a.index - b.index);\r\n \r\n // Extract just the tab names in order\r\n for (const { tab } of tabPositions) {\r\n tabs.push(tab);\r\n }\r\n\r\n // Get raw code content\r\n const code = getTextContent(codeNode);\r\n\r\n // Highlight with Shiki (with meta info)\r\n // Only pass tabs if at least one tab keyword was found\r\n const html = await highlightCode(code.trim(), lang, config, { \r\n filename, \r\n live: isLive, \r\n tabs: tabs.length > 0 ? tabs : undefined \r\n });\r\n\r\n // Parse the HTML string into HAST nodes\r\n const fragment = fromHtml(html, { fragment: true });\r\n \r\n // Replace node with the parsed HAST fragment's children\r\n if (parent && typeof index === 'number' && fragment.children.length > 0) {\r\n // Use the first element from the fragment (should be the code-window div)\r\n parent.children[index] = fragment.children[0];\r\n }\r\n })\r\n );\r\n };\r\n}\r\n\r\n/**\r\n * Extract a meta value from a meta string\r\n * Supports: filename=\"value\" or filename='value' or filename=value\r\n */\r\nfunction extractMeta(metaString: string, key: string): string | null {\r\n if (!metaString) return null;\r\n \r\n // Match: key=\"value\" or key='value' or key=value\r\n const regex = new RegExp(`${key}=[\"']?([^\"'\\\\s]+)[\"']?`, 'i');\r\n const match = metaString.match(regex);\r\n return match ? match[1] : null;\r\n}\r\n\r\n/**\r\n * Extract text content from an AST node\r\n */\r\nfunction getTextContent(node: any): string {\r\n if (node.type === 'text') {\r\n return node.value;\r\n }\r\n\r\n if (node.children) {\r\n return node.children.map(getTextContent).join('');\r\n }\r\n\r\n return '';\r\n}\r\n\r\n/**\r\n * Load additional language on demand\r\n */\r\nexport async function loadLanguage(lang: string): Promise<void> {\r\n const highlighter = await getHighlighter();\r\n const loadedLangs = highlighter.getLoadedLanguages();\r\n\r\n if (!loadedLangs.includes(lang as BundledLanguage)) {\r\n try {\r\n await highlighter.loadLanguage(lang as BundledLanguage);\r\n } catch {\r\n console.warn(`Shiki: Language \"${lang}\" not available, using plain text`);\r\n }\r\n }\r\n}\r\n","/**\r\n * Rehype plugin to extract headings from MDX/MD content\r\n *\r\n * Extracts headings (h2-h6 by default) with their IDs and text content\r\n * for use in table of contents generation.\r\n */\r\n\r\nimport { visit } from 'unist-util-visit';\r\nimport { toString } from 'hast-util-to-string';\r\nimport type { TocHeading } from '../types';\r\n\r\n/**\r\n * Options for the rehype headings plugin\r\n */\r\nexport interface RehypeHeadingsOptions {\r\n /**\r\n * Minimum heading level to include (1-6)\r\n * @default 2\r\n */\r\n minLevel?: number;\r\n\r\n /**\r\n * Maximum heading level to include (1-6)\r\n * @default 3\r\n */\r\n maxLevel?: number;\r\n}\r\n\r\n/**\r\n * Rehype plugin to extract headings from the document\r\n *\r\n * Stores extracted headings in `file.data.headings` for later use.\r\n *\r\n * @example\r\n * ```ts\r\n * import { rehypeExtractHeadings } from './rehype-headings';\r\n *\r\n * // Use with unified\r\n * unified()\r\n * .use(rehypeSlug) // First add IDs to headings\r\n * .use(rehypeExtractHeadings, { minLevel: 2, maxLevel: 3 })\r\n * ```\r\n */\r\nexport function rehypeExtractHeadings(options: RehypeHeadingsOptions = {}) {\r\n const { minLevel = 2, maxLevel = 3 } = options;\r\n\r\n return (tree: any, file: any) => {\r\n const headings: TocHeading[] = [];\r\n\r\n visit(tree, 'element', (node: any) => {\r\n // Check if this is a heading element (h1-h6)\r\n const match = /^h([1-6])$/.exec(node.tagName);\r\n if (!match) return;\r\n\r\n const level = parseInt(match[1], 10);\r\n\r\n // Skip headings outside configured range\r\n if (level < minLevel || level > maxLevel) return;\r\n\r\n // Get the heading ID (should be set by rehype-slug)\r\n const id = node.properties?.id;\r\n if (!id) return;\r\n\r\n // Extract text content from the heading\r\n const text = toString(node).trim();\r\n if (!text) return;\r\n\r\n headings.push({ id, text, level });\r\n });\r\n\r\n // Store headings in file data for later access\r\n file.data = file.data || {};\r\n file.data.headings = headings;\r\n };\r\n}\r\n\r\nexport default rehypeExtractHeadings;\r\n","/**\r\n * MDX Vite plugin\r\n *\r\n * Transforms MDX files into SignalX components with:\r\n * - Frontmatter extraction\r\n * - Shiki syntax highlighting\r\n * - SignalX JSX runtime integration\r\n */\r\n\r\nimport type { Plugin, ResolvedConfig } from 'vite';\r\nimport type { SSGConfig, MarkdownConfig, PageMeta, TocHeading } from '../types';\r\nimport { parseFrontmatter, extractTitleFromContent } from './frontmatter';\r\nimport { rehypeShiki } from './shiki';\r\nimport { rehypeExtractHeadings } from './rehype-headings';\r\n\r\n/**\r\n * MDX plugin options\r\n */\r\nexport interface MDXPluginOptions {\r\n /**\r\n * Markdown configuration\r\n */\r\n markdown?: MarkdownConfig;\r\n\r\n /**\r\n * SSG configuration (for layout resolution)\r\n */\r\n ssgConfig?: SSGConfig;\r\n}\r\n\r\n/**\r\n * Create the MDX Vite plugin\r\n */\r\nexport function mdxPlugin(options: MDXPluginOptions = {}): Plugin {\r\n const { markdown = {} } = options;\r\n\r\n let mdxRollup: any;\r\n let viteConfig: ResolvedConfig;\r\n\r\n return {\r\n name: 'sigx-ssg-mdx',\r\n enforce: 'pre',\r\n\r\n async configResolved(config) {\r\n viteConfig = config;\r\n // Dynamically import @mdx-js/rollup\r\n const mdxModule = await import('@mdx-js/rollup');\r\n const remarkFrontmatter = (await import('remark-frontmatter')).default;\r\n const remarkMdxFrontmatter = (await import('remark-mdx-frontmatter')).default;\r\n const remarkGfm = (await import('remark-gfm')).default;\r\n const rehypeSlug = (await import('rehype-slug')).default;\r\n const rehypeAutolinkHeadings = (await import('rehype-autolink-headings')).default;\r\n\r\n // Get TOC config from SSG config\r\n const tocConfig = options.ssgConfig?.toc || { minLevel: 2, maxLevel: 3 };\r\n\r\n // Build rehype plugins array\r\n const rehypePlugins: any[] = [];\r\n\r\n // Add rehype-slug first to generate heading IDs\r\n rehypePlugins.push(rehypeSlug);\r\n\r\n // Add autolink headings (clickable anchor links)\r\n rehypePlugins.push([rehypeAutolinkHeadings, {\r\n behavior: 'append',\r\n properties: {\r\n class: 'heading-anchor',\r\n ariaHidden: true,\r\n tabIndex: -1,\r\n },\r\n content: {\r\n type: 'element',\r\n tagName: 'span',\r\n properties: { class: 'heading-anchor-icon' },\r\n children: [{ type: 'text', value: '#' }],\r\n },\r\n }]);\r\n\r\n // Add heading extraction for TOC\r\n rehypePlugins.push([rehypeExtractHeadings, tocConfig]);\r\n\r\n // Add Shiki if enabled\r\n if (markdown.shiki !== false) {\r\n const shikiConfig = typeof markdown.shiki === 'object' ? markdown.shiki : undefined;\r\n rehypePlugins.push([rehypeShiki, shikiConfig]);\r\n }\r\n\r\n // Add custom rehype plugins\r\n if (markdown.rehypePlugins) {\r\n rehypePlugins.push(...markdown.rehypePlugins);\r\n }\r\n\r\n // Build remark plugins array\r\n const remarkPlugins: any[] = [\r\n remarkFrontmatter,\r\n [remarkMdxFrontmatter, { name: 'frontmatter' }],\r\n remarkGfm,\r\n ];\r\n\r\n // Add custom remark plugins\r\n if (markdown.remarkPlugins) {\r\n remarkPlugins.push(...markdown.remarkPlugins);\r\n }\r\n\r\n // Create MDX plugin\r\n // Use jsx: false to output function calls instead of JSX syntax\r\n // This avoids needing esbuild to process .mdx files as JSX\r\n mdxRollup = mdxModule.default({\r\n jsx: false,\r\n jsxImportSource: 'sigx',\r\n remarkPlugins,\r\n rehypePlugins,\r\n providerImportSource: undefined,\r\n });\r\n },\r\n\r\n async transform(code, id) {\r\n // Only process MDX and MD files\r\n if (!/\\.mdx?$/.test(id)) {\r\n return null;\r\n }\r\n\r\n // Parse frontmatter first\r\n const { data: frontmatter, content } = parseFrontmatter(code);\r\n\r\n // Extract title from content if not in frontmatter\r\n if (!frontmatter.title) {\r\n const extractedTitle = extractTitleFromContent(content);\r\n if (extractedTitle) {\r\n frontmatter.title = extractedTitle;\r\n }\r\n }\r\n\r\n // Transform MDX content\r\n if (!mdxRollup?.transform) {\r\n throw new Error('MDX plugin not initialized');\r\n }\r\n\r\n const result = await mdxRollup.transform(code, id);\r\n\r\n if (!result) {\r\n return null;\r\n }\r\n\r\n // Extract headings from the file data (set by rehype-extract-headings)\r\n // Note: We need to process the content to get headings\r\n const headings = await extractHeadingsFromContent(content, options);\r\n\r\n // Create module ID for HMR tracking (normalize path separators)\r\n const moduleId = id.replace(/\\\\/g, '/');\r\n\r\n // Inject frontmatter export and wrap in SignalX component\r\n const transformedCode = wrapMDXComponent(\r\n result.code,\r\n frontmatter,\r\n headings,\r\n moduleId,\r\n viteConfig.command === 'serve'\r\n );\r\n\r\n return {\r\n code: transformedCode,\r\n map: result.map,\r\n };\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Wrap MDX output in a SignalX component\r\n * \r\n * Note: remark-mdx-frontmatter already exports `frontmatter`, so we only add the layout export\r\n * \r\n * In dev mode, we:\r\n * 1. Wrap MDXContent in a sigx component() for proper HMR tracking\r\n * 2. Inject HMR registration code so the component updates live\r\n */\r\nfunction wrapMDXComponent(\r\n code: string,\r\n frontmatter: PageMeta,\r\n headings: TocHeading[],\r\n moduleId: string,\r\n isDev: boolean\r\n): string {\r\n // The MDX output already includes frontmatter export from remark-mdx-frontmatter\r\n // We need to add the layout export for the SSG routing system\r\n \r\n // In dev mode, wrap in sigx component for HMR support\r\n if (isDev) {\r\n // Generate a component name from the file path for debugging\r\n const fileName = moduleId.split('/').pop()?.replace(/\\.mdx?$/, '') || 'MDXPage';\r\n const componentName = fileName.charAt(0).toUpperCase() + fileName.slice(1).replace(/[^a-zA-Z0-9]/g, '') + 'Page';\r\n \r\n // The MDX output has \"export default function MDXContent(...)\" \r\n // We need to:\r\n // 1. Remove the \"export default\" from MDXContent to avoid duplicate exports\r\n // 2. Wrap it in a sigx component for HMR\r\n // 3. Export the wrapped component as default\r\n const modifiedCode = code\r\n .replace(/export\\s+default\\s+function\\s+MDXContent/g, 'function _MDXContent')\r\n .replace(/export\\s+{\\s*MDXContent\\s+as\\s+default\\s*}/g, '');\r\n \r\n return `\r\nimport { registerHMRModule } from '@sigx/vite/hmr';\r\nimport { component as __component } from 'sigx';\r\nregisterHMRModule('${moduleId}');\r\n\r\n${modifiedCode}\r\n\r\n// Export layout from frontmatter for SSG routing\r\nexport const layout = ${frontmatter.layout ? JSON.stringify(frontmatter.layout) : 'undefined'};\r\n\r\n// Export headings for table of contents\r\nexport const headings = ${JSON.stringify(headings)};\r\n\r\n// Wrap MDXContent in a sigx component for HMR support\r\nconst MDXPage = __component(() => {\r\n return () => _MDXContent({});\r\n}, { name: '${componentName}' });\r\n\r\nexport default MDXPage;\r\n\r\nif (import.meta.hot) {\r\n // Accept HMR updates with a callback to trigger re-render after module is updated\r\n import.meta.hot.accept((newModule) => {\r\n if (newModule) {\r\n // Notify LayoutRouter to clear its cache and re-render with new module\r\n window.dispatchEvent(new CustomEvent('sigx:mdx-hmr', { \r\n detail: { moduleId: '${moduleId}', newModule } \r\n }));\r\n }\r\n });\r\n}\r\n`;\r\n }\r\n \r\n // Production: just add exports without HMR wrapper\r\n return `\r\n${code}\r\n\r\n// Export layout from frontmatter for SSG routing\r\nexport const layout = ${frontmatter.layout ? JSON.stringify(frontmatter.layout) : 'undefined'};\r\n\r\n// Export headings for table of contents\r\nexport const headings = ${JSON.stringify(headings)};\r\n`;\r\n}\r\n\r\n/**\r\n * Extract headings from markdown/MDX content\r\n */\r\nasync function extractHeadingsFromContent(\r\n content: string,\r\n options: MDXPluginOptions\r\n): Promise<TocHeading[]> {\r\n const { unified } = await import('unified');\r\n const remarkParse = (await import('remark-parse')).default;\r\n const remarkRehype = (await import('remark-rehype')).default;\r\n const rehypeSlug = (await import('rehype-slug')).default;\r\n const rehypeStringify = (await import('rehype-stringify')).default;\r\n\r\n // Get TOC config\r\n const tocConfig = options.ssgConfig?.toc || { minLevel: 2, maxLevel: 3 };\r\n\r\n // Process markdown to extract headings\r\n // Note: rehype-stringify is required for unified to have a compiler\r\n const processor = unified()\r\n .use(remarkParse)\r\n .use(remarkRehype)\r\n .use(rehypeSlug)\r\n .use(rehypeExtractHeadings, tocConfig)\r\n .use(rehypeStringify);\r\n\r\n const file = await processor.process(content);\r\n return (file.data as any).headings || [];\r\n}\r\n\r\n/**\r\n * Create a simple markdown-only plugin (no MDX features)\r\n */\r\nexport function markdownPlugin(options: MDXPluginOptions = {}): Plugin {\r\n return {\r\n name: 'sigx-ssg-markdown',\r\n enforce: 'pre',\r\n\r\n async transform(code, id) {\r\n // Only process .md files (not .mdx)\r\n if (!/\\.md$/.test(id) || /\\.mdx$/.test(id)) {\r\n return null;\r\n }\r\n\r\n // Parse frontmatter\r\n const { data: frontmatter, content } = parseFrontmatter(code);\r\n\r\n // Extract title if not in frontmatter\r\n if (!frontmatter.title) {\r\n const extractedTitle = extractTitleFromContent(content);\r\n if (extractedTitle) {\r\n frontmatter.title = extractedTitle;\r\n }\r\n }\r\n\r\n // Convert markdown to simple HTML using a lightweight parser\r\n // For full MD support, the MDX plugin should be used\r\n const html = await simpleMarkdownToHtml(content, options);\r\n \r\n // Extract headings for TOC\r\n const headings = await extractHeadingsFromContent(content, options);\r\n \r\n const frontmatterJSON = JSON.stringify(frontmatter);\r\n const headingsJSON = JSON.stringify(headings);\r\n\r\n return {\r\n code: `\r\nimport { jsx as _jsx } from 'sigx/jsx-runtime';\r\n\r\nexport const frontmatter = ${frontmatterJSON};\r\nexport const layout = ${frontmatter.layout ? JSON.stringify(frontmatter.layout) : 'undefined'};\r\nexport const headings = ${headingsJSON};\r\n\r\nexport default function MDContent(props) {\r\n return _jsx('div', {\r\n class: 'markdown-content',\r\n dangerouslySetInnerHTML: { __html: ${JSON.stringify(html)} }\r\n });\r\n}\r\n`,\r\n map: null,\r\n };\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Simple markdown to HTML conversion\r\n * For basic markdown without custom components\r\n */\r\nasync function simpleMarkdownToHtml(markdown: string, options: MDXPluginOptions = {}): Promise<string> {\r\n // Use unified for basic markdown processing\r\n const { unified } = await import('unified');\r\n const remarkParse = (await import('remark-parse')).default;\r\n const remarkRehype = (await import('remark-rehype')).default;\r\n const rehypeSlug = (await import('rehype-slug')).default;\r\n const rehypeStringify = (await import('rehype-stringify')).default;\r\n\r\n const result = await unified()\r\n .use(remarkParse)\r\n .use(remarkRehype)\r\n .use(rehypeSlug) // Add IDs to headings\r\n .use(rehypeStringify)\r\n .process(markdown);\r\n\r\n return String(result);\r\n}\r\n","/**\r\n * SSG Vite Plugin\r\n *\r\n * Main Vite plugin for @sigx/ssg that integrates:\r\n * - File-based routing with virtual modules\r\n * - Layout system\r\n * - MDX processing\r\n * - HMR for development\r\n * - Zero-config entry point generation\r\n */\r\n\r\nimport type { Plugin, ResolvedConfig, ViteDevServer } from 'vite';\r\nimport path from 'node:path';\r\nimport fs from 'node:fs';\r\nimport type { SSGConfig } from '../types';\r\nimport { defineSSGConfig, loadConfig } from '../config';\r\nimport { scanPages } from '../routing/scanner';\r\nimport { generateRoutesModule, generateLazyRoutesModule, VIRTUAL_ROUTES_ID, RESOLVED_VIRTUAL_ROUTES_ID } from '../routing/virtual';\r\nimport { generateNavigationModule, VIRTUAL_NAVIGATION_ID, RESOLVED_VIRTUAL_NAVIGATION_ID } from '../routing/virtual-navigation';\r\nimport { discoverLayouts } from '../layouts/resolver';\r\nimport { generateLayoutsModule, VIRTUAL_LAYOUTS_ID, RESOLVED_VIRTUAL_LAYOUTS_ID } from '../layouts/virtual';\r\nimport { mdxPlugin } from '../mdx/plugin';\r\nimport { parseFrontmatter } from '../mdx/frontmatter';\r\nimport {\r\n detectCustomEntries,\r\n generateClientEntry,\r\n generateServerEntry,\r\n generateHtmlTemplate,\r\n VIRTUAL_CLIENT_ID,\r\n RESOLVED_VIRTUAL_CLIENT_ID,\r\n VIRTUAL_SERVER_ID,\r\n RESOLVED_VIRTUAL_SERVER_ID,\r\n SSG_CLIENT_ENTRY_PATH,\r\n type EntryDetectionResult,\r\n} from './virtual-entries';\r\n\r\n/**\r\n * SSG Plugin options\r\n */\r\nexport interface SSGPluginOptions extends Partial<SSGConfig> {\r\n /**\r\n * Path to ssg.config.ts\r\n */\r\n configPath?: string;\r\n \r\n /**\r\n * Enable built-in MDX processing. Set to false if using external MDX plugin.\r\n * @default true\r\n */\r\n enableMdx?: boolean;\r\n}\r\n\r\n/**\r\n * Virtual module for SSG config\r\n */\r\nconst VIRTUAL_CONFIG_ID = 'virtual:ssg-config';\r\nconst RESOLVED_VIRTUAL_CONFIG_ID = '\\0' + VIRTUAL_CONFIG_ID;\r\n\r\n/**\r\n * Create the SSG Vite plugin\r\n */\r\nexport function ssgPlugin(options: SSGPluginOptions = {}): Plugin[] {\r\n let config: ResolvedConfig;\r\n let ssgConfig: SSGConfig;\r\n let root: string;\r\n let server: ViteDevServer | undefined;\r\n let entryDetection: EntryDetectionResult;\r\n\r\n // Cache for virtual modules\r\n let routesCache: { routes: any[]; code: string } | null = null;\r\n let layoutsCache: { layouts: any[]; code: string } | null = null;\r\n let navigationCache: { code: string } | null = null;\r\n \r\n // Cache for frontmatter hashes to detect changes\r\n const frontmatterHashCache = new Map<string, string>();\r\n\r\n const mainPlugin: Plugin = {\r\n name: 'sigx-ssg',\r\n enforce: 'pre',\r\n\r\n async configResolved(resolvedConfig) {\r\n config = resolvedConfig;\r\n root = resolvedConfig.root;\r\n\r\n // Load SSG config - always try to load from file first\r\n const fileConfig = await loadConfig(options.configPath);\r\n \r\n // Merge file config with plugin options (plugin options take precedence)\r\n ssgConfig = defineSSGConfig({\r\n ...fileConfig,\r\n ...options,\r\n });\r\n\r\n // Detect custom entry points\r\n entryDetection = detectCustomEntries(root, ssgConfig);\r\n\r\n // Log zero-config mode status\r\n if (entryDetection.useVirtualClient || entryDetection.useVirtualServer) {\r\n console.log('📦 @sigx/ssg: Using zero-config mode');\r\n if (entryDetection.useVirtualClient) {\r\n console.log(' → Virtual client entry');\r\n }\r\n if (entryDetection.useVirtualServer) {\r\n console.log(' → Virtual server entry');\r\n }\r\n if (entryDetection.globalCssPath) {\r\n console.log(` → Auto-importing ${entryDetection.globalCssPath}`);\r\n }\r\n }\r\n },\r\n\r\n configureServer(devServer) {\r\n server = devServer;\r\n\r\n // Watch pages and layouts directories for changes\r\n const pagesDir = path.resolve(root, ssgConfig.pages || 'src/pages');\r\n const layoutsDir = path.resolve(root, ssgConfig.layouts || 'src/layouts');\r\n const contentDir = path.resolve(root, ssgConfig.content || 'src/content');\r\n\r\n // Clear caches and trigger HMR on file changes\r\n devServer.watcher.on('add', (file) => {\r\n if (file.startsWith(pagesDir)) {\r\n routesCache = null;\r\n navigationCache = null;\r\n invalidateModule(RESOLVED_VIRTUAL_ROUTES_ID);\r\n invalidateModule(RESOLVED_VIRTUAL_NAVIGATION_ID);\r\n } else if (file.startsWith(layoutsDir)) {\r\n layoutsCache = null;\r\n invalidateModule(RESOLVED_VIRTUAL_LAYOUTS_ID);\r\n }\r\n });\r\n\r\n devServer.watcher.on('unlink', (file) => {\r\n if (file.startsWith(pagesDir)) {\r\n routesCache = null;\r\n navigationCache = null;\r\n // Clean up frontmatter hash cache\r\n frontmatterHashCache.delete(file);\r\n invalidateModule(RESOLVED_VIRTUAL_ROUTES_ID);\r\n invalidateModule(RESOLVED_VIRTUAL_NAVIGATION_ID);\r\n } else if (file.startsWith(layoutsDir)) {\r\n layoutsCache = null;\r\n invalidateModule(RESOLVED_VIRTUAL_LAYOUTS_ID);\r\n }\r\n });\r\n\r\n // Handle MDX/MD file content changes for frontmatter updates\r\n devServer.watcher.on('change', async (file) => {\r\n if (!file.startsWith(pagesDir)) return;\r\n if (!/\\.mdx?$/.test(file)) return;\r\n \r\n try {\r\n const content = await fs.promises.readFile(file, 'utf-8');\r\n const { data: newFrontmatter } = parseFrontmatter(content);\r\n const newHash = JSON.stringify(newFrontmatter);\r\n const oldHash = frontmatterHashCache.get(file);\r\n \r\n // Update the cache\r\n frontmatterHashCache.set(file, newHash);\r\n \r\n // If frontmatter changed, invalidate navigation (titles, categories may have changed)\r\n if (oldHash !== undefined && oldHash !== newHash) {\r\n navigationCache = null;\r\n routesCache = null;\r\n \r\n const navMod = devServer.moduleGraph.getModuleById(RESOLVED_VIRTUAL_NAVIGATION_ID);\r\n if (navMod) {\r\n devServer.moduleGraph.invalidateModule(navMod);\r\n }\r\n \r\n const routesMod = devServer.moduleGraph.getModuleById(RESOLVED_VIRTUAL_ROUTES_ID);\r\n if (routesMod) {\r\n devServer.moduleGraph.invalidateModule(routesMod);\r\n }\r\n \r\n // Send HMR update for navigation changes\r\n devServer.ws.send({ type: 'full-reload' });\r\n }\r\n } catch (err) {\r\n // File read error, ignore\r\n }\r\n });\r\n\r\n function invalidateModule(id: string) {\r\n const mod = devServer.moduleGraph.getModuleById(id);\r\n if (mod) {\r\n devServer.moduleGraph.invalidateModule(mod);\r\n devServer.ws.send({ type: 'full-reload' });\r\n }\r\n }\r\n\r\n // Serve virtual HTML template if no index.html exists\r\n if (entryDetection.useVirtualHtml) {\r\n devServer.middlewares.use((req, res, next) => {\r\n // Skip virtual modules and special Vite paths\r\n if (req.url?.startsWith('/@') || \r\n req.url?.startsWith('/__') || \r\n req.url?.includes('virtual:') ||\r\n req.url?.includes('node_modules') ||\r\n req.url?.startsWith('/@vite') ||\r\n req.url?.startsWith('/@fs')) {\r\n return next();\r\n }\r\n \r\n // Only handle requests for HTML pages (not assets with extensions)\r\n if (req.url && (req.url === '/' || !req.url.includes('.'))) {\r\n const html = generateHtmlTemplate(ssgConfig);\r\n // Transform HTML through Vite for HMR injection\r\n devServer.transformIndexHtml(req.url, html).then((transformedHtml) => {\r\n res.setHeader('Content-Type', 'text/html');\r\n res.end(transformedHtml);\r\n }).catch(next);\r\n return;\r\n }\r\n next();\r\n });\r\n }\r\n },\r\n\r\n resolveId(id) {\r\n // Handle virtual modules\r\n if (id === VIRTUAL_ROUTES_ID) {\r\n return RESOLVED_VIRTUAL_ROUTES_ID;\r\n }\r\n if (id === VIRTUAL_LAYOUTS_ID) {\r\n return RESOLVED_VIRTUAL_LAYOUTS_ID;\r\n }\r\n if (id === VIRTUAL_CONFIG_ID) {\r\n return RESOLVED_VIRTUAL_CONFIG_ID;\r\n }\r\n if (id === VIRTUAL_NAVIGATION_ID) {\r\n return RESOLVED_VIRTUAL_NAVIGATION_ID;\r\n }\r\n // Handle virtual entry points (both formats)\r\n if (id === VIRTUAL_CLIENT_ID || id === SSG_CLIENT_ENTRY_PATH) {\r\n return RESOLVED_VIRTUAL_CLIENT_ID;\r\n }\r\n if (id === VIRTUAL_SERVER_ID) {\r\n return RESOLVED_VIRTUAL_SERVER_ID;\r\n }\r\n return null;\r\n },\r\n\r\n async load(id) {\r\n // Generate virtual routes module\r\n if (id === RESOLVED_VIRTUAL_ROUTES_ID) {\r\n if (!routesCache) {\r\n const routes = await scanPages(ssgConfig, root);\r\n // Use lazy loading in dev mode for proper HMR and MDX processing\r\n const code = config.command === 'serve'\r\n ? generateLazyRoutesModule(routes, ssgConfig)\r\n : generateRoutesModule(routes, ssgConfig);\r\n routesCache = { routes, code };\r\n }\r\n return routesCache.code;\r\n }\r\n\r\n // Generate virtual layouts module\r\n if (id === RESOLVED_VIRTUAL_LAYOUTS_ID) {\r\n if (!layoutsCache) {\r\n const layouts = await discoverLayouts(ssgConfig, root);\r\n const code = generateLayoutsModule(layouts, ssgConfig);\r\n layoutsCache = { layouts, code };\r\n }\r\n return layoutsCache.code;\r\n }\r\n\r\n // Generate virtual navigation module\r\n if (id === RESOLVED_VIRTUAL_NAVIGATION_ID) {\r\n if (!navigationCache) {\r\n // Ensure routes are loaded (reuse cache if available)\r\n if (!routesCache) {\r\n const routes = await scanPages(ssgConfig, root);\r\n const routesCode = config.command === 'serve'\r\n ? generateLazyRoutesModule(routes, ssgConfig)\r\n : generateRoutesModule(routes, ssgConfig);\r\n routesCache = { routes, code: routesCode };\r\n }\r\n const isDev = config.command === 'serve';\r\n const code = generateNavigationModule(routesCache.routes, ssgConfig, isDev);\r\n navigationCache = { code };\r\n }\r\n return navigationCache.code;\r\n }\r\n\r\n // Generate virtual config module\r\n if (id === RESOLVED_VIRTUAL_CONFIG_ID) {\r\n return `export default ${JSON.stringify(ssgConfig)};`;\r\n }\r\n\r\n // Generate virtual client entry (needs JSX transform)\r\n if (id === RESOLVED_VIRTUAL_CLIENT_ID) {\r\n const code = generateClientEntry(ssgConfig, entryDetection);\r\n const esbuild = await import('esbuild');\r\n const result = await esbuild.transform(code, {\r\n loader: 'tsx',\r\n jsx: 'automatic',\r\n jsxImportSource: 'sigx',\r\n });\r\n return result.code;\r\n }\r\n\r\n // Generate virtual server entry (needs JSX transform)\r\n if (id === RESOLVED_VIRTUAL_SERVER_ID) {\r\n const code = generateServerEntry(ssgConfig);\r\n const esbuild = await import('esbuild');\r\n const result = await esbuild.transform(code, {\r\n loader: 'tsx',\r\n jsx: 'automatic',\r\n jsxImportSource: 'sigx',\r\n });\r\n return result.code;\r\n }\r\n\r\n return null;\r\n },\r\n\r\n // Handle HMR for layouts and pages\r\n async handleHotUpdate({ file, server }) {\r\n const layoutsDir = path.resolve(root, ssgConfig.layouts || 'src/layouts');\r\n const pagesDir = path.resolve(root, ssgConfig.pages || 'src/pages');\r\n\r\n if (file.startsWith(layoutsDir)) {\r\n // Clear layout cache\r\n layoutsCache = null;\r\n\r\n // Invalidate the virtual layouts module\r\n const mod = server.moduleGraph.getModuleById(RESOLVED_VIRTUAL_LAYOUTS_ID);\r\n if (mod) {\r\n server.moduleGraph.invalidateModule(mod);\r\n }\r\n\r\n // Also reload pages that use this layout\r\n return [];\r\n }\r\n\r\n // Handle MDX/MD file changes in pages directory\r\n if (file.startsWith(pagesDir) && /\\.mdx?$/.test(file)) {\r\n // The MDX plugin handles the transform and HMR code injection.\r\n // We just need to ensure the module is properly invalidated.\r\n // Vite will handle the rest via the injected import.meta.hot.accept()\r\n \r\n // Return undefined to let Vite handle the standard HMR flow\r\n // The MDX file already has import.meta.hot.accept() injected\r\n return undefined;\r\n }\r\n\r\n return undefined;\r\n },\r\n };\r\n\r\n // Combine with MDX plugin if enabled (default: true)\r\n const enableMdx = options.enableMdx !== false;\r\n \r\n if (enableMdx) {\r\n const mdx = mdxPlugin({\r\n markdown: options.markdown,\r\n ssgConfig: undefined as any, // Will be set by configResolved\r\n });\r\n return [mainPlugin, mdx];\r\n }\r\n \r\n return [mainPlugin];\r\n}\r\n\r\n/**\r\n * Export the plugin as default\r\n */\r\nexport default ssgPlugin;\r\n"],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Routing module exports
3
+ */
4
+ export { scanPages, fileToRoute, filePathToRoutePath, pathToRouteName, sortRoutes, isDynamicRoute, extractParams, expandDynamicRoute } from './scanner';
5
+ export { resolveRoutes, getAllPaths, matchRoute } from './resolver';
6
+ export type { ResolvedRoutes, ExpandedRoute } from './resolver';
7
+ export { generateRoutesModule, generateLazyRoutesModule, loadRoutesModule, VIRTUAL_ROUTES_ID, RESOLVED_VIRTUAL_ROUTES_ID } from './virtual';
8
+ export { generateNavigation, generateAllCollections, detectCollection, mergeNavigation } from './navigation';
9
+ export type { CollectionNavigation } from './navigation';
10
+ export { generateNavigationModule, loadNavigationModule, VIRTUAL_NAVIGATION_ID, RESOLVED_VIRTUAL_NAVIGATION_ID } from './virtual-navigation';
11
+ export type { NavigationModule } from './virtual-navigation';
12
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/routing/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,mBAAmB,EAAE,eAAe,EAAE,UAAU,EAAE,cAAc,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAExJ,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACpE,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhE,OAAO,EAAE,oBAAoB,EAAE,wBAAwB,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,0BAA0B,EAAE,MAAM,WAAW,CAAC;AAG5I,OAAO,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC7G,YAAY,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACzD,OAAO,EAAE,wBAAwB,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,8BAA8B,EAAE,MAAM,sBAAsB,CAAC;AAC7I,YAAY,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Navigation generator for SSG
3
+ *
4
+ * Generates navigation structure from scanned routes based on
5
+ * page frontmatter (category, order) or explicit configuration.
6
+ */
7
+ import type { SSGRoute, SSGConfig, NavSection, CollectionConfig } from '../types';
8
+ /**
9
+ * Collection navigation result
10
+ */
11
+ export interface CollectionNavigation {
12
+ sidebar: NavSection[];
13
+ }
14
+ /**
15
+ * Generate navigation structure from routes for a specific collection path
16
+ *
17
+ * @param routes - Scanned SSG routes
18
+ * @param collectionPath - Path prefix for the collection (e.g., '/docs')
19
+ * @param showDrafts - Whether to show draft pages
20
+ * @param isDev - Whether running in development mode
21
+ */
22
+ export declare function generateNavigation(routes: SSGRoute[], collectionPath: string, showDrafts: 'dev' | 'never', isDev: boolean): CollectionNavigation;
23
+ /**
24
+ * Merge explicit sidebar config with auto-generated navigation
25
+ */
26
+ export declare function mergeNavigation(autoGenerated: NavSection[], explicit: NavSection[]): NavSection[];
27
+ /**
28
+ * Generate navigation for all collections
29
+ *
30
+ * @param routes - Scanned SSG routes
31
+ * @param config - SSG configuration
32
+ * @param isDev - Whether running in development mode
33
+ * @returns Record mapping collection names to their navigation
34
+ */
35
+ export declare function generateAllCollections(routes: SSGRoute[], config: SSGConfig, isDev: boolean): Record<string, CollectionNavigation>;
36
+ /**
37
+ * Detect which collection a route path belongs to
38
+ *
39
+ * @param path - Current route path
40
+ * @param collections - Collections configuration
41
+ * @returns The collection name if found, undefined otherwise
42
+ */
43
+ export declare function detectCollection(path: string, collections: Record<string, CollectionConfig>): string | undefined;
44
+ //# sourceMappingURL=navigation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"navigation.d.ts","sourceRoot":"","sources":["../../src/routing/navigation.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAqB,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAErG;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACjC,OAAO,EAAE,UAAU,EAAE,CAAC;CACzB;AAuBD;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAC9B,MAAM,EAAE,QAAQ,EAAE,EAClB,cAAc,EAAE,MAAM,EACtB,UAAU,EAAE,KAAK,GAAG,OAAO,EAC3B,KAAK,EAAE,OAAO,GACf,oBAAoB,CA8DtB;AA0LD;;GAEG;AACH,wBAAgB,eAAe,CAC3B,aAAa,EAAE,UAAU,EAAE,EAC3B,QAAQ,EAAE,UAAU,EAAE,GACvB,UAAU,EAAE,CAwBd;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAClC,MAAM,EAAE,QAAQ,EAAE,EAClB,MAAM,EAAE,SAAS,EACjB,KAAK,EAAE,OAAO,GACf,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAUtC;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC5B,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,GAC9C,MAAM,GAAG,SAAS,CAapB"}
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Route resolver
3
+ *
4
+ * Resolves dynamic routes by calling getStaticPaths() and generates
5
+ * the full list of static paths to render.
6
+ */
7
+ import type { SSGRoute, SSGConfig } from '../types';
8
+ /**
9
+ * Result of resolving routes
10
+ */
11
+ export interface ResolvedRoutes {
12
+ /**
13
+ * Static routes that can be rendered directly
14
+ */
15
+ staticRoutes: SSGRoute[];
16
+ /**
17
+ * Expanded dynamic routes with all parameter combinations
18
+ */
19
+ expandedRoutes: ExpandedRoute[];
20
+ /**
21
+ * Warnings encountered during resolution
22
+ */
23
+ warnings: string[];
24
+ }
25
+ /**
26
+ * A dynamic route expanded with specific parameters
27
+ */
28
+ export interface ExpandedRoute {
29
+ /**
30
+ * Original route with dynamic segments
31
+ */
32
+ originalRoute: SSGRoute;
33
+ /**
34
+ * Fully resolved path (e.g., /blog/hello-world)
35
+ */
36
+ path: string;
37
+ /**
38
+ * Parameters used to resolve this path
39
+ */
40
+ params: Record<string, string>;
41
+ /**
42
+ * Optional props to pass to the page
43
+ */
44
+ props?: Record<string, unknown>;
45
+ }
46
+ /**
47
+ * Resolve all routes and expand dynamic routes using getStaticPaths
48
+ */
49
+ export declare function resolveRoutes(routes: SSGRoute[], config: SSGConfig, root: string): Promise<ResolvedRoutes>;
50
+ /**
51
+ * Build a complete list of all paths to render
52
+ */
53
+ export declare function getAllPaths(resolved: ResolvedRoutes): Array<{
54
+ path: string;
55
+ route: SSGRoute;
56
+ params: Record<string, string>;
57
+ props?: Record<string, unknown>;
58
+ }>;
59
+ /**
60
+ * Match a path against a route pattern
61
+ */
62
+ export declare function matchRoute(routePath: string, urlPath: string): {
63
+ match: boolean;
64
+ params: Record<string, string>;
65
+ };
66
+ //# sourceMappingURL=resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolver.d.ts","sourceRoot":"","sources":["../../src/routing/resolver.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAA0B,MAAM,UAAU,CAAC;AAG5E;;GAEG;AACH,MAAM,WAAW,cAAc;IAC3B;;OAEG;IACH,YAAY,EAAE,QAAQ,EAAE,CAAC;IAEzB;;OAEG;IACH,cAAc,EAAE,aAAa,EAAE,CAAC;IAEhC;;OAEG;IACH,QAAQ,EAAE,MAAM,EAAE,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC1B;;OAEG;IACH,aAAa,EAAE,QAAQ,CAAC;IAExB;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAE/B;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED;;GAEG;AACH,wBAAsB,aAAa,CAC/B,MAAM,EAAE,QAAQ,EAAE,EAClB,MAAM,EAAE,SAAS,EACjB,IAAI,EAAE,MAAM,GACb,OAAO,CAAC,cAAc,CAAC,CAyBzB;AAgDD;;GAEG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,cAAc,GAAG,KAAK,CAAC;IACzD,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,QAAQ,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC,CAAC,CA4BD;AAED;;GAEG;AACH,wBAAgB,UAAU,CACtB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,GAChB;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,CAuDpD"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * File-based route scanner
3
+ *
4
+ * Scans a pages directory and generates route definitions from file paths.
5
+ * Supports dynamic routes with [param] and catch-all with [...slug] patterns.
6
+ */
7
+ import type { SSGRoute, SSGConfig } from '../types';
8
+ /**
9
+ * Scan pages directory and generate routes
10
+ */
11
+ export declare function scanPages(config: SSGConfig, root: string): Promise<SSGRoute[]>;
12
+ /**
13
+ * Convert a file path to a route definition
14
+ */
15
+ export declare function fileToRoute(filePath: string, pagesDir: string): SSGRoute | null;
16
+ /**
17
+ * Convert file path patterns to route path patterns
18
+ *
19
+ * Examples:
20
+ * blog/[slug] -> /blog/:slug
21
+ * docs/[...path] -> /docs/*path
22
+ * users/[id]/posts -> /users/:id/posts
23
+ */
24
+ export declare function filePathToRoutePath(filePath: string): string;
25
+ /**
26
+ * Convert route path to a route name
27
+ *
28
+ * Examples:
29
+ * / -> index
30
+ * /about -> about
31
+ * /blog/:slug -> blog-slug
32
+ * /docs/*path -> docs-path
33
+ */
34
+ export declare function pathToRouteName(routePath: string): string;
35
+ /**
36
+ * Sort routes by specificity
37
+ *
38
+ * Order:
39
+ * 1. Static routes (most specific)
40
+ * 2. Dynamic param routes
41
+ * 3. Catch-all routes (least specific)
42
+ *
43
+ * Within each category, longer paths come first
44
+ */
45
+ export declare function sortRoutes(routes: SSGRoute[]): SSGRoute[];
46
+ /**
47
+ * Check if a route has dynamic segments
48
+ */
49
+ export declare function isDynamicRoute(route: SSGRoute): boolean;
50
+ /**
51
+ * Extract parameter names from a route path
52
+ */
53
+ export declare function extractParams(routePath: string): string[];
54
+ /**
55
+ * Generate all static paths for a route using getStaticPaths
56
+ */
57
+ export declare function expandDynamicRoute(route: SSGRoute, staticPaths: Array<{
58
+ params: Record<string, string>;
59
+ }>): string[];
60
+ //# sourceMappingURL=scanner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../../src/routing/scanner.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAY,MAAM,UAAU,CAAC;AAwB9D;;GAEG;AACH,wBAAsB,SAAS,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAwBpF;AAwBD;;GAEG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAqB/E;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CA+B5D;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAazD;AAED;;;;;;;;;GASG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,QAAQ,EAAE,GAAG,QAAQ,EAAE,CAazD;AAyBD;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,QAAQ,GAAG,OAAO,CAEvD;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,CAazD;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAC9B,KAAK,EAAE,QAAQ,EACf,WAAW,EAAE,KAAK,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,CAAC,GACvD,MAAM,EAAE,CAiBV"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Virtual module generator for navigation
3
+ *
4
+ * Generates the virtual:ssg-navigation module that exports
5
+ * the navigation structure for all collections.
6
+ */
7
+ import type { SSGConfig, CollectionConfig } from '../types';
8
+ import type { SSGRoute } from '../types';
9
+ import { CollectionNavigation } from './navigation';
10
+ /**
11
+ * Virtual module ID for SSG navigation
12
+ */
13
+ export declare const VIRTUAL_NAVIGATION_ID = "virtual:ssg-navigation";
14
+ export declare const RESOLVED_VIRTUAL_NAVIGATION_ID: string;
15
+ /**
16
+ * Navigation module result type
17
+ */
18
+ export interface NavigationModule {
19
+ /** Navigation keyed by collection name */
20
+ navigation: Record<string, CollectionNavigation>;
21
+ /** Collections configuration for path detection */
22
+ collections: Record<string, CollectionConfig>;
23
+ }
24
+ /**
25
+ * Generate the virtual navigation module code
26
+ *
27
+ * @param routes - Scanned SSG routes with metadata
28
+ * @param config - SSG configuration
29
+ * @param isDev - Whether running in development mode
30
+ */
31
+ export declare function generateNavigationModule(routes: SSGRoute[], config: SSGConfig, isDev: boolean): string;
32
+ /**
33
+ * Create a loader for the navigation module
34
+ */
35
+ export declare function loadNavigationModule(routes: SSGRoute[], config: SSGConfig, isDev: boolean): Promise<{
36
+ navigation: Record<string, CollectionNavigation>;
37
+ code: string;
38
+ }>;
39
+ //# sourceMappingURL=virtual-navigation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"virtual-navigation.d.ts","sourceRoot":"","sources":["../../src/routing/virtual-navigation.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAuB,gBAAgB,EAAE,MAAM,UAAU,CAAC;AACjF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAoE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAEtH;;GAEG;AACH,eAAO,MAAM,qBAAqB,2BAA2B,CAAC;AAC9D,eAAO,MAAM,8BAA8B,QAA+B,CAAC;AAE3E;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC7B,0CAA0C;IAC1C,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC;IACjD,mDAAmD;IACnD,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;CACjD;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CACpC,MAAM,EAAE,QAAQ,EAAE,EAClB,MAAM,EAAE,SAAS,EACjB,KAAK,EAAE,OAAO,GACf,MAAM,CAiER;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CACtC,MAAM,EAAE,QAAQ,EAAE,EAClB,MAAM,EAAE,SAAS,EACjB,KAAK,EAAE,OAAO,GACf,OAAO,CAAC;IAAE,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAI7E"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Virtual module generator for routes
3
+ *
4
+ * Generates the virtual:ssg-routes module that exports all routes
5
+ * for use by the router.
6
+ */
7
+ import type { SSGRoute, SSGConfig } from '../types';
8
+ /**
9
+ * Virtual module ID for SSG routes
10
+ */
11
+ export declare const VIRTUAL_ROUTES_ID = "virtual:ssg-routes";
12
+ export declare const RESOLVED_VIRTUAL_ROUTES_ID: string;
13
+ /**
14
+ * Generate the virtual routes module code
15
+ */
16
+ export declare function generateRoutesModule(routes: SSGRoute[], config: SSGConfig): string;
17
+ /**
18
+ * Generate lazy-loading routes module (for development with HMR)
19
+ */
20
+ export declare function generateLazyRoutesModule(routes: SSGRoute[], config: SSGConfig): string;
21
+ /**
22
+ * Create a module loader for routes
23
+ */
24
+ export declare function loadRoutesModule(config: SSGConfig, root: string): Promise<{
25
+ routes: SSGRoute[];
26
+ code: string;
27
+ }>;
28
+ //# sourceMappingURL=virtual.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"virtual.d.ts","sourceRoot":"","sources":["../../src/routing/virtual.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAGpD;;GAEG;AACH,eAAO,MAAM,iBAAiB,uBAAuB,CAAC;AACtD,eAAO,MAAM,0BAA0B,QAA2B,CAAC;AASnE;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,QAAQ,EAAE,EAAE,MAAM,EAAE,SAAS,GAAG,MAAM,CA2ClF;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,QAAQ,EAAE,EAAE,MAAM,EAAE,SAAS,GAAG,MAAM,CAoCtF;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAClC,MAAM,EAAE,SAAS,EACjB,IAAI,EAAE,MAAM,GACb,OAAO,CAAC;IAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAK/C"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Sitemap Generation
3
+ *
4
+ * Generates XML sitemaps for SSG sites following the sitemap protocol.
5
+ * https://www.sitemaps.org/protocol.html
6
+ */
7
+ import type { SSGConfig, PageBuildResult } from './types';
8
+ /**
9
+ * Sitemap entry with optional metadata
10
+ */
11
+ export interface SitemapEntry {
12
+ /** URL path (relative to site base) */
13
+ path: string;
14
+ /** Last modification date */
15
+ lastmod?: Date | string;
16
+ /** Change frequency hint */
17
+ changefreq?: 'always' | 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'never';
18
+ /** Priority relative to other pages (0.0 to 1.0) */
19
+ priority?: number;
20
+ }
21
+ /**
22
+ * Sitemap generation options
23
+ */
24
+ export interface SitemapOptions {
25
+ /** Include all built pages automatically */
26
+ includePages?: boolean;
27
+ /** Additional URLs to include */
28
+ additionalUrls?: SitemapEntry[];
29
+ /** URLs to exclude (glob patterns or exact matches) */
30
+ exclude?: string[];
31
+ /** Default change frequency */
32
+ defaultChangefreq?: SitemapEntry['changefreq'];
33
+ /** Default priority */
34
+ defaultPriority?: number;
35
+ }
36
+ /**
37
+ * Generate sitemap XML content
38
+ */
39
+ export declare function generateSitemap(entries: SitemapEntry[], config: SSGConfig): string;
40
+ /**
41
+ * Generate robots.txt content
42
+ */
43
+ export declare function generateRobotsTxt(config: SSGConfig, sitemapPath?: string): string;
44
+ /**
45
+ * Convert page build results to sitemap entries
46
+ */
47
+ export declare function pagesToSitemapEntries(pages: PageBuildResult[], options?: SitemapOptions): SitemapEntry[];
48
+ /**
49
+ * Write sitemap and robots.txt to output directory
50
+ */
51
+ export declare function writeSitemap(pages: PageBuildResult[], config: SSGConfig, outDir: string, options?: SitemapOptions): Promise<{
52
+ sitemapPath: string;
53
+ robotsPath: string;
54
+ }>;
55
+ //# sourceMappingURL=sitemap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sitemap.d.ts","sourceRoot":"","sources":["../src/sitemap.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE1D;;GAEG;AACH,MAAM,WAAW,YAAY;IACzB,uCAAuC;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,6BAA6B;IAC7B,OAAO,CAAC,EAAE,IAAI,GAAG,MAAM,CAAC;IACxB,4BAA4B;IAC5B,UAAU,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,GAAG,OAAO,CAAC;IACvF,oDAAoD;IACpD,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC3B,4CAA4C;IAC5C,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,iCAAiC;IACjC,cAAc,CAAC,EAAE,YAAY,EAAE,CAAC;IAChC,uDAAuD;IACvD,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,+BAA+B;IAC/B,iBAAiB,CAAC,EAAE,YAAY,CAAC,YAAY,CAAC,CAAC;IAC/C,uBAAuB;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC3B,OAAO,EAAE,YAAY,EAAE,EACvB,MAAM,EAAE,SAAS,GAClB,MAAM,CAwBR;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,EAAE,WAAW,SAAiB,GAAG,MAAM,CASzF;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CACjC,KAAK,EAAE,eAAe,EAAE,EACxB,OAAO,GAAE,cAAmB,GAC7B,YAAY,EAAE,CA0ChB;AAED;;GAEG;AACH,wBAAsB,YAAY,CAC9B,KAAK,EAAE,eAAe,EAAE,EACxB,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,cAAmB,GAC7B,OAAO,CAAC;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC,CAoBtD"}