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) -> Noneverify_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.
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file adf_bridge-0.1.0.tar.gz.
File metadata
- Download URL: adf_bridge-0.1.0.tar.gz
- Upload date:
- Size: 62.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a53845a16b11f03b3ae023959c3992a069a1fe92fa6a8f697452dd7c34a143f7
|
|
| MD5 |
534b80708e4c0ee2b863a11f35d13428
|
|
| BLAKE2b-256 |
5e467ded60efc982686f932e3a2a6168394b7c0a0d5972881a59b5c0d09d0a6d
|
Provenance
The following attestation bundles were made for adf_bridge-0.1.0.tar.gz:
Publisher:
publish.yml on en-ver/adf-bridge
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
adf_bridge-0.1.0.tar.gz -
Subject digest:
a53845a16b11f03b3ae023959c3992a069a1fe92fa6a8f697452dd7c34a143f7 - Sigstore transparency entry: 2742809612
- Sigstore integration time:
-
Permalink:
en-ver/adf-bridge@b6a66d9a6b96778c876d74bb2c0e00f941b1bfb2 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/en-ver
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@b6a66d9a6b96778c876d74bb2c0e00f941b1bfb2 -
Trigger Event:
push
-
Statement type:
File details
Details for the file adf_bridge-0.1.0-py3-none-any.whl.
File metadata
- Download URL: adf_bridge-0.1.0-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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d789f2ea2f6159f86aaa34cbc34abec34179a14e2a971626bff41c132449a3a7
|
|
| MD5 |
7bf5448be4800c90cca54f0f488ede12
|
|
| BLAKE2b-256 |
ed17987eaaa49cc110487bd24b986b5377e86d031f3ecd51f4e8ca74dac5c026
|
Provenance
The following attestation bundles were made for adf_bridge-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on en-ver/adf-bridge
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
adf_bridge-0.1.0-py3-none-any.whl -
Subject digest:
d789f2ea2f6159f86aaa34cbc34abec34179a14e2a971626bff41c132449a3a7 - Sigstore transparency entry: 2742809706
- Sigstore integration time:
-
Permalink:
en-ver/adf-bridge@b6a66d9a6b96778c876d74bb2c0e00f941b1bfb2 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/en-ver
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@b6a66d9a6b96778c876d74bb2c0e00f941b1bfb2 -
Trigger Event:
push
-
Statement type: