Skip to content

Supported formats reference

docmeta reads metadata from a document using a per-format extractor. The extractor is chosen from the file extension, or forced with --as <format>. Every extractor below is implemented and counts toward directory and glob walks.

Format (--as name) Extensions Metadata source fill can write
markdown .md, .markdown Leading fenced frontmatter — YAML (--- … ---), TOML (+++ … +++), or JSON (;;; … ;;;). Yes
mdx .mdx Leading fenced frontmatter — YAML, TOML, or JSON. Yes
asciidoc .adoc, .asciidoc Fenced frontmatter, or the native header: = Title plus :key: value attributes. Only into an existing fenced block
rst .rst Fenced frontmatter, or the native section title plus :key: value docinfo fields. Only into an existing fenced block
xml .xml, .dita, .ditamap Attributes of the root element. No
html .html, .htm <title> plus <meta name="…" content="…"> tags. No

Writing metadata back is a harder problem than reading it. fill will only write a format it can round-trip without disturbing the rest of the document.

Fenced frontmatter round-trips cleanly: docmeta replaces only the characters between the fences, so the body, the fence style, and (for YAML) comments and quoting survive untouched.

The native syntaxes do not. AsciiDoc attributes and reStructuredText docinfo fields are read through a YAML scalar parse that loses the original spelling, and an rst title is synthesized from the section heading rather than stored as a field. Writing it back would mean rewriting the underline adornment or adding a :title: field that shadows the heading. Nor can docmeta simply add a fenced block to those files: a bare --- is a transition in reStructuredText and an open-block delimiter in AsciiDoc, so inventing one would change how the page renders. XML and HTML would have to be re-serialized wholesale, which reflows entities, attribute quoting, and void elements across the entire file.

Run docmeta schemas to see the current writability of each format. Targeting a read-only file with fill is reported as a per-file error; the rest of the run continues.

The --as name is the extractor name in the first column. The extension match is case-insensitive.

Wherever docmeta reads frontmatter (Markdown, MDX, and the fenced-block path of AsciiDoc and reStructuredText), it accepts three interchangeable flavors (a convention also used by Vale). The flavor is auto-detected from the opening fence, so no flag or --as name is needed:

Flavor Fence Inner syntax
YAML ------ (or ... close) YAML
TOML ++++++ TOML
JSON ;;;;;; a JSON object

YAML additionally accepts the conventional ... document-end marker as a closing fence; TOML and JSON close on a repeat of their own opening fence.

All three are fenced blocks at the very top of the file: the opening fence on its own line, the content beneath, and a matching closing fence. A fence that never closes is not treated as frontmatter. For AsciiDoc and rst the native header is read instead, and for Markdown and MDX (which have no native fallback) the metadata is reported as absent, not as an error. A malformed block (invalid YAML, TOML, or JSON) is a per-file parse failure (exit code 1; see Output & exit codes), and the rest of the run continues.

Error annotations point at the offending field’s own source line. For TOML this is best-effort: bare and simply-quoted top-level keys (key = …, "key" = …) map to their line, while dotted keys, keys nested under a [table], and quoted keys containing escape sequences fall back to the block’s opening fence line.

Both read a leading fenced frontmatter block in any of the three flavors. MDX uses the same logic as Markdown; export const meta = {…} is not read. A file with no frontmatter reports its metadata as not present.

The three blocks below are equivalent:

---
type: guide
title: Getting started
tags: [setup, onboarding]
---
+++
type = "guide"
title = "Getting started"
tags = ["setup", "onboarding"]
+++
;;;
{
"type": "guide",
"title": "Getting started",
"tags": ["setup", "onboarding"]
}
;;;

AsciiDoc accepts two metadata styles. If the file opens with a complete fenced frontmatter block (YAML, TOML, or JSON), that block is used. Otherwise docmeta reads the native document header: the lines from the top of the file down to the first blank line:

  • A leading = Title line becomes title.
  • Each :name: value line becomes a name key. A :name: with no value is true; an unset attribute (:!name: or :name!:) is false.
  • Other header lines (such as author or revision lines) are ignored.
= Getting started
:type: guide
:draft: false

reStructuredText also accepts two styles. A complete leading fenced frontmatter block (YAML, TOML, or JSON) is used when present (as some MyST setups produce it). Otherwise docmeta reads the native page metadata:

  • A leading section title (a line underlined, and optionally overlined, with punctuation) becomes title.
  • The docinfo field list that follows, a run of :name: value fields, becomes the remaining keys. A :name: with no value is true. An explicit :title: field takes precedence over the heading.
Getting started
===============
:type: guide
:tags: [setup, onboarding]

XML metadata comes from the attributes of the root element. Namespace declarations (xmlns and xmlns:*) are dropped as transport noise.

<document type="concept" version="2" />

This yields type: "concept" and version: 2. Malformed XML is reported as a per-file parse error. An entity docmeta cannot resolve is not malformed XML: no external DTD is ever fetched, so a reference such as &nbsp; is left as written and the file is still read.

DITA topics (.dita) and maps (.ditamap) are read by the same extractor, so their root-element attributes are the metadata:

<concept id="metadata-overview" type="concept" xml:lang="en-us">

This yields id, type, and xml:lang; the DOCTYPE declaration is skipped. The DTD-declared entities common in DITA content (&nbsp;, &mdash;) do not fail the file — see above. Metadata held in a <prolog> element is not read.

HTML metadata comes from the document head:

  • <title>…</title> becomes title (the first <title> wins; its text is kept verbatim).
  • <meta name="X" content="Y"> becomes X: Y. property="X" is accepted in place of name for OpenGraph-style tags.
  • <meta> tags with neither name nor property (such as charset or http-equiv) carry no metadata and are skipped. For duplicate keys, the last tag wins.
<title>Getting started</title>
<meta name="type" content="guide">
<meta name="draft" content="false">

HTML parsing recovers from malformed markup, so extraction does not throw a parse error.

On the native metadata paths (the AsciiDoc header, the reStructuredText docinfo field list, XML attributes, and HTML <meta>/<title>), each value is parsed as a YAML scalar. This means string-looking inputs are coerced to their natural types:

Raw value Becomes Type
2 2 number
true true boolean
[a, b] ["a", "b"] array

An explicitly empty value (title="" in XML, content="" in HTML) stays the empty string rather than becoming null.

Fenced frontmatter carries its own native types instead, with no per-value scalar re-parsing is applied. YAML types come from normal YAML rules, and TOML and JSON from their own type systems (so version = 2 and "version": 2 are both the number 2, and a TOML/JSON array is a list).

Because the value’s type is decided by how it’s written, quoting is a real authoring choice in every flavor: a quoted "2" (or YAML version: "2") is the string "2", which will not satisfy a schema field typed integer.