UNPKG

@tanstack/markdown

Version:

A tiny, fast, deterministic Markdown renderer for blogs and documentation.

139 lines (138 loc) 4.96 kB
import { blocksToText, slugify, splitByHeading } from './shared.js'; const bundlers = ['vite', 'rsbuild']; export function transformTabsComponent(node) { const variant = node.attributes.variant?.toLowerCase(); if (variant === 'files') return transformFileTabs(node); if (variant === 'package-manager' || variant === 'package-managers') return transformPackageManagerTabs(node); if (variant === 'bundler') return transformBundlerTabs(node); return transformHeadingTabs(node); } export function transformFileTabs(node) { const files = node.children.filter((child) => child.type === 'code'); if (!files.length) return node; const tabs = files.map((file, index) => ({ slug: `file-${index}`, name: file.title || file.file || 'Untitled', })); return { ...node, properties: { ...(node.properties ?? {}), 'data-attributes': JSON.stringify({ tabs }), 'data-files-meta': JSON.stringify({ files: files.map(file => ({ title: file.title || file.file || 'Untitled', code: file.value, language: file.lang ?? 'plaintext', })), }), }, children: files.map((file, index) => ({ type: 'component', name: 'tab-panel', tagName: 'md-tab-panel', attributes: {}, properties: { 'data-tab-slug': `file-${index}`, 'data-tab-index': String(index), }, children: [file], })), }; } export function transformPackageManagerTabs(node) { const packagesByFramework = Object.create(null); for (const line of blocksToText(node.children).split('\n')) { const colon = line.indexOf(':'); if (colon === -1) continue; const framework = line.slice(0, colon).trim().toLowerCase(); const packages = line.slice(colon + 1).trim().split(/\s+/).filter(Boolean); if (!framework || packages.length === 0) continue; packagesByFramework[framework] ??= []; packagesByFramework[framework].push(packages); } if (!Object.keys(packagesByFramework).length) return node; return { ...node, properties: { ...(node.properties ?? {}), 'data-package-manager-meta': JSON.stringify({ packagesByFramework, mode: resolveInstallMode(node.attributes.mode), }), }, children: [], }; } export function transformBundlerTabs(node) { const sections = splitByHeading(node.children); const selected = bundlers.flatMap(bundler => { const section = sections.find(section => section.name.toLowerCase() === bundler); return section ? [section] : []; }); if (!selected.length) return node; const tabs = selected.map(section => ({ slug: section.name.toLowerCase(), name: section.name.toLowerCase() })); return { ...node, properties: { ...(node.properties ?? {}), 'data-attributes': JSON.stringify({ tabs }), 'data-bundler-meta': JSON.stringify({ bundlers: tabs.map(tab => tab.slug) }), }, children: selected.map((section, index) => { return { type: 'component', name: 'tab-panel', tagName: 'md-tab-panel', attributes: {}, properties: { 'data-tab-slug': section.name.toLowerCase(), 'data-tab-index': String(index), 'data-content': section.children.length === 1 && section.children[0]?.type === 'code' ? 'code-only' : 'mixed', }, children: section.children, }; }), }; } export function transformHeadingTabs(node) { const sections = splitByHeading(node.children); if (!sections.length) return node; const tabs = sections.map((section, index) => ({ slug: section.id || slugify(section.name, `tab-${index + 1}`), name: section.name, })); return { ...node, properties: { ...(node.properties ?? {}), 'data-attributes': JSON.stringify({ tabs }), }, children: sections.map((section, index) => ({ type: 'component', name: 'tab-panel', tagName: 'md-tab-panel', attributes: {}, properties: { 'data-tab-slug': tabs[index]?.slug ?? `tab-${index + 1}`, 'data-tab-index': String(index), }, children: section.children, })), }; } function resolveInstallMode(value) { const mode = value?.toLowerCase(); if (mode === 'dev-install' || mode === 'local-install') return mode; return 'install'; }