Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[submodule "markitdown"]
path = markitdown
path = third-party/markitdown
url = https://github.com/microsoft/markitdown
[submodule "anydoc"]
path = anydoc
path = third-party/anydoc
url = https://github.com/firecrawl/anydoc.git
23 changes: 18 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ bytes ──► MimeDetector ──► DocumentConverter.parse ──► Documen
```

Converters contain no Markdown syntax, so escaping, table shaping, list indentation and spacing are
fixed once for all formats. The model is public: `mid.parse(path)` returns the `Document`, and
fixed once for all formats. JVM and Android share one `jvmShared` source set, so a converter exists
once rather than per target; only PDF extraction and MIME detection are platform-specific. The model is public: `mid.parse(path)` returns the `Document`, and
`ConversionResult.document` exposes it alongside the rendered Markdown.

```kotlin
Expand Down Expand Up @@ -134,11 +135,23 @@ Both extend `MikroMarkdownException`.
|---|---|---|
| [ktfmt](https://github.com/facebook/ktfmt) | `./gradlew ktfmtFormat` / `ktfmtCheck` | formatting (kotlinlang style, 120 columns) |
| [detekt](https://detekt.dev) | `./gradlew detekt` | static analysis; overrides in `config/detekt/detekt.yml` |
| [Konsist](https://docs.konsist.lemonappdev.com) | `./gradlew :library:jvmTest --tests '*ArchitectureTest*'` | pipeline boundaries |
| [Konsist](https://docs.konsist.lemonappdev.com) | `./gradlew :library:jvmTest --tests '*ArchitectureTest*'` | pipeline boundaries and encapsulation |

`./gradlew check` runs all three. The Konsist rules encode the architecture: the model depends on
nothing, converters never import the renderer, and Markdown syntax appears only under `render/` —
so a converter cannot quietly start building Markdown strings again.
`./gradlew check` runs all three. The library also builds in Kotlin's
[explicit API mode](https://kotlinlang.org/docs/whatsnew14.html#explicit-api-mode-for-library-authors),
so every exported declaration states its visibility and return type.

The Konsist rules in `ArchitectureTest` encode the architecture, and each one is verified to fail
against a deliberate violation:

*Layering* — the model depends on nothing and stays free of `java.*`/`android.*`; converters never
import the renderer or each other; Markdown syntax appears only under `render/`.

*Encapsulation* — helpers under `utils` are never public, the model exposes no mutable state, and
every `DocumentConverter` is named `*Converter` and lives in `converters`.

*Hygiene* — no wildcard imports, no printing from library code, and no source file duplicated
between source sets (the drift that the `jvmShared` set removed).

ktfmt-gradle only derives tasks for the common and JVM source sets, so `library/build.gradle.kts`
registers matching tasks for the Android ones.
Expand Down
37 changes: 24 additions & 13 deletions library/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ group = "io.github.lemcoder"
version = "0.1.0"

kotlin {
// Public API must be spelled out: visibility and return types, no accidental exports.
explicitApi()

jvm {
compilerOptions { jvmTarget = JvmTarget.JVM_21 }
testRuns["test"].executionTask.configure { useJUnitPlatform() }
Expand All @@ -30,21 +33,29 @@ kotlin {
sourceSets {
commonMain.dependencies { implementation(libs.kotlinx.io.core) }

jvmMain.dependencies {
implementation(libs.jsoup)
implementation(libs.jackson.kotlin)
implementation(libs.commons.csv)
implementation(libs.poi.ooxml)
implementation(libs.tika.core)
implementation(libs.pdfbox)
// JVM and Android run the same parsers on the same libraries; only PDF and MIME
// detection differ. Converters live here once instead of being copied per target.
val jvmShared by creating {
dependsOn(commonMain.get())
dependencies {
implementation(libs.jsoup)
implementation(libs.jackson.kotlin)
implementation(libs.commons.csv)
implementation(libs.poi.ooxml)
}
}

jvmMain {
dependsOn(jvmShared)
dependencies {
implementation(libs.tika.core)
implementation(libs.pdfbox)
}
}

androidMain.dependencies {
implementation(libs.jsoup)
implementation(libs.jackson.kotlin)
implementation(libs.commons.csv)
implementation(libs.poi.ooxml)
implementation(libs.pdfbox.android)
androidMain {
dependsOn(jvmShared)
dependencies { implementation(libs.pdfbox.android) }
}

commonTest.dependencies {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import java.io.File
*
* PDF support needs a [Context]: pdfbox-android loads its resources from the app's assets.
*/
fun MikroMarkdown(context: Context? = null): MikroMarkdown =
public fun MikroMarkdown(context: Context? = null): MikroMarkdown =
MikroMarkdown(AndroidMimeDetector).apply {
register(MarkdownPassthroughConverter())
register(HtmlConverter())
Expand All @@ -39,4 +39,4 @@ fun MikroMarkdown(context: Context? = null): MikroMarkdown =
register(PlainTextConverter(), priority = 10.0)
}

fun MikroMarkdown.convert(file: File): ConversionResult = convert(file.absolutePath)
public fun MikroMarkdown.convert(file: File): ConversionResult = convert(file.absolutePath)

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import io.github.lemcoder.mikromarkdown.StreamInfo
import io.github.lemcoder.mikromarkdown.model.Document
import io.github.lemcoder.mikromarkdown.utils.plainTextBlocks

class PdfConverter : DocumentConverter {
public class PdfConverter : DocumentConverter {
override fun accepts(bytes: ByteArray, info: StreamInfo): Boolean {
return info.extension == "pdf" || info.mimetype == "application/pdf"
}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import io.github.lemcoder.mikromarkdown.MimeDetector
import io.github.lemcoder.mikromarkdown.StreamInfo
import java.io.File

object AndroidMimeDetector : MimeDetector {
internal object AndroidMimeDetector : MimeDetector {
override fun detect(path: String): StreamInfo {
val file = File(path)
val extension = file.extension.lowercase().ifEmpty { null }
Expand Down
Loading
Loading