Convert Atlassian Document Format (ADF) content to plain text. ADF is Jira Cloud's rich text format returned for fields like description. This function recursively extracts text content from the ADF structure. Args: adf_content: ADF document (dict), content list, string, o
(adf_content: dict | list | str | None)
| 275 | |
| 276 | |
| 277 | def adf_to_text(adf_content: dict | list | str | None) -> str | None: |
| 278 | """ |
| 279 | Convert Atlassian Document Format (ADF) content to plain text. |
| 280 | |
| 281 | ADF is Jira Cloud's rich text format returned for fields like description. |
| 282 | This function recursively extracts text content from the ADF structure. |
| 283 | |
| 284 | Args: |
| 285 | adf_content: ADF document (dict), content list, string, or None |
| 286 | |
| 287 | Returns: |
| 288 | Plain text string or None if no content |
| 289 | """ |
| 290 | if adf_content is None: |
| 291 | return None |
| 292 | |
| 293 | if isinstance(adf_content, str): |
| 294 | return adf_content |
| 295 | |
| 296 | if isinstance(adf_content, list): |
| 297 | texts = [] |
| 298 | for item in adf_content: |
| 299 | text = adf_to_text(item) |
| 300 | if text: |
| 301 | texts.append(text) |
| 302 | return "\n".join(texts) if texts else None |
| 303 | |
| 304 | if isinstance(adf_content, dict): |
| 305 | # Check if this is a text node |
| 306 | if adf_content.get("type") == "text": |
| 307 | return adf_content.get("text", "") |
| 308 | |
| 309 | # Check if this is a hardBreak node |
| 310 | if adf_content.get("type") == "hardBreak": |
| 311 | return "\n" |
| 312 | |
| 313 | # Check if this is a mention node |
| 314 | if adf_content.get("type") == "mention": |
| 315 | attrs = adf_content.get("attrs", {}) |
| 316 | return attrs.get("text") or f"@{attrs.get('id', 'unknown')}" |
| 317 | |
| 318 | # Check if this is an emoji node |
| 319 | if adf_content.get("type") == "emoji": |
| 320 | attrs = adf_content.get("attrs", {}) |
| 321 | return attrs.get("text") or attrs.get("shortName", "") |
| 322 | |
| 323 | # Check if this is a date node |
| 324 | if adf_content.get("type") == "date": |
| 325 | attrs = adf_content.get("attrs", {}) |
| 326 | timestamp = attrs.get("timestamp") |
| 327 | if timestamp: |
| 328 | try: |
| 329 | dt = datetime.fromtimestamp(int(timestamp) / 1000, tz=timezone.utc) |
| 330 | return dt.strftime("%Y-%m-%d") |
| 331 | except (ValueError, OSError, TypeError, OverflowError): |
| 332 | return str(timestamp) |
| 333 | return "" |
| 334 |