Skip to content

Housekeeping: rename the API, add ktfmt, detekt and Konsist - #3

Merged
lemcoder merged 3 commits into
mainfrom
housekeeping-lint
Aug 11, 2026
Merged

Housekeeping: rename the API, add ktfmt, detekt and Konsist#3
lemcoder merged 3 commits into
mainfrom
housekeeping-lint

Conversation

@lemcoder

Copy link
Copy Markdown
Owner

Three commits, reviewable in order.

1. Rename the MarkItDown API surface to MikroMarkdown

The factory functions and exception base class still carried the name of the upstream project this was ported from.

  • MarkItDown()MikroMarkdown() (JVM), MarkItDown(context)MikroMarkdown(context) (Android)
  • MarkItDownExceptionMikroMarkdownException
  • CLI command class and its help name now read mikromarkdown
  • README updated; the one remaining MarkItDown mention is the upstream project link

Breaking for 0.1.0 consumers, with no deprecated aliases, matching the convertparse change.

2. Vendor anydoc as a submodule

This is a cherry-pick of #2, which never reached main. #2 was based on document-model-pipeline and merged into it at 22:53 — but that branch had already merged to main at 11:36, so the submodule landed on a dead branch. main's .gitmodules has only markitdown. This commit fixes that.

3. ktfmt, detekt and Konsist

All three run under ./gradlew check, plus a new CI lint job.

tool version scope
ktfmt 0.27.0 kotlinlang style, 120 columns, all source sets
detekt 1.23.8 defaults plus config/detekt/detekt.yml
Konsist 0.17.3 ArchitectureTest in library/jvmTest

ktfmt gap: ktfmt-gradle only derives tasks for the common and JVM source sets. androidMain, androidHostTest and androidDeviceTest get none — half the converters live there. library/build.gradle.kts registers matching format/check tasks and wires them into ktfmtCheck and check.

detekt config overrides only rules that clash with deliberate choices here: broad catch in converters (format libraries throw widely and converters degrade instead of propagating), PascalCase factory functions, and complexity thresholds for the format-walking parsers.

Konsist rules, each verified to fail against a planted violation:

  1. layers depend in one direction only — model depends on nothing; render and converters depend on model
  2. converters do not reach into the renderer — nothing under ..converters.. imports .render.
  3. markdown syntax only lives in the renderer — no table pipes, ATX headings, bold markers, image syntax or code fences in string literals outside render/
  4. converters implement DocumentConverter and are named accordingly
  5. the model stays free of platform dependencies — no java.* or android.* under model/, keeping the model usable from any KMP target

Rule 3 is a text scan rather than an AST rule, so it is blunt on purpose: a legitimate "**" in a converter would trip it. That is the trade that keeps Markdown building out of converters.

Bug found while clearing detekt

The escaping pass tracked line-start position in a mutable flag that was already false by the time it reached an ordered-list delimiter, so both the digit and delimiter branches were dead — 1. item in running text could still open a list. Escaping is now position-based and honours leading indentation.

Other cleanups it prompted:

  • PPTX chart extraction went from eight near-identical loops to five toSeries() helpers; bar/bar3D, line/line3D and area/area3D each share a generated series type
  • MikroMarkdown.parse selects the converter first, with failure wrapping in a single parseOrFail
  • the EPUB manifest predicate and the CLI command class moved into their own named units

Most of commit 3's diff is the one-time ktfmt sweep. Happy to split that into a formatting-only commit if it makes review easier.

Verification

./gradlew check passes: JVM tests, Android host tests, CLI build, detekt, ktfmtCheck and the Konsist rules.

🤖 Generated with Claude Code

lemcoder and others added 3 commits August 11, 2026 01:29
The factory functions and exception base class still carried the name of the
upstream project this was ported from, which no longer matches anything in the
library.

- MarkItDown() -> MikroMarkdown() (JVM), MarkItDown(context) -> MikroMarkdown(context)
- MarkItDownException -> MikroMarkdownException
- CLI command class and its help name now read mikromarkdown
- README updated; the remaining MarkItDown mention is the upstream project link

Breaking for 0.1.0 consumers, with no deprecated aliases, matching the
convert -> parse change.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The benchmark compares our Markdown against anydoc, and its parsers are the
reference for the document-model architecture. Pinning it next to the existing
markitdown submodule keeps both references at a known revision.

Pinned at v0.1.7.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Three guards, wired into `check` and a CI lint job:

- ktfmt (kotlinlang style, 120 columns) formats every source set. ktfmt-gradle
  only derives tasks for the common and JVM ones, so the library registers
  matching tasks for androidMain/androidHostTest/androidDeviceTest, which hold
  half the converters and would otherwise go unchecked.
- detekt on top of its default config, with overrides in config/detekt/detekt.yml
  limited to rules that clash with deliberate choices here (broad catches in
  converters, PascalCase factory functions).
- Konsist encodes the pipeline's boundaries as tests: the model depends on
  nothing and stays platform-free, converters never import the renderer, and
  Markdown syntax only appears under render/. Each rule was verified to fail
  against a deliberate violation.

Fixing detekt's findings turned up a real bug: the escaping pass tracked
line-start state in a mutable flag that was already false by the time it
reached an ordered-list delimiter, so both the digit and delimiter branches were
dead and "1. item" in running text could still open a list. Escaping is now
position-based, and honours leading indentation.

Other cleanups it prompted:

- PPTX chart extraction collapsed from eight near-identical loops to five
  toSeries() helpers, since bar/bar3D, line/line3D and area/area3D each share a
  generated series type
- MikroMarkdown.parse selects the converter first, with failure wrapping in a
  single parseOrFail helper
- the EPUB manifest predicate and the CLI command class each moved out into
  their own named unit

The bulk of the diff is the one-time ktfmt sweep.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@lemcoder
lemcoder merged commit fe36d6a into main Aug 11, 2026
3 checks passed
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.

1 participant