Skip to content

Conversation

@jlevy
Copy link
Owner

@jlevy jlevy commented Jan 7, 2026

Summary

Fixes #11 - GitHub alert/callout blocks like > [!NOTE] were being completely dropped during Markdown normalization, leaving only the content without the block quote formatting.

Root Cause

Marko (the Markdown parser) recognizes GitHub-style alerts as a separate Alert element type (which extends Quote). The MarkdownNormalizer class was missing a render_alert method, so alerts were not being rendered correctly.

Changes

src/flowmark/formats/flowmark_markdown.py

  • Added render_alert() method to MarkdownNormalizer class
  • Outputs the alert header line (> [!NOTE], > [!TIP], etc.)
  • Renders alert content with proper > prefixing
  • Handles all five GFM alert types: NOTE, TIP, IMPORTANT, WARNING, CAUTION
  • Normalizes lowercase alert types to uppercase (e.g., [!note][!NOTE])

tests/test_alerts.py (new file)

  • 15 comprehensive test cases for alert handling
  • Covers all valid alert types
  • Critical robustness tests: Ensures misspelled/unknown alert types preserve quote formatting

tests/testdocs/testdoc.orig.md

  • Added GitHub Alerts/Callouts section with test cases

Validation Plan

Automated Testing ✅

Test Category Tests Status
Alert rendering (test_alerts.py) 15 tests ✅ Pass
All valid alert types NOTE, TIP, IMPORTANT, WARNING, CAUTION ✅ Pass
Lowercase normalization [!note][!NOTE] ✅ Pass
Robustness: Misspelled alerts [!NOOT], [!WARNUNG], etc. preserve quote ✅ Pass
Robustness: Unknown types [!CUSTOM], [!INFO] preserve quote ✅ Pass
Robustness: Malformed syntax [NOTE], [!NOTE, ![NOTE] preserve quote ✅ Pass
Multi-line content Multiple lines in alert ✅ Pass
Multiple paragraphs Paragraphs separated by > ✅ Pass
Nested code blocks ```python inside alert ✅ Pass
Nested lists - item inside alert ✅ Pass
Multiple alerts in document Several alerts with text between ✅ Pass
Regular quotes Normal quotes still work ✅ Pass
Reference doc formats All 4 expected output formats ✅ Pass
Full test suite 89 tests total ✅ All Pass

Linting & Type Checking ✅

  • ✅ codespell - no spelling errors
  • ✅ ruff check - all checks passed
  • ✅ ruff format - all files formatted
  • ✅ basedpyright - 0 errors, 0 warnings

Code Review Checklist ✅

  • Follows Python 3.11+ conventions
  • Full type annotations (with appropriate pyright ignores for Marko stub limitations)
  • Docstrings explain the "why" (Alert not in type stubs)
  • No unnecessary comments
  • Uses dedent() for multi-line strings in tests
  • No trivial tests - all tests verify important behavior
  • Robustness tests document critical requirements in docstrings

Edge Cases Verified ✅

Edge Case Expected Behavior Verified
Valid alerts (5 types) Preserve > [!TYPE] header and content
Lowercase alert type Normalize to uppercase
Misspelled alert type Fall back to regular quote, preserve all content
Unknown/custom alert type Fall back to regular quote, preserve all content
Empty alert [!] Preserve as regular quote
Malformed [NOTE] (no !) Preserve as regular quote
Malformed [!NOTE (no ]) Preserve as regular quote
Alert with code block Preserve code block inside
Alert with bullet list Preserve list inside
Alert with multiple paragraphs Preserve paragraph breaks
Alert after heading Proper spacing
Regular quotes (no alert) Still work correctly

Reviewer Notes

  1. Type annotations: The render_alert method uses block.Quote as the parameter type with # pyright: ignore because Marko's Alert class isn't in its type stubs. At runtime, the element is actually gfm_elements.Alert.

  2. Robustness design: Unknown/misspelled alert types gracefully degrade to regular quotes via Marko's parser fallback. This means content is never lost - at worst, it becomes a regular quote instead of a styled alert.

  3. Future alert types: The rendering code is flexible - it outputs whatever alert_type Marko parses. If Marko adds new types, they'll work automatically. The only limitation is Marko's parser regex which currently only matches the 5 standard GitHub types.

claude added 6 commits January 7, 2026 00:13
GitHub-flavored Markdown supports alert blocks (callouts) like:
> [!NOTE]
> This is a note

These were being dropped during normalization because the
MarkdownNormalizer class was missing a render_alert method to handle
Marko's Alert element type (which extends Quote).

Added render_alert method to properly preserve alert blocks with their
type (NOTE, TIP, IMPORTANT, WARNING, CAUTION) and content.

Also added comprehensive test cases to the testdoc covering:
- All five alert types
- Multi-line alert content
- Multiple paragraphs in alerts
- Alerts with code blocks
- Alerts with lists
- Lowercase alert types (normalized to uppercase)

Fixes #11
- Add tests/test_alerts.py with 15 test cases covering:
  - All five valid alert types (NOTE, TIP, IMPORTANT, WARNING, CAUTION)
  - Lowercase alert normalization to uppercase
  - CRITICAL robustness tests: misspelled/unknown alert types must
    preserve quote formatting (fall back to regular quotes)
  - Edge cases: empty brackets, malformed syntax, multiple paragraphs
  - Nested content: code blocks, lists within alerts
  - Multiple alerts in a document

- Fix type annotations in render_alert to work with pyright
  (Alert class not in Marko's type stubs)

All 89 tests pass.
GFM Alert support was added in Marko v2.2.0 (August 2025).
The previous minimum of 2.1.3 did not include this feature,
causing CI failures on systems that installed older versions.
Documents behavior for:
- Non-standard alert types ([!FOO], [!CUSTOM], [!INFO])
- Misspelled alert types ([!NOOT], [!WRANING])
- Malformed alert syntax ([NOTE], [!])

All of these gracefully degrade to regular block quotes,
preserving all content without any data loss.
…ection

- Added [!FOO] to unknown alert types test to match testdoc
- Changed [!WRANING] to [!WARNNG] to avoid codespell auto-correction
  (WRANING was being corrected to WARNING, which is a valid alert type)
- Updated testdoc and expected files accordingly

All 89 tests pass.
@jlevy jlevy merged commit b561943 into main Jan 7, 2026
5 checks passed
@jlevy jlevy deleted the claude/setup-gh-cli-fix-issues-70Vzi branch January 7, 2026 01:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Quotations with GitHub callouts are dropped

3 participants