Skip to main content

adf-bridge

adf-bridge is a small, pure-Python bridge between portable GFM Markdown and a focused Jira-oriented subset of Atlassian Document Format (ADF). It returns ordinary JSON-compatible dictionaries rather than model classes.

from adf_bridge import adf_to_markdown, markdown_to_adf

created = markdown_to_adf("Hello [~accountId:557057:User-AbC]")
assert created.value["type"] == "doc"
assert adf_to_markdown(created.value).value == "Hello [~accountId:557057:User-AbC]"

API and behavior

  • markdown_image_urls(markdown, *, strict=False) -> ConversionResult[tuple[str, ...]]
  • markdown_to_adf(markdown, *, strict=False, resolved_images=()) -> ConversionResult[AdfDocument]
  • adf_to_markdown(document, *, strict=False) -> ConversionResult[str]
  • validate_adf(document) -> None
  • verify_jira_media_readback(submitted, persisted, *, resolved_images) -> None

A ConversionResult holds value and an ordered tuple of structured Diagnostic values. strict=True converts any readable-degradation warning into LossyConversionError after conversion completes. Invalid ADF, unknown constructs, and out-of-profile features always raise project-owned errors.

Blank CommonMark Markdown becomes the canonical sole empty root paragraph. Empty ADF documents also render as an empty string. GFM output is canonicalized and has no terminal newline; exact source spelling is not round-tripped.

v0.1 profile

Direct support covers paragraphs, headings, blockquotes, lists, code blocks, hard breaks, rules, tables, text, strong/emphasis/strike/code/link marks, and canonical Jira account-ID mentions. A mention nested in Markdown emphasis, strong, or strikethrough is emitted unmarked because the Jira ADF schema forbids mention marks; this produces markdown.mention_marks_discarded and strict mode rejects it. Mention IDs remain opaque; &, <, and > are source-encoded safely. Adjacent marked text uses a local mark stack, so shared presentation marks stay open across supported overlaps. Basic table-cell paragraphs and hard breaks are flattened through exact lowercase <br> with one warning per affected cell. Dates, emoji, inline cards, status, expand/panel, and unmarked media have readable warning-producing fallbacks. Inline-code line endings normalize to spaces with a diagnostic; code-block text canonicalizes to LF with one trailing newline when nonempty and warns only when that changes its semantic text.

Link, image, and card labels entity-encode their nested literal syntax, so URL labels with Markdown punctuation round-trip without retained escape backslashes. Inside table cells, nested syntax-owned values including mention IDs and link titles entity-encode pipes before GFM table parsing. Form feed is entity-encoded losslessly. Bridge-generated direct link, card, and external-media destinations are opaque values: a reversible CommonMark entity encoding preserves their exact supported characters without URL normalization. Caller-authored Markdown autolinks and used reference links instead use CommonMark/Mistune URL normalization; their raw source spelling is not an opaque-destination preservation contract and produces no diagnostic. Ordinary and readable-fallback text containing U+0000 normalizes to U+FFFD with a warning; mention IDs containing U+0000 are rejected to preserve their opaque identity. Markdown consisting only of reference definitions produces no visible ADF content and warns with markdown.reference_definitions_discarded. Values containing a character that HTML5 character references cannot preserve (such as NUL) are fatal at the bridge-generated destination attribute. Presentation marks with an unrepresentable Unicode-whitespace boundary (such as VT or NEL) preserve their text but are discarded with a warning. Ordinary/root VT and NEL text remains exact; at list or table edges a reversible source entity is used when available, or adf.boundary_whitespace_normalized documents unavoidable loss. Empty link titles and titles containing control characters are intentionally omitted with an attribute-discard warning.

