poka.sh

Docs

Which AST to emit, and when to go standalone

explanation

A parser takes file bytes and answers with a typed message. This page explains the three ways it can answer and why a shared AST is the default. The exact contract is in SPEC.md section 4; where this page and SPEC.md differ, SPEC.md wins.

Three extension kinds

Kind plugin.json stdin stdout
Parser with a shared viewer "viewer": "poka-<shape>-viewer" PreviewRequest one *Ast message
Standalone parser no viewer field PreviewRequest a full PreviewResponse
Viewer "file_extension": "" a *Ast message HTML

A viewer belongs to the viewers repo. A parser author chooses between the first two.

Why a shared viewer is the default

The host runs the parser, pipes its output into the viewer and wraps the HTML that comes back. As a result:

  • The parser has no HTML. It decodes the format and fills a typed structure. A typical parser is a few dozen to a few hundred lines of format logic.
  • One fix reaches every format. A better table renderer improves every parser that emits a TableAst.
  • Desktop, web and mobile look the same, because the viewer is shared and the host renders its output identically everywhere.

Pick the AST by the shape of the content

Choose the AST for what the user needs to see, not for how the file is stored. The proto (core/proto/preview.proto) defines the set, among them TableAst, WorkbookAst, TextAst, TreeAst, SlideDeckAst, Drawing2DAst, Scene3DAst, ImageWithMetaAst, ImagePagesAst, DiffAst, EbookAst, ChartAst and MetadataCardAst.

  • A file of rows and columns is a TableAst, even if it is binary.
  • A file of nested keys, an XML or a container listing is a TreeAst.
  • A file you can only identify, with a header and a few fields, is a MetadataCardAst. That is a thin result; see Depth tiers.
  • A drawing is a Drawing2DAst, a model is a Scene3DAst.

One AST type per plugin. Every success path emits the type the manifest's viewer decodes. A parser that emits TreeAst on one branch and ImageWithMetaAst on another breaks the viewer on the branch the manifest does not name. The failure path is the one exception: it answers with an ErrorResponse, which the host shows before the viewer runs.

When to go standalone

Go standalone only when the format needs a response type no shared AST covers, for example an SVG, an image, a PDF or a drawing the host draws itself. A standalone parser writes the whole PreviewResponse, so it also owns escaping, theming and limits. That is more code and more risk, and it is the exception: most manifests declare a shared viewer.

Two cases look like standalone but are not. A parser with a viewer may answer with a complete PreviewResponse when its content has no shared shape (a text fallback, or several tabs through a MultiView). SPEC.md section 4 lists them. The manifest still names a viewer.

See also