Skip to content

Latest commit

 

History

History

README.md

@wdprlib/render

HTML renderer for Wikidot markup.

Installation

bun add @wdprlib/render

Usage

import { parse, processWikitext } from "@wdprlib/parser";
import { renderToHtml, renderWikitext } from "@wdprlib/render";
import type { PageContext } from "@wdprlib/render";

const { ast } = parse("**Hello** world");

// Basic rendering
const html = renderToHtml(ast);

// With page context and resolvers
const pageContext: PageContext = {
  pageName: "main",
  site: "mysite",
  domain: "mysite.example.com",
  pageExists: (name) => checkPageExists(name),
  // Image attachments of the page, shown by the content-less [[gallery]]
  // form (image/* with resized variants; createdAt enables order="created_at")
  files: [{ name: "photo.jpg", createdAt: 1700000000 }],
};

const html = renderToHtml(ast, {
  page: pageContext,
  footnotes: ast.footnotes,
  resolvers: {
    user: (username) => ({ name: username, displayName: "Display Name" }),
    htmlBlockUrl: (index) => `/local--html/page/${index}`,
  },
});

For an asynchronous application pipeline, parse first and render second. @wdprlib/render does not import or depend on @wdprlib/parser:

const document = await processWikitext(source, {
  page: {
    fullName: "docs:start",
    unixName: "start",
    tags: ["docs"],
    urlPath: "/docs:start",
  },
  dataProvider,
});

const result = await renderWikitext(document, {
  styleMode: "separate",
  resolvers: {
    resolvePageExistence: async (pages) => findExistingPages(pages),
    resolveHtmlBlockUrl: async ({ index, content, page }) => {
      const hash = await storeHtmlBlock(content);
      return `/local--html/${page.fullName}/${index}/${hash}`;
    },
  },
});

result.html; // contains no <style> tags in separate mode
result.styles;
result.htmlBlocks;
result.diagnostics;
result.dependencies;

Security defaults

  • [[embed]] accepts HTTPS iframes only. Inline style attributes are removed; use the allowed width and height attributes for sizing.
  • Local image and gallery paths reject traversal segments, encoded path components, backslashes, NUL bytes, query strings, and fragments.
  • createSettings("page") and DEFAULT_SETTINGS keep [[module CSS]] disabled. Enable it only when the CSS source is trusted:
import { createSettings } from "@wdprlib/ast";

const trustedPageSettings = {
  ...createSettings("page"),
  allowStyleElements: true,
};
  • HTML block iframes use an empty sandbox attribute by default. Set htmlBlockSandbox: null only when Wikidot-compatible unsandboxed execution is explicitly required. Avoid combining allow-scripts and allow-same-origin for same-origin content because that can negate the sandbox.

Features

  • HTML generation from AST
  • Footnote and bibliography rendering
  • User link resolution
  • Embed block with configurable allowlist
  • Math rendering (via Temml)
  • XSS protection (via DOMPurify)

Related Packages

License

AGPL-3.0 - See LICENSE