renderPost

tcmts.site.renderPost · #2xjmvmlm · function · runs anywhere

A blog post as HTML: its title (the # heading), what's under it with its code highlighted, and its first paragraph (for the list of posts, and link previews). Its links are to the site from its root (/docs/apps.html) or elsewhere in full: one to a docs page that docs (the docs site's files) doesn't have is a problem, as is a relative one. A definition named as a doc comment names one (@link) links to its page in the docs' code browser.

import type { Highlight } from "#codebase/tcmts/content";
import { codeBlock, esc, linkExtension, plain, slug } from "#codebase/tcmts/site";
import type { Post, RenderedPost } from "#codebase/tcmts/site";
import { Marked } from "marked";
import type { Tokens } from "marked";

export function renderPost(post: Post, hl: Highlight, docs: Set<string>): RenderedPost {
  const problems: string[] = [];
  let title = "";
  let titleHtml = "";
  let summary = "";
  const marked = new Marked({
    gfm: true,
    extensions: [
      linkExtension((name) =>
        name.startsWith("tcmts.")
          ? `/docs/code/tcm/${name.slice("tcmts.".length).replaceAll(".", "/")}.html`
          : undefined,
      ),
    ],
    renderer: {
      heading({ tokens, depth, text }: Tokens.Heading) {
        const inner = this.parser.parseInline(tokens);
        if (depth > 1) return `<h${depth} id="${slug(plain(text))}">${inner}</h${depth}>\n`;
        title = plain(text);
        titleHtml = inner;
        return "";
      },
      paragraph({ tokens }: Tokens.Paragraph) {
        const inner = this.parser.parseInline(tokens);
        summary ||= inner;
        return `<p>${inner}</p>\n`;
      },
      link({ href, tokens }: Tokens.Link) {
        const text = this.parser.parseInline(tokens);
        const doc = /^\/docs\/([^#?]*)/.exec(href);
        if (doc && !docs.has(doc[1] || "index.html"))
          problems.push(`link to ${href}: no such docs page`);
        else if (!/^([a-z]+:|\/)/i.test(href))
          problems.push(`link to ${href}: write it from the site's root (/docs/…), or in full`);
        return `<a href="${esc(href)}">${text}</a>`;
      },
      code({ text, lang }: Tokens.Code) {
        return codeBlock(hl, text, lang);
      },
    },
  });
  const body = marked.parse(post.md) as string;
  if (!title) problems.push("no title: a post starts with a # heading");
  const description = summary
    .replace(/<[^>]+>/g, "")
    .replace(
      /&(amp|lt|gt|quot|#39);/g,
      (_, e: string) => ({ amp: "&", lt: "<", gt: ">", quot: '"', "#39": "'" })[e]!,
    )
    .replace(/\s+/g, " ")
    .trim();
  return { title, titleHtml, body, summary, description, problems };
}

uses

used by