diff --git a/CLAUDE.md b/CLAUDE.md index 3a602fa..575bb56 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -4,7 +4,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co ## Build / test commands -- `./gradlew build` — compiles, runs ktlint, and runs the test suite for both modules. +- `./gradlew build` — compiles, runs ktlint, and runs the test suite for every module. - `./gradlew test` — runs tests only. The root `:test` task transitively triggers the recorder's GraalVM `nativeCompile` and a `publishToMavenLocal` (see *Test fixture wiring*), so a clean checkout's first run takes several minutes for the native image build. - `./gradlew test --tests "ServiceAndMethodWrapperTests"` — single test class. (`-i` for info logging.) - `./gradlew ktlintCheck` / `./gradlew ktlintFormat` — lint / autoformat. ktlint excludes everything under `build/` (workaround for the plugin not honoring generated-source exclusions). **Always run `ktlintFormat` after editing Kotlin source** so the next CI run isn't blocked on a trivial formatting failure. @@ -17,10 +17,11 @@ The `pr.yaml` workflow just calls `build.yaml` (which runs `./gradlew build` aft ## Module layout -The repo is a multi-project Gradle build with two modules: +The repo is a multi-project Gradle build with three modules: - **Root project `:protoc-utils`** (`src/main/kotlin/com/engine/protoc/util/…`) — the published Kotlin library. Pure JVM, no native code. - **Subproject `:protoc-utils-recorder`** (`recorder/`) — a tiny GraalVM-native protoc plugin (single `Main.kt`) that copies stdin to a file named `code-generator-request.binpb`. It is shipped as multi-platform native binaries to Maven Central, **not** as a JVM jar. +- **Subproject `:protoc-utils-markdown`** (`markdown/`) — a JVM library, depending on the root library and commonmark-java, that resolves proto reference links in doc comments and converts comment Markdown to plain text. Kept separate so the core library stays free of the commonmark dependency. `settings.gradle.kts` walks the tree and includes every directory containing a `build.gradle.kts` (skipping `build`, `buildSrc`, `tmp`, `scratch`, dotfile dirs, and dirs containing `.gradle_ignore`). Subproject names are derived as `:-`, so the directory `recorder/` becomes `:protoc-utils-recorder`. To add a subproject, just create a directory with a `build.gradle.kts` — no manual `include(…)` needed. diff --git a/README.md b/README.md index 5504c35..d624b09 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,8 @@ dependencies { The companion `protoc-utils-recorder` plugin is published as multi-platform native binaries under the same group; see [`recorder/README.md`](recorder/README.md) for how to consume those. +The companion `protoc-utils-markdown` library resolves proto reference links (`[Widget]`, `[Service.Rpc]`) in doc comments and converts comment Markdown to plain text; see [`markdown/README.md`](markdown/README.md). + --- ## Why this exists @@ -79,6 +81,7 @@ val comment: String? = nameElement?.location?.leadingComments?.cleaned | `cleaned` | The comment text with fencing characters (`//`, `/*`, `*`, etc.) stripped | The `cleaned` form is what you almost always want when generating documentation or OpenAPI descriptions. +For ordinary `//` comments only the common leading whitespace is removed, so Markdown in the comment (a leading code span or reference link, list markers, code fences, tables) is preserved. ### Extension options diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 7fe799d..41bbcb5 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -2,6 +2,8 @@ kotest = "6.1.4" kotlin = "2.4.20" protobuf = "4.34.1" +commonmark = "0.28.0" +slf4j = "2.0.17" # plugin versions google-osdetector-plugin = "1.7.3" @@ -21,6 +23,8 @@ cyclonedx = { id = "org.cyclonedx.bom", version.ref = "cyclonedx" } license-report = { id = "com.github.jk1.dependency-license-report", version.ref = "jk1-dependency-license-report" } [libraries] +commonmark = { group = "org.commonmark", name = "commonmark", version.ref = "commonmark" } +slf4j-api = { group = "org.slf4j", name = "slf4j-api", version.ref = "slf4j" } protobuf-java = { group = "com.google.protobuf", name = "protobuf-java", version.ref = "protobuf" } # test dependencies diff --git a/gradle/license/allowed-licenses.json b/gradle/license/allowed-licenses.json index dcde8a7..9ca893c 100644 --- a/gradle/license/allowed-licenses.json +++ b/gradle/license/allowed-licenses.json @@ -2,6 +2,8 @@ "allowedLicenses": [ { "moduleLicense": "Apache License, Version 2.0" }, { "moduleLicense": "MIT License" }, - { "moduleLicense": "The 3-Clause BSD License" } + { "moduleLicense": "The 2-Clause BSD License" }, + { "moduleLicense": "The 3-Clause BSD License" }, + { "moduleName": "org.slf4j:slf4j-api" } ] } diff --git a/markdown/README.md b/markdown/README.md new file mode 100644 index 0000000..d5152fe --- /dev/null +++ b/markdown/README.md @@ -0,0 +1,37 @@ +# protoc-utils-markdown + +CommonMark helpers shared by Engine's protoc plugins for handling proto doc comments. + +```kotlin +implementation("com.engine:protoc-utils-markdown:VERSION") +``` + +## Reference links + +Doc comments refer to other proto elements with CommonMark reference-link syntax: `[Widget]`, `[acme.v1.Widget]`, `[Widget.name]`, `[Status.STATUS_ACTIVE]`, `[WidgetService.GetWidget]`, or the full form `[display text][Widget]`. + +- `ReferenceIndex` indexes every message, field, enum, enum value, service, and RPC in a set of files. + A plugin-supplied function maps each `ReferenceElement` to a target `T` (an href, a rendering decision, …); returning `null` leaves the element unindexed. + Bare names resolve against the members of the comment's own descriptor before global short names, so a comment on `message Widget` can write `[name]`. +- `ReferenceLinkProcessor` is a commonmark-java `LinkProcessor` that rewrites resolved references as links (`ReferenceRendering.Link`) or code spans (`ReferenceRendering.Code`). + Inline links, images, code spans, and escaped brackets are left alone. + Labels in the `overrides` map (parsed from repeated `referenceLink=