Ferromark Flavored Markdown
Ferromark Flavored Markdown (FFM)
FFM is the name for Ferromark's opt-in authoring syntax on top of CommonMark and
GFM. It groups features for publishing richer documents without requiring a new
file format. Turn them all on with the ffm preset, or enable each feature
separately. Caption, attribution, table layout, marked text, inserted text,
inline notes, bracketed spans, guillemet digraphs, and technical abbreviations
are off in Node.js defaults and in every Rust preset except ffm(). Other
features have their own defaults. Keep unused syntax disabled to avoid its
parsing cost.
For standard Markdown, start with CommonMark and GFM. For option defaults and HTML trust, see Node.js, Rust, and rendering and trust.
Figures and sources
{.diagram}
: The **processing pipeline** {#pipeline .figure-wide}
> A memorable passage.
: Jane Doe, **author** {#source .byline}imageCaptions / image_captions gives a standalone image a visible
<figcaption>; its alternative text stays on <img>. imageAttributes /
image_attributes adds image classes and IDs. blockquoteAttributions /
blockquote_attributions puts a source line outside the quote in a figure
caption. IDs and classes on the caption line attach to the figure. Both caption
forms accept inline Markdown and can follow their block immediately or after
one blank line. See image boundaries
and quote boundaries.
Tables with captions and spans
| Item | Net | Tax |
| :--- | ---: | ---: |
| Book | 20.00 | 1.40 |
| Gift | Included ||
: Prices *today* {#prices .price-list}mergedTableCells / merged_table_cells reads adjacent closing pipes as a
horizontal span. tableAttributes / table_attributes adds a caption and
optional ID/classes to a GFM table. Renderer options tableColgroup and
tableColumnNames (Rust: table_colgroup, table_column_names) emit CSS
hooks for columns. Set column widths in CSS. See the
table syntax and CSS example.
Inline meaning and attributes
This is ==important==.^[An explanatory note.]
We ++added this sentence++ in the second edition.
The French [C’est la vie]{lang=fr} fits here.
[Documentation](https://example.org){.external hreflang=en}highlight renders ==...== as <mark>; inlineFootnotes /
inline_footnotes turns ^[...] into a footnote, and insertions renders
++...++ as semantic <ins> markup. These options are independent of code
highlighting, strikethrough, and reference footnotes. bracketedSpans /
bracketed_spans enables [text]{...}. extendedAttributes /
extended_attributes enables key/value attributes on spans, links, headings,
tables, images, and figures. Basic ID/class suffixes also have their own
feature options. Read the writing syntax
and attribute mapping rules,
especially before embedding untrusted output in a host framework that uses
data-* attributes.
More authoring syntax
| Use | Example | Node.js option | Rust option |
|---|---|---|---|
| Reference notes | A fact.[^source] | footnotes | footnotes |
| Definition lists | Term followed by : Explanation | definitionLists | definition_lists |
| Heading IDs/classes | # Title {#title .section} | headingAttributes | heading_attributes |
| Math notation | $x^2$ | math | math |
| Superscript/subscript | x^2^, H~2~O | superscript, subscript | superscript, subscript |
| Source metadata | Leading --- or +++ block | frontMatter | front_matter |
| Source comments | // note at line start | lineComments | line_comments |
| Alert boxes | > [!NOTE] | callouts | HtmlRendererOptions::callouts |
These options have separate boundaries. Math needs downstream typesetting. Front matter exposes raw metadata text, without parsing YAML or TOML values. Subscript takes precedence over single-tilde strikethrough when enabled. Callouts are a renderer feature, enabled in Node.js and the default Rust renderer; strict Rust specification profiles disable them. Other defaults are listed in the configuration guides. See front matter, line comments, and the feature comparison for further details.
Use the preset
import { toHtml } from "ferromark";
const html = toHtml("\n\n: Company logo", { preset: "ffm" });preset: "ffm" starts from GFM plus every syntax on this page except
subscript, math, front matter, and MDX, which change the meaning of
GFM input or need downstream processing. In Node.js it also enables technical
abbreviation markup. Individual options still override the preset, and the
output policy (renderPolicy, table colgroups, typography) stays your choice.
The preset trades speed for convenience. On documents that use none of its syntax, parsing takes 10–55% longer than with GFM alone, mostly for definition lists; abbreviation markup adds render time in proportion to the prose. Enable individual features when a document needs only a few. The preset decision lists the measured cost of each option.
In Rust, ParserOptions::ffm() selects the same syntax. Pair it with
HtmlRendererOptions::gfm() and, for abbreviations,
HtmlRenderer::with_abbreviations(AbbreviationOptions::default()). Guillemet
digraphs only become quotes when a typography pass with a language runs.
Enable a small dialect
import { toHtml } from "ferromark";
const html = toHtml("\n\n: Company logo", {
imageCaptions: true,
});The same option can be set as image_captions: true in Rust ParserOptions.
Other features remain at their defaults. Each additional enabled syntax may
add work even when a document does not use it; the
runtime profiles and linked feature reports
provide measurements.
Language-aware quotes
Il a dit <<Bonjour>> avant de partir.guillemetDigraphs / guillemet_digraphs keeps doubled angle brackets as text
instead of reading them as raw HTML or autolinks. A typography pass with an
explicit language then turns balanced pairs into that language's primary
quotation marks, for example « Bonjour » in French or „Bonjour“ in German. Unbalanced, escaped,
and protected markers, URLs, and shift expressions stay literal. For portable
input, write straight quotes and select a typography language instead. See the
typography guide.
Technical abbreviations
The API returns JSON over HTTP.Technical abbreviation markup adds no Markdown syntax. Set autoAbbreviations
in Node.js, or use HtmlRenderer::with_abbreviations in Rust, to wrap complete
uppercase technical terms in semantic <abbr> markup. A small built-in
dictionary supplies common titles; unknown candidates receive a bare wrapper.
The abbreviations map (Rust: AbbreviationOptions::overrides) adds a
mixed-case term, changes a title, or suppresses a false positive with null
(Rust: None). Matching runs during rendering, so the parsed AST and heading
metadata stay unchanged. Code, math, raw HTML, MDX attributes, URLs, link
destinations, and image alternative text are never wrapped. See the
API, token boundaries, and known limitations.
Typography transforms punctuation after parsing, and MDX captures component syntax for downstream integration. Their processing and trust boundaries differ from FFM's authoring syntax.