My App
LoopKitBackend

Content Pipeline

Template rendering with optional Markdown, KaTeX, and code highlighting transforms

Overview

The content pipeline handles rendering note fields into card HTML. It consists of two stages:

  1. Template interpolation — Replace {{FieldName}} placeholders with field values
  2. Content transforms — Apply optional Markdown, math, code highlighting, and sanitization

Template Syntax

SyntaxDescription
{{FieldName}}Replace with the field's value
{{#FieldName}}...{{/FieldName}}Show content only if field is non-empty
{{^FieldName}}...{{/FieldName}}Show content only if field is empty
{{FrontSide}}Insert the rendered front (back template only)

Example template:

{{Front}}

{{#Extra}}
<hr>
<small>{{Extra}}</small>
{{/Extra}}

Creating a Pipeline

import {
    createContentPipeline,
    createMarkdownTransform,
    createKatexTransform,
    createCodeHighlightTransform,
    createSanitizeTransform,
} from '@loopkit/nestjs';

Basic Pipeline (No Transforms)

const pipeline = createContentPipeline();
// Only template interpolation — no Markdown, math, etc.

Full Pipeline

import { parse } from 'marked';
import katex from 'katex';
import hljs from 'highlight.js';
import sanitize from 'sanitize-html';

const pipeline = createContentPipeline([
    createMarkdownTransform({ parse }),
    createKatexTransform(katex),
    createCodeHighlightTransform(hljs),
    createSanitizeTransform(sanitize),   // Always last!
]);

Built-in Transforms

createMarkdownTransform

function createMarkdownTransform(marked: {
    parse: (src: string) => string;
}): ContentTransform

Converts Markdown to HTML. Requires marked as a peer dependency.

createKatexTransform

function createKatexTransform(katex: {
    renderToString: (tex: string, options?: Record<string, unknown>) => string;
}): ContentTransform

Renders math expressions:

  • Block math: $$E = mc^2$$ — rendered with displayMode: true
  • Inline math: $x^2$ — rendered with displayMode: false

createCodeHighlightTransform

function createCodeHighlightTransform(hljs: {
    highlightAuto: (code: string) => { value: string };
}): ContentTransform

Highlights code blocks using highlight.js auto-detection.

createSanitizeTransform

function createSanitizeTransform(
    sanitize: (dirty: string) => string,
): ContentTransform

Sanitizes HTML to prevent XSS. Should always be the last transform in the pipeline.

ContentPipeline Interface

interface ContentPipeline {
    transforms: ContentTransform[];
    render(note: NoteBase, template: TemplateDef): RenderedCard;
}

The render method:

  1. Builds a field map from the note's fields
  2. Interpolates the front template
  3. Applies all transforms to the front
  4. Interpolates the back template (with {{FrontSide}} available)
  5. Applies all transforms to the back
  6. Returns { front: string, back: string }

Template Interpolation

function interpolateTemplate(
    template: string,
    fields: Record<string, string>,
    frontRendered?: string,
): string

This function is also exported if you need standalone template processing.

On this page