Volver a la wiki

Función renderMarkdownDoc — Renderizador markdown con títulos e IDs

Librería TypeScript que renderiza Markdown a HTML, extrayendo el primer # título global y generando IDs únicos para todos los headings. Centraliza la lógica de transformación compartida por visor de informes y reports del Supercontexto.

Propósito

Antes: cada visor de documentos tenía su propia lógica para:

Ahora: una función única (renderMarkdownDoc) que maneja todo esto.

Interfaz

export interface DocHeading {
  depth: number;    // 2 = h2, 3 = h3 (solo h2/h3 recolectados)
  text: string;     // Texto del heading (sin etiquetas HTML)
  slug: string;     // ID único (ej: "resumen" o "resumen-1")
}

export interface MarkdownDoc {
  title: string | null;    // Texto extraído del primer "# " o null
  html: string;            // HTML renderizado (sin el # título)
  headings: DocHeading[];  // Listado h2/h3 para el TOC
}

export function renderMarkdownDoc(raw: string): MarkdownDoc

Pasos internos

1. Extracción de título

2. Renderización con marked

renderer: {
  heading({ tokens, depth, text }) {
    let id = slugifyHeading(text);
    const n = vistos.get(id) ?? 0;
    vistos.set(id, n + 1);
    if (n > 0) id = `${id}-${n}`;
    // Recolectar solo h2/h3
    if (depth >= 2 && depth <= 3) 
      headings.push({ depth, text, slug: id });
    return `<h${depth} id="${id}">...</h${depth}>`;
  }
}

3. Slugificación

function slugifyHeading(text: string): string
  // Minúsculas
  // Normalización Unicode (NFD + eliminar diacríticos)
  // Remover caracteres especiales (keep alfanumérico + guiones)
  // Trim + collapse espacios a guiones
  // Resultado: "¿Qué es esto?" → "que-es-esto"

4. Deduplicación

Uso

import { renderMarkdownDoc } from '../lib/markdownDoc';

const rawMarkdown = fs.readFileSync(filePath, 'utf-8');
const { title, html, headings } = renderMarkdownDoc(rawMarkdown);

// En el template Astro:
const titulo = title ?? 'Sin título';
<h1>{titulo}</h1>
<Fragment set:html={html} />

<PageToc headings={headings} actions={[...]} />

Ubicaciones en uso

Nota: Las páginas wiki NO pasan por aquí. Usan el pipeline de contenido Astro (remark/rehype + componente render() de Astro). Este renderizador es solo para documentos sueltos en formato .md.

Diferencias con pipeline wiki

AspectorenderMarkdownDocPipeline Astro (wiki)
Motormarkedremark/rehype
EntradaString bruto .mdAstro Content Collection
Salida{ title, html, headings }HTML renderizado + headings en frontmatter
IDs en headingsGenerados por el rendererGenerados por rehype-autolink-headings
Extracción de títuloManual (regex)En frontmatter
Deduplicación slugsIntegrada (Map vistos)Integrada en rehype
Recolección headingsPor renderer customizadoPor Astro.props.headings

Véase también

Subir