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. 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.1.tar.gz (62.6 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.1-py3-none-any.whl (47.0 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: adf_bridge-0.1.1.tar.gz
  • Upload date:
  • Size: 62.6 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.1.tar.gz
Algorithm Hash digest
SHA256 ed157f7632f755c21ab205e7b7776e2fd1c0384106a2be2cd506abad3ecff7a0
MD5 9aa335c2c3f3e1fe53be28588a402e52
BLAKE2b-256 8ef7be66fc4dcafe8cdf668cd844b1e1491e150ec4d3f4b2ecdee59aa0664f78

See more details on using hashes here.

Provenance

The following attestation bundles were made for adf_bridge-0.1.1.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.1-py3-none-any.whl.

File metadata

  • Download URL: adf_bridge-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 47.0 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.1-py3-none-any.whl
Algorithm Hash digest
SHA256 6cfcad3500dba477c54a365eacab166d1935ac8c0e433a79c2f261621369d5cc
MD5 6c085b2faa28358395a169968987bed3
BLAKE2b-256 eedf3a0b1ee5c90e686f990139230a680a77d7c8743b35a74ece0ac543940db7

See more details on using hashes here.

Provenance

The following attestation bundles were made for adf_bridge-0.1.1-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

This release

0.1.1 This release

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