Releases: giordano137/MarkdownDocumentKit
Release list
v0.5.0 — real editable DOCX tables, written as OOXML by hand
v0.5.0 — real editable DOCX tables, written as OOXML by hand
WordDocumentExporter.export(blocks, title:) now produces .docx files whose
tables are actual Word tables — selectable, editable, resizable — instead of
the image AppKit's own .officeOpenXML writer produced. The reason it had to
be hand-written: asking AppKit for a table the "correct" way, via
NSTextTable/NSTextTableBlock, gets the structure silently dropped by that
specific writer. Confirmed it isn't the wrong way to ask by writing the same
attributed string to .rtf instead, where the table does come out real — it's
an .officeOpenXML-writer gap.
So each table is emitted as <w:tbl> XML by a new OOXMLTableWriter and spliced
into AppKit's own output at a placeholder paragraph, with MinimalZipArchive
(and CRC32) reading and rewriting the .docx container in place. Everything
that isn't a table still goes through AppKit's writer, which gets styling,
list numbering and the document skeleton right and would be a lot of surface
to reimplement for no gain. Verified against tools outside this codebase —
unzip plus XML well-formedness checks on word/document.xml, and opening the
result in a real word processor — since our own writer being validated
against our own reader proves nothing.
Also in this release:
-
Task lists (- [ ] / - [x]) and footnotes ([^id] inline, [^id]: as a
definition). Task lists get their own .taskListItem case rather than a new
field on .listItem, so existing exhaustive switches keep compiling;
footnote numbering follows GFM's first-reference-order convention. -
Fixed a docx superscript bug this surfaced: AppKit's writer encodes a
footnote reference's superscript as a raw <w:position> offset, which
macOS's own Quick Look docx preview renders lowered instead of raised.
WordDocumentExporter now substitutes the semantic
<w:vertAlign w:val="superscript"/> that Word's own UI writes. -
BREAKING (pre-1.0, see README's Versioning section): .codeBlock gained a
language: String? field carrying the fence's info string. It was already
parsed just to rule out ```mermaid and then discarded, leaving a consumer
no way to tell Swift from Python from untagged. Not rendered as syntax
highlighting — that stays out of scope with zero dependencies — this just
stops losing the information. -
Platform floor lowered to iOS 16+ / macOS 13+ (from iOS 17 / macOS 14).
Nothing in the codebase needed the higher floor; verified by lowering
Package.swift's platforms and rebuilding and retesting clean on both,
then confirming the availability check itself still bites. -
Opted into Swift Package Index DocC hosting via .spi.yml, and replaced the
hand-maintained Swift/platform badges with SPI's own. -
CONTRIBUTING.md now states the position on AI-assisted contributions —
allowed, no disclosure required, the bar is architecture rather than
syntax — and carries the iOS Simulator command, issue-first guidance for
larger changes, and a release procedure that pushes main before tagging.
The README now says outright that stars, issues and PRs are welcome, and
names scope as the one filter.
v0.4.0 — DiagramRenderer: real Mermaid diagrams, theme-matched
v0.4.0 — DiagramRenderer: real Mermaid diagrams, theme-matched
A fenced ```mermaid block now becomes a .diagram(source:) block, rendered
through an injected DiagramRenderer exactly like .image already is
through ImageRenderer — a consumer typically backs it with a hidden
WKWebView running mermaid.js. No renderer, or one that can't parse a
given diagram, falls back to the raw Mermaid source shown as a code
block, same "show the source, don't fake it" reasoning
FormulaRenderer/ImageRenderer already use.
DiagramRenderer also receives a DiagramPalette (four colors: node
background/border, line color, text color) derived from the active
DocumentTheme, so a rendered diagram can match the rest of the document's
colors instead of a diagramming library's own unrelated stock theme.
Verified end-to-end with a real mermaid-cli-backed DiagramRenderer:
side-by-side renders of the same diagram showed the difference between
"looks bolted on" and "looks like one document."
Also in this release:
- Fixed a real rendering bug: a multi-line code block showed a visible
gap between every line instead of one continuous shaded block, caused
by a paragraph style's spacing being applied per-line instead of once
for the whole block. Found by actually generating a PDF with a YAML
config example and looking at it. - Fixed a crash risk in DocumentTheme.calloutTint(for:) — it force-
unwrapped a lookup that assumed every CalloutKind case had a matching
default tint, an invariant the compiler never checked. - Added PDFRenderer test coverage for multi-page pagination and a table
landing whole on one page rather than split across a page break —
previously the riskiest, least-tested part of the package. - README overhaul: a Quick Start example right under the description
(verified to actually compile — the version that shipped briefly
didn't), a code example for each injected protocol, a real screenshot
of rendered output, and a "Known limitations" section. The old
phase-by-phase status writeup moved to ARCHITECTURE.md. Added
CONTRIBUTING.md and a versioning policy note.
v0.3.0 — DocumentTheme: inject colors/font sizes/spacing
v0.3.0 — DocumentTheme: inject colors/font sizes/spacing
Every color, font size, and spacing constant DocumentRenderer/
TableRenderer used is now sourced from a DocumentTheme struct, passed
as an optional parameter defaulting to .default (reproduces v0.2.0's
hardcoded look exactly — zero change for an existing consumer).
Overriding one field, or one callout kind's colors, leaves everything
else at its default.
Deliberately does not cover font family (system-font variants only) —
see README's "Styling is injected too" section for why.
Verified end-to-end on both platforms: a custom theme rendered into a
real PDF (macOS) and a real iOS Simulator-rendered table PNG, both
opened and visually confirmed correct, not just asserted via isolated
attribute checks.
v0.2.0 — real iOS (UIKit) support, not just macOS (AppKit)
v0.2.0 — real iOS (UIKit) support, not just macOS (AppKit)
Every renderer (DocumentRenderer, TableRenderer, PDFRenderer,
TableAttachment, FormulaRenderer, ImageRenderer) now runs on both
platforms from one shared implementation, via PlatformTypes.swift's
typealiases and a handful of helpers for genuine AppKit/UIKit API
divergences. v0.1.0 declared .iOS(.v17) support in Package.swift without
actually providing it — this closes that gap for real.
Verified on iOS with an actual Simulator test run (not just
cross-compilation): the full test suite green via xcodebuild test
against an iOS Simulator destination, plus a real rendered table bitmap
saved from that same simulator process and opened directly to confirm
it isn't upside down.
CI now runs both a macOS job and an iOS Simulator job on every push/PR.
v0.1.0 — first tagged release
v0.1.0 — first tagged release
A native Swift package that parses Markdown into a structured document
model and renders it to PDF, DOCX, or a plain NSAttributedString, without
a browser engine or an external typesetting binary. Zero dependencies —
math and image rendering are injected via FormulaRenderer/ImageRenderer
protocols a consumer implements.
Included:
- Block layout: headings, paragraphs (justified + hyphenated), lists,
fenced code blocks, blockquotes - Tables: measured column widths, wrapped rows, real selectable text in
PDF (not a flattened image), a bitmap fallback for DOCX - GFM alert callouts (> [!NOTE]/[!TIP]/[!WARNING]/[!IMPORTANT]) as
tinted, rounded, accent-labeled boxes - LaTeX formulas (block [...]/$$...$$ and inline
$...$ /(...)),
baseline-aligned so inline math flows with surrounding text - Images (
) — data: URI sources decode with zero consumer
code; local/remote sources go through an injected ImageRenderer - PDFRenderer: real multi-page PDF pagination via raw CoreText, no
NSPrintOperation round trip
Not yet implemented: Mermaid diagrams (DiagramRenderer), rounded table
corners in PDF, a real (not image) DOCX table.