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.
Formats
Section titled “Formats”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 |
Why some formats are read-only
Section titled “Why some formats are read-only”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.
Frontmatter flavors
Section titled “Frontmatter flavors”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.
How each format is read
Section titled “How each format is read”Markdown and MDX
Section titled “Markdown and MDX”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: guidetitle: Getting startedtags: [setup, onboarding]---+++type = "guide"title = "Getting started"tags = ["setup", "onboarding"]+++;;;{ "type": "guide", "title": "Getting started", "tags": ["setup", "onboarding"]};;;AsciiDoc
Section titled “AsciiDoc”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
= Titleline becomestitle. - Each
:name: valueline becomes anamekey. A:name:with no value istrue; an unset attribute (:!name:or:name!:) isfalse. - Other header lines (such as author or revision lines) are ignored.
= Getting started:type: guide:draft: falsereStructuredText
Section titled “reStructuredText”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: valuefields, becomes the remaining keys. A:name:with no value istrue. 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 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 ( , —) 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>becomestitle(the first<title>wins; its text is kept verbatim).<meta name="X" content="Y">becomesX: Y.property="X"is accepted in place ofnamefor OpenGraph-style tags.<meta>tags with neithernamenorproperty(such ascharsetorhttp-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.
Type coercion
Section titled “Type coercion”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.