Block alignment and indentation marks, and every mark on media, mediaSingle, or mediaGroup, are fatal because v0.1 has no unambiguous GFM placement for them. Linked inline code containing [ or ] is also fatal: Mistune/CommonMark cannot preserve those code-label characters exactly. A nonterminal heading hard break and an ordered list whose generated sequence exceeds nine-digit markers are rejected rather than silently changing block structure. Every break in a terminal paragraph or heading hard-break run is discarded with a warning because portable GFM has no semantic representation for it; table-cell breaks retain their <br> flattening policy. A heading's literal ATX closing-hash candidate is source-encoded to preserve trailing # text. Only the canonical sole root empty paragraph represents empty visible Markdown; other ordinary empty ADF paragraphs are fatal. The exact empty paragraph shapes produced by GFM empty list items and table cells render as canonical empty list markers and cells. Adjacent same-kind lists use equivalent alternating GFM markers to remain distinct. Empty Markdown link labels, linked images, images in headings or table cells, and unsupported table-cell shapes are rejected rather than silently dropped.

See the support matrix and diagnostics guide for details. markdown_image_urls() uses the same focused parser as conversion and returns supported image destinations in source order. Callers can supply immutable ResolvedJiraImage(source_url, media_id, collection) values to convert exact matching image URLs into Jira file media; unmapped URLs remain external. Mappings are data only: invalid, unused, duplicate-source, or duplicate Jira media-identity (media_id, collection) entries fail, and no URL normalization or Jira enrichment is performed. Markdown owns alt text for every occurrence. Managed media cannot render back to its original attachment-content URL. On ADF-to-Markdown conversion, nonempty managed-media alt text is preserved as escaped readable text; absent or empty alt renders as neutral attachment text. Opaque media IDs are never used in Markdown presentation. verify_jira_media_readback() narrowly checks persisted managed media at the same ADF paths, permitting only known Jira local IDs, sizing, occurrence keys, and nonnegative media dimensions. This package does not perform Jira lookups, network operations, CLI work, or plugin registration.

Schema and licenses

The wheel bundles the exact unmodified @atlaskit/adf-schema 57.3.4 full JSON Schema. It is checksum-verified, requires local-only $ref values, and is compiled once with defaults disabled using fastjsonschema. Project code is MIT licensed. The bundled Atlassian schema is Apache-2.0; its attribution and full license are in THIRD_PARTY_NOTICES.md.

Development

Use uv:

uv sync --all-groups
make check-ci

See CONTRIBUTING.md for the focused validation commands.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

adf_bridge-0.1.2.tar.gz (63.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

adf_bridge-0.1.2-py3-none-any.whl (47.1 kB view details)

Uploaded Python 3

File details

Details for the file adf_bridge-0.1.2.tar.gz.

File metadata

  • Download URL: adf_bridge-0.1.2.tar.gz
  • Upload date:
  • Size: 63.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for adf_bridge-0.1.2.tar.gz
Algorithm Hash digest
SHA256 8c55d2e28b239519f0996bb8b6c4948a3c0c154082afdabc6078d36e051b211d
MD5 6b5600273edab13b59245bb25b5ebd3b
BLAKE2b-256 c6679a09d50daedb9892e88c3d02fd917bbae7a5dc10eac45e90dcf8e62b5803

See more details on using hashes here.

Provenance

The following attestation bundles were made for adf_bridge-0.1.2.tar.gz:

Publisher: publish.yml on en-ver/adf-bridge

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file adf_bridge-0.1.2-py3-none-any.whl.

File metadata

  • Download URL: adf_bridge-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 47.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for adf_bridge-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 90fad16ee1cb2f24811c8100e4435d114017fb161079281eef169db3f8203f0e
MD5 a331f54d3badab5e68438deadc8fcd41
BLAKE2b-256 233be007149d82d5227c0a4b5407cfadc15033a0c1bb5c4a029201962f97cbef

See more details on using hashes here.

Provenance

The following attestation bundles were made for adf_bridge-0.1.2-py3-none-any.whl:

Publisher: publish.yml on en-ver/adf-bridge

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.1.3

2 files

This release

0.1.2 This release

2 files

0.1.1

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page