Skip to content

About

Manage the organisation and compilation of multiple Typst documents.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

typst-press

Manage the organisation and compilation of multiple Typst documents.

Declare the tree of documents you want to compile — a schema of sections and resources — and typst-press compiles every resource to a PDF in one pass. Compilation runs in-process via the native @myriaddreamin/typst-ts-node-compiler, so no Typst CLI is required.

Installation

npm install typst-press

Requires Node.js 18+. The package is ESM-only.

Basic usage

The simplest usage needs no subclassing and no type parameters:

import { Press } from 'typst-press';

const press = new Press('./src', './build', [
  {
    id: 'mathematics',
    name: 'Mathematics',
    items: [{ id: 'notes', name: 'Notes' }],
  },
  {
    id: 'physics',
    name: 'Physics',
    items: [
      { id: 'notes', name: 'Notes' },
      { id: 'formula-sheet', name: 'Formula sheet' },
    ],
  },
]);

await Promise.all(press.run());
  • The schema is a tree. Nodes with items are sections; leaf nodes are resources, i.e. the documents to compile.
  • Every node has an id and a name. id determines the file paths; name is just a human-readable label.
  • new Press(sourceDirectory, outputDirectory, schema, defaultOptions?, root?) — the last two arguments are optional.
  • run() returns an array of promises, one per resource. Callers must await Promise.all(...).

This example compiles:

Source Output
src/mathematics/notes.typ build/mathematics/notes.pdf
src/physics/notes.typ build/physics/notes.pdf
src/physics/formula-sheet.typ build/physics/formula-sheet.pdf

Paths

By default, each resource path is the branch of node ids joined together, prefixed with the source or output directory. The .typ / .pdf extension is appended automatically when missing.

Each node can override its part of the path with sourcePath / outputPath:

  • false — omit this level from the path;
  • null — (output only) reuse the corresponding source path;
  • a string — use it instead of id.

Options

Options configure individual resources. They come from two places, merged with the resource's own options taking precedence:

  • defaultOptions (4th constructor argument) — applied to every resource;
  • options on each resource node.

ResourceOptions supports:

  • sysInputs — values passed to Typst's sys.inputs for this resource.
  • mainFile — compile a directory entrypoint instead of a .typ file named after the resource. true looks for main.typ; a string names a different entrypoint:
{
  id: 'notes',
  name: 'Notes',
  options: { mainFile: true }, // src/.../notes/main.typ
}

Customization

Beyond options there are two further, independent ways to customize a press: extra fields and subclassing.

Extra fields

Add typed metadata to sections, resources, options or nodes by providing a PressCtx type parameter — no subclassing needed. PressCtx<TSectionExtra, TResourceExtra, TOptions, TNodeExtra> describes the extra fields allowed at each level:

import { Press } from 'typst-press';
import type { PressCtx } from 'typst-press';

enum ResourceType { NOTES, CHEAT_SHEET }

type Ctx = PressCtx<
  { shortName: string },                   // extra fields on sections
  { type: ResourceType; version: string }  // extra fields on resources
>;

const press = new Press<Ctx>('./src', './build', [
  {
    id: 'subject',
    name: 'Subject',
    shortName: 'SUB',
    items: [
      {
        id: 'notes',
        name: 'Notes',
        type: ResourceType.NOTES,
        version: '1.0.0',
      },
    ],
  },
]);

await Promise.all(press.run());

Extra fields only add compile-time type checking; they do not change behavior by themselves.

Subclassing

Subclass Press<Ctx> to change how documents are compiled. The most useful methods to override:

  • getSystemInputs(nodePath, resource) — project-wide Typst sys.inputs, computed per resource. Returned inputs are merged over the resource's own sysInputs.
  • getSourcePath(nodePath) / getOutputPath(nodePath) — compute the input/output file paths (default: the branch of node ids plus the extension).
  • compile(inputPath, outputPath, nodePath, resource) — full control over the compilation step (default: write the PDF via the native compiler).

When you override a method, you don't need to worry about the exact Ctx['TNode'] / Ctx['TResource'] types — just copy the signatures from the base class. They exist so that inside the override you can read the extra fields you declared in Ctx: for example, the code below accesses resource.version, which is only available because version was declared in the PressCtx type. Without those types you'd lose your metadata (and type checking) in the override.

class MyPress extends Press<Ctx> {
  protected override getSystemInputs(
    nodePath: Ctx['TNode'][],
    resource: Ctx['TResource'],
  ): Record<string, string | object> {
    return { ver: resource.version };
  }
}

const press = new MyPress('./src', './build', schema, { mainFile: true });
await Promise.all(press.run());

root (5th constructor argument) sets the compiler workspace, e.g. './' so resources can #include files outside the source directory.

About

Manage the organisation and compilation of multiple Typst documents.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages