feat: support mrkdwn descriptions on OptionObject (#1471) - #1645
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #1645 +/- ##
============================================
+ Coverage 72.74% 72.77% +0.03%
- Complexity 4546 4551 +5
============================================
Files 483 483
Lines 14456 14458 +2
Branches 1513 1513
============================================
+ Hits 10516 10522 +6
+ Misses 3042 3039 -3
+ Partials 898 897 -1
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. |
97d33f2 to
e5f142f
Compare
`OptionObject.description` was hard-typed to `PlainTextObject`, so a `mrkdwn` description on a radio-button or checkbox option was coerced to plain_text on deserialize, losing the markdown. The option-object docs state that radio buttons and checkboxes can use mrkdwn text objects for the description. Widen the field to `TextObject` (the same type already used for `OptionObject.text`), which routes deserialization through the existing polymorphic text-object factory so `mrkdwn` round-trips as a `MarkdownTextObject` and `plain_text` still returns a `PlainTextObject`. The Kotlin DSL gains a `markdownDescription(...)` overload alongside the existing plain_text `description(...)`. Source-compatible: all call sites pass plain_text and the getter's declared type only broadens. Ref: https://docs.slack.dev/reference/block-kit/composition-objects/option-object Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
e5f142f to
9b52084
Compare
Exercise markdownDescription() within the existing "Channel select and checkboxes" test rather than a standalone case, mirroring the Java-side fold into parseCheckboxes(). The first checkbox option now asserts the mrkdwn description path while the second keeps the plain_text path. Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
zimeg
left a comment
There was a problem hiding this comment.
🗣️ note: A few callouts on these changes that are worth consideration before merge I think!
| * A plain_text text object that defines a line of descriptive text shown below | ||
| * the text field beside a single selectable item in a select menu, multi-select | ||
| * menu, checkbox group, radio button group, or overflow menu. Checkbox group and | ||
| * radio button group items can also use mrkdwn formatting. | ||
| * Maximum length for the text within this field is 75 characters. | ||
| */ | ||
| private PlainTextObject description; | ||
| private TextObject description; |
There was a problem hiding this comment.
🤓 note: This matches reference and becomes more general to support API requests with validation left to blocks itself.
🔗 https://docs.slack.dev/reference/block-kit/composition-objects/option-object
| " \"description\": {\n" + | ||
| " \"type\": \"mrkdwn\",\n" + | ||
| " \"text\": \"*this is mrkdwn text*\"\n" + | ||
| " },\n" + |
There was a problem hiding this comment.
👽 note: This existed in tests before these change but wasn't checked below.
| fun markdownDescription(text: String, verbatim: Boolean? = null) { | ||
| description = MarkdownTextObject(text, verbatim) | ||
| } |
There was a problem hiding this comment.
👁️🗨️ note: This pattern is similar to how the text object is supported although I understand this isn't identical for the current description object:
- plainText
- markdownText
There was a problem hiding this comment.
☁️ note: Calling this out here because I'm uncertain if we're using the best pattern without introducing a break:
- description
- markdownDescription
| options { | ||
| option { | ||
| description("I accept the terms and conditions") | ||
| markdownDescription("*I accept the terms and conditions*") | ||
| value("tac-accept") | ||
| } | ||
| option { | ||
| description("I have read the privacy policy") | ||
| value("privacy-policy-read") | ||
| } | ||
| } |
There was a problem hiding this comment.
🧪 note: The existing test suite was modified to check both cases alongside one another.
…Object field The sample-JSON generator (SampleObjects) reflectively instantiates null model fields via a no-arg constructor. Widening OptionObject.description from PlainTextObject to the abstract TextObject broke this for the radio-button option fixtures that set text but left description null, crashing MethodsResponseDumpTest's static init with InstantiationException. Supply concrete descriptions in those builders (as the generator already does elsewhere), giving the mrkdwn option a mrkdwn description. Regenerates the views.* API samples to show a mrkdwn option description. Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
zimeg
left a comment
There was a problem hiding this comment.
🪐 A comment of test changes for stable CI.
| initProperties(OptionObject.builder().text(initProperties(PlainTextObject.builder().build())).description(initProperties(PlainTextObject.builder().build())).build()), | ||
| initProperties(OptionObject.builder().text(initProperties(MarkdownTextObject.builder().build())).description(initProperties(MarkdownTextObject.builder().build())).build()) | ||
| )) | ||
| .initialOption(initProperties(OptionObject.builder().text(initProperties(PlainTextObject.builder().build())).build())) | ||
| .initialOption(initProperties(OptionObject.builder().text(initProperties(PlainTextObject.builder().build())).description(initProperties(PlainTextObject.builder().build())).build())) |
There was a problem hiding this comment.
🔭 note: These description values are added to tests so JSON reflections don't error when deciding between plain_text and mrkdwn values.
There was a problem hiding this comment.
👾 note: This is a test change and wouldn't require similar from developers as I understand.
Summary
OptionObject.descriptionwas hard-typed toPlainTextObject, so amrkdwndescription on a radio-button or checkbox option was coerced to plain_text on deserialize — the markdown was lost. The option-object docs state that radio buttons and checkboxes can usemrkdwntext objects for the description.Fixes #1471.
What changed
OptionObject.description:PlainTextObject→TextObject(the same type already used forOptionObject.text). This routes deserialization through the existing polymorphic text-object factory, so amrkdwndescription round-trips as aMarkdownTextObjectand aplain_textdescription still returns aPlainTextObject.OptionObjectBuilder): added amarkdownDescription(text, verbatim)overload alongside the existing plain_textdescription(text, emoji).BlockKitTest#parseCheckboxes— now asserts amrkdwnoption description deserializes toMarkdownTextObjectwhile aplain_textoption staysPlainTextObject.ActionsBlockTest#Channel select and checkboxes`` (Kotlin) — the first checkbox option now serializes viamarkdownDescription()to a `mrkdwn` object, the second keeps the `plain_text` path.Compatibility
Source-compatible: existing call sites all pass plain_text, and the getter's declared type only broadens (
PlainTextObject→ its supertypeTextObject).Testing
slack-api-modelBlockKitTest: 55/55 greenslack-api-model-kotlin-extension: 58/58 green🤖 Generated with Claude Code