Decompose _parseBlock (447 lines) into directive/fenced/body/type-inference phases #53

Merged
brenno merged 1 commit from refactor/decompose-parseblock into main 2026-06-30 17:52:30 +00:00
Owner

The parse counterpart to #52. _parseBlock was the single largest method in the tree at 447 lines, doing four jobs at once. It is decomposed into named phases (all kept in the markdown_service_parse part), leaving _parseBlock a thin orchestrator:

phase responsibility
_parseBlockDirectives parse the <!-- _class --> marker + every directive comment (advance/skip/tlp/_style/two-bullets/timeline/list-style/checklist/title/bullet-marker); returns the stripped body + decoded values
_tryFencedSlide delegate code/chart/cockpit/question slides up front
_parseBodyLines walk the body lines into headings/bullets/images/captions/video/audio/quote/table content
_inferSlideType pick the SlideType from class tokens, else from content

Why this is safe

The method bodies move verbatim (only wrapped in the new methods and threaded through plain records; bullets is passed by reference so it still accumulates in place). The parse result is therefore identical — proven by the round-trip (65 tests) and adversarial fuzz (53 tests) suites, which serialise a deck then re-parse it and compare every field.

On the ceiling

_parseBodyLines remains a single 229-line state machine over ~20 accumulated fields. Splitting it further needs a mutable state-holder that would relocate the same code with real transcription risk and little readability gain, so I stopped there. The worst-method ceiling for this file still drops 447 → 229: the _parseBlock baseline entry is replaced by a _parseBodyLines one (count unchanged at 27 baselined). A future PR can take it under 150 with a holder if desired.

Verification

  • flutter analyze --fatal-infos — clean
  • flutter test921 passed, incl. round-trip (65) and fuzz (53)
  • dart run tool/check_method_length.dart — green (27 baselined)
  • dart format — clean
The parse counterpart to #52. `_parseBlock` was the single largest method in the tree at **447 lines**, doing four jobs at once. It is decomposed into named phases (all kept in the `markdown_service_parse` part), leaving `_parseBlock` a thin orchestrator: | phase | responsibility | |---|---| | `_parseBlockDirectives` | parse the `<!-- _class -->` marker + every directive comment (advance/skip/tlp/_style/two-bullets/timeline/list-style/checklist/title/bullet-marker); returns the stripped body + decoded values | | `_tryFencedSlide` | delegate code/chart/cockpit/question slides up front | | `_parseBodyLines` | walk the body lines into headings/bullets/images/captions/video/audio/quote/table content | | `_inferSlideType` | pick the `SlideType` from class tokens, else from content | ### Why this is safe The method bodies move **verbatim** (only wrapped in the new methods and threaded through plain records; `bullets` is passed by reference so it still accumulates in place). The parse result is therefore identical — proven by the **round-trip** (65 tests) and **adversarial fuzz** (53 tests) suites, which serialise a deck then re-parse it and compare every field. ### On the ceiling `_parseBodyLines` remains a single **229-line** state machine over ~20 accumulated fields. Splitting it further needs a mutable state-holder that would relocate the same code with real transcription risk and little readability gain, so I stopped there. The worst-method ceiling for this file still drops **447 → 229**: the `_parseBlock` baseline entry is replaced by a `_parseBodyLines` one (count unchanged at 27 baselined). A future PR can take it under 150 with a holder if desired. ### Verification - `flutter analyze --fatal-infos` — clean - `flutter test` — **921 passed**, incl. round-trip (65) and fuzz (53) - `dart run tool/check_method_length.dart` — green (27 baselined) - `dart format` — clean
Decompose _parseBlock into directive/fenced/body/type-inference phases
Some checks failed
CI / Gate (Linux) · Format · Analyze · Coverage (push) Has been cancelled
CI / Test (macos-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Web hardening (push) Has been cancelled
CI / Docs links (push) Has been cancelled
CI / Gate (Linux) · Format · Analyze · Coverage (pull_request) Has been cancelled
CI / Test (macos-latest) (pull_request) Has been cancelled
CI / Test (windows-latest) (pull_request) Has been cancelled
CI / Web hardening (pull_request) Has been cancelled
CI / Docs links (pull_request) Has been cancelled
1578d6b4e7
_parseBlock was a 447-line method doing four jobs at once. It is split into
named phases, all kept in the markdown_service_parse part:

  * _parseBlockDirectives — parse the <!-- _class --> marker and every other
    directive comment (advance/skip/tlp/_style/two-bullets/timeline/list-
    style/checklist/title/bullet-marker), returning the stripped body + the
    decoded values;
  * _tryFencedSlide — delegate code/chart/cockpit/question slides up front;
  * _parseBodyLines — walk the body lines into headings/bullets/images/
    captions/video/audio/quote/table content;
  * _inferSlideType — pick the SlideType from class tokens, else content.

_parseBlock is now a thin orchestrator. The bodies are moved verbatim, so
the parse result is identical — proven by the round-trip and adversarial
fuzz suites (which serialise then re-parse and compare every field).

The body-line walker stays a single 229-line state machine over ~20
accumulated fields: splitting it further needs a mutable holder that would
relocate the same code with real transcription risk and little gain. So the
worst-method ceiling for this file drops from 447 to 229 — the _parseBlock
baseline entry is replaced by a _parseBodyLines one (still 27 baselined).
brenno merged commit 465d34e6e8 into main 2026-06-30 17:52:30 +00:00
brenno deleted branch refactor/decompose-parseblock 2026-06-30 17:52:31 +00:00
Sign in to join this conversation.
No description provided.