slack-markdown-parser 2.3.2__tar.gz → 2.4.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (18) hide show
  1. {slack_markdown_parser-2.3.2 → slack_markdown_parser-2.4.1}/CHANGELOG.md +17 -0
  2. {slack_markdown_parser-2.3.2/slack_markdown_parser.egg-info → slack_markdown_parser-2.4.1}/PKG-INFO +19 -12
  3. {slack_markdown_parser-2.3.2 → slack_markdown_parser-2.4.1}/README-ja.md +17 -10
  4. {slack_markdown_parser-2.3.2 → slack_markdown_parser-2.4.1}/README.md +17 -10
  5. {slack_markdown_parser-2.3.2 → slack_markdown_parser-2.4.1}/docs/spec-ja.md +22 -8
  6. {slack_markdown_parser-2.3.2 → slack_markdown_parser-2.4.1}/docs/spec.md +22 -8
  7. {slack_markdown_parser-2.3.2 → slack_markdown_parser-2.4.1}/pyproject.toml +2 -2
  8. {slack_markdown_parser-2.3.2 → slack_markdown_parser-2.4.1}/slack_markdown_parser/__init__.py +1 -1
  9. {slack_markdown_parser-2.3.2 → slack_markdown_parser-2.4.1}/slack_markdown_parser/converter.py +573 -28
  10. {slack_markdown_parser-2.3.2 → slack_markdown_parser-2.4.1/slack_markdown_parser.egg-info}/PKG-INFO +19 -12
  11. {slack_markdown_parser-2.3.2 → slack_markdown_parser-2.4.1}/LICENSE +0 -0
  12. {slack_markdown_parser-2.3.2 → slack_markdown_parser-2.4.1}/MANIFEST.in +0 -0
  13. {slack_markdown_parser-2.3.2 → slack_markdown_parser-2.4.1}/setup.cfg +0 -0
  14. {slack_markdown_parser-2.3.2 → slack_markdown_parser-2.4.1}/slack_markdown_parser/py.typed +0 -0
  15. {slack_markdown_parser-2.3.2 → slack_markdown_parser-2.4.1}/slack_markdown_parser.egg-info/SOURCES.txt +0 -0
  16. {slack_markdown_parser-2.3.2 → slack_markdown_parser-2.4.1}/slack_markdown_parser.egg-info/dependency_links.txt +0 -0
  17. {slack_markdown_parser-2.3.2 → slack_markdown_parser-2.4.1}/slack_markdown_parser.egg-info/requires.txt +0 -0
  18. {slack_markdown_parser-2.3.2 → slack_markdown_parser-2.4.1}/slack_markdown_parser.egg-info/top_level.txt +0 -0
@@ -6,6 +6,23 @@ The format is based on Keep a Changelog, and the project follows Semantic Versio
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [2.4.1] - 2026-05-29
10
+
11
+ ### Fixed
12
+
13
+ - Stopped punctuation-terminated emphasis from leaking its literal markers (`**`, `*`, `~~`) in `markdown` blocks. A ZWSP placed just outside a closing marker broke Slack's CommonMark right-flanking check whenever the last inner character was punctuation (e.g. `- **項目:**` at a line end, or `**70.9%→83.0%**、` before CJK punctuation), exposing the raw markers. Chunk boundaries are now treated as safe so no stray ZWSP is appended at line/text ends, and when a marker sits against inner punctuation a ZWSP is inserted just inside it so the run flanks via rule 2a regardless of the following character — including before CJK text and CJK punctuation that Slack does not accept as a flanking neighbor.
14
+ - Stopped preserving English-like punctuation-flanked emphasis raw when its tight neighbor is non-ASCII punctuation (e.g. `**APIYI (apiyi.com)**。` or `Score **70.9%→83.0%**、`). Slack only accepts ASCII punctuation/whitespace as a flanking neighbor, so these now receive the inner ZWSP protection instead of being emitted unchanged.
15
+
16
+ ## [2.4.0] - 2026-05-14
17
+
18
+ ### Added
19
+
20
+ - Added automatic richer Block Kit output for unambiguous standalone Markdown constructs, including image blocks, dividers, fenced code, simple quotes, and simple lists, while leaving Markdown headings in `markdown` blocks so Slack can preserve heading levels.
21
+
22
+ ### Documentation
23
+
24
+ - Documented the Slack mobile `markdown` block limitation where list-item continuation lines are re-prefixed with the list marker, and linked the tracking issue so users can check upstream status instead of expecting a parser-side workaround.
25
+
9
26
  ## [2.3.2] - 2026-04-17
10
27
 
11
28
  ### Fixed
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: slack-markdown-parser
3
- Version: 2.3.2
4
- Summary: Convert LLM Markdown into Slack Block Kit markdown/table messages
3
+ Version: 2.4.1
4
+ Summary: Convert LLM Markdown into Slack Block Kit messages
5
5
  Author: darkgaldragon
6
6
  License-Expression: MIT
7
7
  Project-URL: Homepage, https://github.com/darkgaldragon/slack-markdown-parser
@@ -30,7 +30,8 @@ Dynamic: license-file
30
30
 
31
31
  # slack-markdown-parser
32
32
 
33
- `slack-markdown-parser` is a Python library that converts ordinary Markdown generated by LLMs into Slack Block Kit messages built from `markdown` and `table` blocks.
33
+ `slack-markdown-parser` is a Python library that converts general Markdown generated by LLMs into Slack Block Kit messages built from `markdown`, `table`, and selected richer blocks so the output renders cleanly in Slack.
34
+ Basic headings and text formatting stay in `markdown` blocks, while constructs that benefit from dedicated Slack rendering, such as tables and simple standalone lists, are converted into native Block Kit blocks to produce a ChatGPT-like reading experience.
34
35
 
35
36
  ## Why this library exists
36
37
 
@@ -42,23 +43,25 @@ Many Slack AI bots have traditionally converted model output into Slack-specific
42
43
 
43
44
  ## Design approach
44
45
 
45
- This library uses Slack Block Kit `markdown` blocks for regular Markdown and `table` blocks for tables.
46
+ This library combines Slack Block Kit's newer `markdown` block, `table` blocks, and richer block conversion for Markdown patterns that can be mapped safely.
46
47
 
47
48
  | Problem | Approach |
48
49
  |---|---|
49
- | Extra conversion work | Send ordinary Markdown through Slack `markdown` blocks without rewriting it into `mrkdwn`. |
50
- | Formatting instability | Prefer zero-width spaces (`U+200B`) around formatting markers, and only add visible spaces in a few language-specific cases where Slack still renders Japanese, Chinese, or Korean text incorrectly. |
51
- | No table syntax in `mrkdwn` | Detect Markdown tables and convert them into Slack `table` blocks, including repair of common LLM-generated table inconsistencies. |
50
+ | Extra conversion work | Slack `markdown` blocks can render a useful subset of Markdown other than tables, so LLM output can usually be sent with minimal rewriting instead of being converted into `mrkdwn`. |
51
+ | Formatting instability | Slack's `markdown` parser is not complete, so this library adds zero-width spaces (`U+200B`) around formatting-marker boundaries and uses visible spaces only for a few Japanese, Chinese, and Korean cases where that is still needed. This keeps emphasis stable across English and dense CJK text. |
52
+ | No table syntax in `mrkdwn` | Detect Markdown tables and render them as Slack `table` blocks, while also repairing common LLM-generated table issues such as missing pipes. |
53
+ | Rich LLM output | Convert standalone images, dividers, simple quotes, code fences, and simple lists into native Block Kit blocks where the Markdown structure is unambiguous. |
52
54
 
53
- The goal is natural rendering on Slack, not full CommonMark or HTML fidelity.
55
+ The goal is natural rendering on Slack without exposing raw formatting markers, not full CommonMark or HTML fidelity.
54
56
  If Slack itself does not support a construct in `markdown` blocks, this library prefers safe plain-text rendering or explicit `table` blocks over aggressive rewrites into old `mrkdwn`.
55
57
 
56
58
  ## Features
57
59
 
58
- - Convert ordinary Markdown into Slack `markdown` blocks
60
+ - Convert general Markdown into Slack `markdown` blocks
59
61
  - Convert Markdown tables into Slack `table` blocks
62
+ - Promote safe standalone Markdown constructs into richer Block Kit blocks: `image`, `divider`, and `rich_text`
60
63
  - Repair common LLM table issues such as missing outer pipes, missing separator rows, mismatched column counts, and empty cells
61
- - Split output into multiple Slack messages when needed to satisfy Slack's "one table per message" constraint
64
+ - Split output into multiple Slack messages when needed to satisfy Slack's "one table per message" and per-message block-count constraints
62
65
  - Remove ANSI/control characters and neutralize invalid Slack angle-bracket tokens before block generation
63
66
  - Add zero-width spaces around inline formatting markers to reduce rendering issues outside fenced code blocks, while preserving English-like punctuation-only boundaries that Slack already renders reliably
64
67
  - Add visible spaces for a small set of nested inline-code cases in dense Japanese, Chinese, and Korean text when zero-width spaces alone are not enough
@@ -73,7 +76,7 @@ The library is built around how Slack actually renders `markdown` and `table` bl
73
76
 
74
77
  Slack updated its [`markdown` block docs](https://docs.slack.dev/reference/block-kit/blocks/markdown-block/)
75
78
  and [changelog entry](https://docs.slack.dev/changelog/2026/03/06/block-kit-rich-text)
76
- on March 6, 2026 to describe broader support for headings, dividers, task lists,
79
+ on March 6, 2026 as it started supporting broader Markdown features such as headings, dividers, task lists,
77
80
  native Markdown tables, and syntax-highlighted code blocks. In the Slack Web
78
81
  workspace used for this project's April 8, 2026 validation, raw `markdown`
79
82
  blocks rendered those constructs natively, including distinct heading levels
@@ -90,6 +93,7 @@ Reliable in current Slack rendering:
90
93
  - Bare URLs, `<https://...>` style links, Markdown links, reference-style links, and mailto links
91
94
  - Bullet lists, ordered lists, task lists, and simple blockquotes
92
95
  - Explicit Slack `table` blocks generated from Markdown tables
96
+ - Explicit richer blocks generated from unambiguous Markdown, such as standalone images, code fences, simple lists, and simple quotes
93
97
  - In environments where Slack has enabled the newer renderer, raw Markdown headings, dividers, and tables inside `markdown` blocks
94
98
 
95
99
  Known Slack-side limitations:
@@ -100,19 +104,22 @@ Known Slack-side limitations:
100
104
  - Raw Markdown tables inside `markdown` blocks now render in some newer Slack environments, but explicit Slack `table` blocks remain the reliable option across workspaces and delivery paths
101
105
  - Markdown image syntax does not become an embedded image in `markdown` blocks
102
106
  - Math, raw HTML, HTML comments, `<details>`, admonition syntax, and Mermaid are rendered as plain text or code, not as rich features
107
+ - Some newly documented Block Kit block types can be unavailable on a given `chat.postMessage` path; this library emits only a conservative subset of richer block types that has been validated through real Slack posting checks.
108
+ - The Slack **mobile** app re-prefixes the list marker onto each continuation line of a list item inside `markdown` blocks (e.g. `1. Heading` followed by an indented paragraph shows as `1. Heading` / `1.continuation` on mobile, while Slack desktop and Slack Web render the same payload correctly). This is a Slack client-side rendering behavior, not a parser bug. Tracking: [issue #45](https://github.com/darkgaldragon/slack-markdown-parser/issues/45).
103
109
 
104
110
  What this library compensates for:
105
111
 
106
112
  - Normalizes underscore emphasis (`_..._`, `__...__`) into Slack-friendly asterisk emphasis
107
113
  - Wraps bare URLs into Slack-friendly `<https://...>` link form before sending `markdown` blocks
108
114
  - Repairs malformed LLM-generated tables before converting them into Slack `table` blocks
115
+ - Converts unambiguous standalone Markdown constructs into native Block Kit blocks when that is safer than relying on raw `markdown` rendering
109
116
  - Keeps table-like rows inside fenced code blocks out of table normalization
110
117
  - Optionally turns internal blank lines into placeholder lines that keep paragraphs visibly separated in Slack `markdown` blocks
111
118
  - Neutralizes invalid Slack angle-bracket tokens such as raw HTML-like tags
112
119
 
113
120
  ## Requirements
114
121
 
115
- - Your Slack integration must support Block Kit payloads with `markdown` and `table` blocks.
122
+ - Your Slack integration must support Block Kit payloads with `markdown`, `table`, and the richer blocks emitted by this library (`rich_text`, `image`, and `divider`).
116
123
  - This library does not help when your delivery path only accepts plain `text` or `mrkdwn` strings.
117
124
 
118
125
  ## Installation
@@ -1,6 +1,7 @@
1
1
  # slack-markdown-parser
2
2
 
3
- LLM が生成するふつうの Markdown を、Slack Block Kit(`markdown` + `table` ブロック)に変換する Python ライブラリです。
3
+ LLM が生成する一般的な Markdown を、Slackで綺麗にレンダリングできるように、Slack Block Kit(`markdown` / `table` / 一部のリッチブロック)に変換する Python ライブラリです。
4
+ 基本的な見出しや文字修飾は `markdown` ブロックで対応し、さらにテーブルや単純な単独リストなど、Slack ネイティブの表示が有効な記法は専用の Block Kit ブロックに変換することで、ChatGPT のような読み心地に近づけています。
4
5
 
5
6
  ## 背景
6
7
 
@@ -12,23 +13,25 @@ Slack で AI BOT を動かすとき、従来は Slack 独自の `mrkdwn` 形式
12
13
 
13
14
  ## 設計方針
14
15
 
15
- Slack Block Kit `markdown` ブロックと `table` ブロックを使って、上の課題に対応します。
16
+ Slack Block Kit の比較的あたらしい `markdown` ブロック、`table` ブロック、そして安全に判定できる Markdown だけを対象にしたリッチブロック変換で、上の課題に対応できるようにしました。
16
17
 
17
18
  | 課題 | 解決手段 |
18
19
  |---|---|
19
- | 変換の手間 | `markdown` ブロックがふつうの Markdown を受け取れるので、LLM 出力を `mrkdwn` に書き換えずに使う |
20
- | 装飾の崩れ | 基本はゼロ幅スペース(`U+200B`)で装飾記号の境界を補い、それでも崩れる一部の日本語・中国語・韓国語のケースだけ可視スペースを使う |
21
- | テーブル非対応 | Markdown テーブルを見つけて `table` ブロックに変換し、LLM が作りがちな表の崩れも自動で補う |
20
+ | 変換の手間 | `markdown` ブロックがテーブル以外のある程度の Markdown をレンダリングできるので、LLM 出力を `mrkdwn` に書き換えずになるべくそのまま使う |
21
+ | 装飾の崩れ | `markdown` ブロックのMarkdownパーサーが完全ではないため、文字修飾が反映されない問題に対して、ゼロ幅スペース(`U+200B`)で装飾記号の境界を補い、それでも崩れる一部の日本語・中国語・韓国語のケースだけ可視スペースを使うことで、英語だけでなく、日本語、中国語、韓国語のレンダリングが崩れやすい言語についても、安定して装飾記号が反映される |
22
+ | テーブル非対応 | Markdown テーブルを検知して `table` ブロックに変換してレンダリングすると同時に、LLM が起こしがちな表の崩れ(パイプ不足等)も自動で補う |
23
+ | リッチなLLM出力 | 単独画像、水平線、単純な引用、コードフェンス、単純なリストを、意味が明確な範囲で Slack ネイティブの Block Kit ブロックへ変換する |
22
24
 
23
- このライブラリの目標は、CommonMark や HTML を完全再現することではなく、Slack 上で自然に読める表示を作ることです。
25
+ このライブラリの目標は、CommonMark や HTML を完全再現することではなく、Slack 上で修飾記号を露出させず、自然に読める表示を作ることです。
24
26
  Slack の `markdown` ブロック自体が対応していない構文は、古い `mrkdwn` へ無理に書き換えるより、安全なプレーンテキスト表示や `table` ブロック化を優先します。
25
27
 
26
28
  ## 主な機能
27
29
 
28
- - ふつうの Markdown テキストを `markdown` ブロックに変換
30
+ - 一般的な Markdown テキストを `markdown` ブロックに変換
29
31
  - Markdown テーブルを `table` ブロックに変換
32
+ - 安全に判定できる単独 Markdown 構文を `image` / `divider` / `rich_text` ブロックに変換
30
33
  - LLM が生成する表で起こりやすい崩れ(外枠パイプ不足、区切り行不足、列数不一致、空セル)を補正
31
- - テーブルごとにメッセージを自動分割し、Slack の「1メッセージ1テーブル」制約に対応
34
+ - 必要に応じてメッセージを自動分割し、Slack の「1メッセージ1テーブル」制約とメッセージあたりのブロック数制限に対応
32
35
  - ANSI escape / 制御文字を除去し、不正な Slack 角括弧トークンを無害化
33
36
  - フェンスドコードブロック外では、装飾記号の前後にゼロ幅スペースを入れて表示崩れを減らす
34
37
  - 日本語・中国語・韓国語の詰まった文で、インラインコードを含む装飾が崩れる一部のケースでは可視スペースを補って安定化
@@ -41,7 +44,7 @@ Slack の `markdown` ブロック自体が対応していない構文は、古
41
44
 
42
45
  本ライブラリは、Slack の `markdown` / `table` ブロックが実際にどう見えるかを前提に設計しています。
43
46
 
44
- Slack は 2026-03-06 に `markdown` ブロックの公式ドキュメントを更新し、見出し、水平線、タスクリスト、表、言語付きコードブロックなど、これまでより多くの Markdown 記法を案内し始めました。ただし、これらの機能は環境ごとに順番に有効化されるとも書かれています。つまり、ワークスペースやクライアントによって見え方が違う可能性があります。
47
+ Slack は 2026-03-06 に `markdown` ブロックの公式ドキュメントを更新し、見出し、水平線、タスクリスト、表、言語付きコードブロックなど、これまでより多くの Markdown 記法をサポートし始めました。ただし、これらの機能は環境ごとに順番に有効化されるとも書かれています。つまり、ワークスペースやクライアントによって見え方が違う可能性があります。
45
48
 
46
49
  現在の Slack で比較的安定して表示されるもの:
47
50
 
@@ -49,6 +52,7 @@ Slack は 2026-03-06 に `markdown` ブロックの公式ドキュメントを
49
52
  - bare URL, `<https://...>` 形式リンク, Markdown リンク, 参照リンク, mailto リンク
50
53
  - 箇条書き, 番号付きリスト, タスクリスト, 単純な引用
51
54
  - Markdown テーブルを変換した明示的な Slack `table` ブロック
55
+ - 単独画像、コードフェンス、単純なリスト、単純な引用から生成したリッチブロック
52
56
  - Slack 側で新しい Markdown 表示が有効な環境では、`markdown` ブロック内の見出し・水平線・表
53
57
 
54
58
  Slack 側の制約として残るもの:
@@ -59,19 +63,22 @@ Slack 側の制約として残るもの:
59
63
  - `markdown` ブロック内の生 Markdown テーブルは一部環境では表示されるが、安定性では明示的な Slack `table` ブロックの方が上
60
64
  - Markdown 画像記法は `markdown` ブロック内では埋め込み画像にならない
61
65
  - 数式, 生 HTML, HTML comment, `<details>`, admonition 記法, Mermaid は特別な表示にならず、テキストまたはコードとして出る
66
+ - 新しく公式記載された Block Kit ブロックでも、利用する `chat.postMessage` 経路では未対応の場合があるため、このライブラリは実際の Slack 送信で確認した保守的なリッチブロックだけを出力する
67
+ - Slack **モバイル**アプリは、`markdown` ブロック内のリスト項目に属する継続行(CommonMark で同じリスト項目に紐づくインデントされた段落)の先頭に、リストマーカーを再付加してしまう。例: `1. 見出し` の次にインデントされた継続段落を置くと、モバイルでは `1. 見出し` と `1.継続行...` のように番号が重複して表示される。Slack デスクトップ/Web は同じペイロードを正しく描画する。これはパーサー側の不具合ではなく Slack クライアントのレンダリング挙動。追跡: [issue #45](https://github.com/darkgaldragon/slack-markdown-parser/issues/45)。
62
68
 
63
69
  このライブラリが吸収するもの:
64
70
 
65
71
  - underscore 装飾 (`_..._`, `__...__`) を Slack 互換の asterisk 装飾へ正規化
66
72
  - bare URL を Slack の `<https://...>` 形式にそろえる
67
73
  - 崩れた Markdown テーブルを補って Slack `table` ブロックへ変換
74
+ - 意味が明確な単独 Markdown 構文を、raw `markdown` 表示に頼らず Slack ネイティブの Block Kit ブロックへ変換
68
75
  - フェンスドコード内の table 風行をテーブル処理から除外
69
76
  - 必要に応じて、内部空行を補助用の行に置き換えて段落の区切りを見えやすくする
70
77
  - 生 HTML 風タグなど、Slack の特殊記法としては無効な `<...>` 形式を無害化
71
78
 
72
79
  ## 利用前提
73
80
 
74
- - Slack Block Kit の `blocks` で `markdown` / `table` ブロックを送信できる実装が必要です。
81
+ - Slack Block Kit の `blocks` で `markdown` / `table` と、このライブラリが出力するリッチブロック(`rich_text`, `image`, `divider`)を送信できる実装が必要です。
75
82
  - `text` / `mrkdwn` のみ送信できる経路では利用できません。
76
83
 
77
84
  ## インストール
@@ -1,6 +1,7 @@
1
1
  # slack-markdown-parser
2
2
 
3
- `slack-markdown-parser` is a Python library that converts ordinary Markdown generated by LLMs into Slack Block Kit messages built from `markdown` and `table` blocks.
3
+ `slack-markdown-parser` is a Python library that converts general Markdown generated by LLMs into Slack Block Kit messages built from `markdown`, `table`, and selected richer blocks so the output renders cleanly in Slack.
4
+ Basic headings and text formatting stay in `markdown` blocks, while constructs that benefit from dedicated Slack rendering, such as tables and simple standalone lists, are converted into native Block Kit blocks to produce a ChatGPT-like reading experience.
4
5
 
5
6
  ## Why this library exists
6
7
 
@@ -12,23 +13,25 @@ Many Slack AI bots have traditionally converted model output into Slack-specific
12
13
 
13
14
  ## Design approach
14
15
 
15
- This library uses Slack Block Kit `markdown` blocks for regular Markdown and `table` blocks for tables.
16
+ This library combines Slack Block Kit's newer `markdown` block, `table` blocks, and richer block conversion for Markdown patterns that can be mapped safely.
16
17
 
17
18
  | Problem | Approach |
18
19
  |---|---|
19
- | Extra conversion work | Send ordinary Markdown through Slack `markdown` blocks without rewriting it into `mrkdwn`. |
20
- | Formatting instability | Prefer zero-width spaces (`U+200B`) around formatting markers, and only add visible spaces in a few language-specific cases where Slack still renders Japanese, Chinese, or Korean text incorrectly. |
21
- | No table syntax in `mrkdwn` | Detect Markdown tables and convert them into Slack `table` blocks, including repair of common LLM-generated table inconsistencies. |
20
+ | Extra conversion work | Slack `markdown` blocks can render a useful subset of Markdown other than tables, so LLM output can usually be sent with minimal rewriting instead of being converted into `mrkdwn`. |
21
+ | Formatting instability | Slack's `markdown` parser is not complete, so this library adds zero-width spaces (`U+200B`) around formatting-marker boundaries and uses visible spaces only for a few Japanese, Chinese, and Korean cases where that is still needed. This keeps emphasis stable across English and dense CJK text. |
22
+ | No table syntax in `mrkdwn` | Detect Markdown tables and render them as Slack `table` blocks, while also repairing common LLM-generated table issues such as missing pipes. |
23
+ | Rich LLM output | Convert standalone images, dividers, simple quotes, code fences, and simple lists into native Block Kit blocks where the Markdown structure is unambiguous. |
22
24
 
23
- The goal is natural rendering on Slack, not full CommonMark or HTML fidelity.
25
+ The goal is natural rendering on Slack without exposing raw formatting markers, not full CommonMark or HTML fidelity.
24
26
  If Slack itself does not support a construct in `markdown` blocks, this library prefers safe plain-text rendering or explicit `table` blocks over aggressive rewrites into old `mrkdwn`.
25
27
 
26
28
  ## Features
27
29
 
28
- - Convert ordinary Markdown into Slack `markdown` blocks
30
+ - Convert general Markdown into Slack `markdown` blocks
29
31
  - Convert Markdown tables into Slack `table` blocks
32
+ - Promote safe standalone Markdown constructs into richer Block Kit blocks: `image`, `divider`, and `rich_text`
30
33
  - Repair common LLM table issues such as missing outer pipes, missing separator rows, mismatched column counts, and empty cells
31
- - Split output into multiple Slack messages when needed to satisfy Slack's "one table per message" constraint
34
+ - Split output into multiple Slack messages when needed to satisfy Slack's "one table per message" and per-message block-count constraints
32
35
  - Remove ANSI/control characters and neutralize invalid Slack angle-bracket tokens before block generation
33
36
  - Add zero-width spaces around inline formatting markers to reduce rendering issues outside fenced code blocks, while preserving English-like punctuation-only boundaries that Slack already renders reliably
34
37
  - Add visible spaces for a small set of nested inline-code cases in dense Japanese, Chinese, and Korean text when zero-width spaces alone are not enough
@@ -43,7 +46,7 @@ The library is built around how Slack actually renders `markdown` and `table` bl
43
46
 
44
47
  Slack updated its [`markdown` block docs](https://docs.slack.dev/reference/block-kit/blocks/markdown-block/)
45
48
  and [changelog entry](https://docs.slack.dev/changelog/2026/03/06/block-kit-rich-text)
46
- on March 6, 2026 to describe broader support for headings, dividers, task lists,
49
+ on March 6, 2026 as it started supporting broader Markdown features such as headings, dividers, task lists,
47
50
  native Markdown tables, and syntax-highlighted code blocks. In the Slack Web
48
51
  workspace used for this project's April 8, 2026 validation, raw `markdown`
49
52
  blocks rendered those constructs natively, including distinct heading levels
@@ -60,6 +63,7 @@ Reliable in current Slack rendering:
60
63
  - Bare URLs, `<https://...>` style links, Markdown links, reference-style links, and mailto links
61
64
  - Bullet lists, ordered lists, task lists, and simple blockquotes
62
65
  - Explicit Slack `table` blocks generated from Markdown tables
66
+ - Explicit richer blocks generated from unambiguous Markdown, such as standalone images, code fences, simple lists, and simple quotes
63
67
  - In environments where Slack has enabled the newer renderer, raw Markdown headings, dividers, and tables inside `markdown` blocks
64
68
 
65
69
  Known Slack-side limitations:
@@ -70,19 +74,22 @@ Known Slack-side limitations:
70
74
  - Raw Markdown tables inside `markdown` blocks now render in some newer Slack environments, but explicit Slack `table` blocks remain the reliable option across workspaces and delivery paths
71
75
  - Markdown image syntax does not become an embedded image in `markdown` blocks
72
76
  - Math, raw HTML, HTML comments, `<details>`, admonition syntax, and Mermaid are rendered as plain text or code, not as rich features
77
+ - Some newly documented Block Kit block types can be unavailable on a given `chat.postMessage` path; this library emits only a conservative subset of richer block types that has been validated through real Slack posting checks.
78
+ - The Slack **mobile** app re-prefixes the list marker onto each continuation line of a list item inside `markdown` blocks (e.g. `1. Heading` followed by an indented paragraph shows as `1. Heading` / `1.continuation` on mobile, while Slack desktop and Slack Web render the same payload correctly). This is a Slack client-side rendering behavior, not a parser bug. Tracking: [issue #45](https://github.com/darkgaldragon/slack-markdown-parser/issues/45).
73
79
 
74
80
  What this library compensates for:
75
81
 
76
82
  - Normalizes underscore emphasis (`_..._`, `__...__`) into Slack-friendly asterisk emphasis
77
83
  - Wraps bare URLs into Slack-friendly `<https://...>` link form before sending `markdown` blocks
78
84
  - Repairs malformed LLM-generated tables before converting them into Slack `table` blocks
85
+ - Converts unambiguous standalone Markdown constructs into native Block Kit blocks when that is safer than relying on raw `markdown` rendering
79
86
  - Keeps table-like rows inside fenced code blocks out of table normalization
80
87
  - Optionally turns internal blank lines into placeholder lines that keep paragraphs visibly separated in Slack `markdown` blocks
81
88
  - Neutralizes invalid Slack angle-bracket tokens such as raw HTML-like tags
82
89
 
83
90
  ## Requirements
84
91
 
85
- - Your Slack integration must support Block Kit payloads with `markdown` and `table` blocks.
92
+ - Your Slack integration must support Block Kit payloads with `markdown`, `table`, and the richer blocks emitted by this library (`rich_text`, `image`, and `divider`).
86
93
  - This library does not help when your delivery path only accepts plain `text` or `mrkdwn` strings.
87
94
 
88
95
  ## Installation
@@ -9,13 +9,13 @@
9
9
 
10
10
  ## 出力
11
11
 
12
- - Slack Block Kit ブロック(`markdown` / `table`)
13
- - 複数テーブル入力時は「1メッセージ1テーブル」を満たすメッセージ群
12
+ - Slack Block Kit ブロック(`markdown`, `table`, `rich_text`, `image`, `divider`)
13
+ - 複数テーブルや多数の昇格ブロックがある入力時は、「1メッセージ1テーブル」と Slack のメッセージあたりブロック数制限を満たすメッセージ群
14
14
 
15
15
  ## 設計目標
16
16
 
17
17
  このパーサーは、CommonMark 全体や HTML / リッチドキュメントの完全再現を目標にはしません。
18
- 目的は、Slack Block Kit の `markdown` / `table` ブロックで送ったときに自然に読めるメッセージを作ることです。
18
+ 目的は、Slack Block Kit で送ったときに自然に読めるメッセージを作ることです。
19
19
 
20
20
  Markdown としての厳密さより Slack 上での読みやすさが重要になる場合は、Slack 上で安定して読める表現を優先します。
21
21
 
@@ -31,10 +31,10 @@ Markdown としての厳密さより Slack 上での読みやすさが重要に
31
31
  6. テーブル領域と非テーブル領域に分割する
32
32
  7. 領域ごとにブロックを作る
33
33
  - テーブル領域: セル内装飾を解析して `table` ブロックを生成。変換に失敗した場合は `markdown` ブロックに戻す
34
- - 非テーブル領域: 必要に応じてゼロ幅スペースを加えた上で `markdown` ブロックを生成する
35
- - `preserve_visual_blank_lines=True` の場合は、非テーブル領域の内部空行を「ノーブレークスペースだけを含む行」に置き換えてから `markdown` ブロックを作る
34
+ - 非テーブル領域: 安全に判定できる単独 Markdown 構文を先にリッチブロックへ変換し、残りのテキストは必要に応じてゼロ幅スペースを加えた上で `markdown` ブロックを生成する
35
+ - `preserve_visual_blank_lines=True` の場合は、残った `markdown` ブロックの内部空行を「ノーブレークスペースだけを含む行」に置き換えてから `markdown` ブロックを作る
36
36
 
37
- `convert_markdown_to_slack_messages` は上記の結果を「1メッセージ1テーブル」制約に沿って分割します。
37
+ `convert_markdown_to_slack_messages` は上記の結果を「1メッセージ1テーブル」制約と Slack のメッセージあたりブロック数制限に沿って分割します。
38
38
  `convert_markdown_to_slack_payloads` は、同じ分割結果に `chat.postMessage.text` 用のプレビュー文字列を付けた送信データを返します。
39
39
 
40
40
  ## 実測ベースの Slack の挙動
@@ -49,6 +49,7 @@ Markdown としての厳密さより Slack 上での読みやすさが重要に
49
49
  - bare URL, `<https://...>` 形式リンク, Markdown リンク, 参照リンク, mailto リンク
50
50
  - 箇条書き, 番号付きリスト, タスクリスト, 単純な1段引用
51
51
  - Slack `table` ブロック
52
+ - 意味が明確な単独 Markdown 構文から生成した Slack ネイティブのリッチブロック
52
53
 
53
54
  Slack は 2026-03-06 に `markdown` ブロックの公式ドキュメントを更新し、これまでより多くの Markdown 記法を案内し始めました。本プロジェクトの 2026-04-08 の Slack Web 実測では、raw の `markdown` ブロックで次を確認しています。
54
55
 
@@ -73,6 +74,13 @@ Slack は 2026-03-06 に `markdown` ブロックの公式ドキュメントを
73
74
  - `_..._` / `__...__` を Slack 互換の `*...*` / `**...**` に正規化する
74
75
  - bare URL を Slack で安定しやすい `<https://...>` 形式にそろえる
75
76
  - 崩れた Markdown テーブルを補って `table` ブロックへ変換する
77
+ - 意味が明確な単独 Markdown 構文を Slack ネイティブのブロックへ変換する
78
+ - 単独行の画像構文 `![alt](https://...)` → `image`
79
+ - 水平線 → `divider`
80
+ - フェンスドコード → `rich_text_preformatted`
81
+ - 単純な1段引用 → `rich_text_quote`
82
+ - 単純な箇条書き / 番号付きリスト → `rich_text_list`
83
+ - リストは、テキスト領域の先頭または空行の直後から始まり、連続する非空行がすべてリスト項目で、1〜3スペースの曖昧なネストインデントや Markdown バックスラッシュエスケープに依存せず、直後にインデント付きの継続段落がない場合だけ昇格する
76
84
  - フェンスドコード内の table 風行をテーブル解析対象から除外する
77
85
  - 内部空行を、必要に応じて段落区切りを見えやすくする補助行へ置き換える
78
86
  - `<foo>` や生 HTML 風タグのような、Slack の特殊記法としては無効な `<...>` 形式を無害化する
@@ -158,16 +166,22 @@ LLM は外枠パイプの省略、区切り行の欠落、列数の不一致な
158
166
 
159
167
  ### 対象パターン
160
168
 
161
- 以下の装飾記号について、前後のどちらか一方でも隣接文字がスペース・タブ・改行・既存のゼロ幅スペースでない場合、または行頭・行末に接している場合、通常は装飾トークン全体をゼロ幅スペース(`U+200B`)で囲みます。
169
+ 以下の装飾記号について、見た目を変えずに Slack の装飾境界を保つために必要な箇所だけにゼロ幅スペース(`U+200B`)を挿入します。
162
170
 
163
171
  - `` `code` `` — インラインコード
164
172
  - `**bold**` — 太字
165
173
  - `*italic*` — 斜体
166
174
  - `~~strike~~` — 取消線
167
175
 
176
+ ルール:
177
+
178
+ - チャンクの先頭・末尾(行頭・行末・テキスト端、またはフェンスドコードブロックの境界)は安全とみなし、ゼロ幅スペースを付けません。
179
+ - 外側の片方が前後の非境界テキストに密着している場合、その側だけにゼロ幅スペースを付けます。安全(境界)側はそのままにします。
180
+ - 強調マーカー(`**`・`*`・`~~`)の内側が句読点に密着している場合(例 `**注意:**` や `**70.9%→83.0%**`)、マーカーの内側にゼロ幅スペースを挿入します。これによりマーカーの内側隣接文字が非句読点になり、後続が何であっても Slack の CommonMark right-/left-flanking 判定が成立します。Slack が flanking 近傍として認めない CJK テキストや CJK 句読点(`、` / `。`)の直前でも有効です。インラインコードは flanking 規則の対象外なので、このルールから除外します。
181
+
168
182
  例外:
169
183
 
170
- - 装飾の中身が英語系テキストで、密着している隣接文字が句読点だけの場合は、元のトークンをそのまま保つ。`**APIYI (apiyi.com)**:` のように Slack がそのまま表示できるケースで、不要なゼロ幅スペースを増やさないためです。
184
+ - 装飾の中身が英語系テキストで、密着している隣接文字が **ASCII** 句読点だけの場合は、元のトークンをそのまま保ちます。`**APIYI (apiyi.com)**:` のように Slack がそのまま表示できるケースで、不要なゼロ幅スペースを増やさないためです。`、` や `。` のような非ASCII句読点が隣接する場合は保持せず、上記の内側ゼロ幅スペースで保護します。
171
185
 
172
186
  ### 除外範囲
173
187
 
@@ -9,13 +9,13 @@ This document describes how `slack-markdown-parser` converts Markdown into Slack
9
9
 
10
10
  ## Output
11
11
 
12
- - Slack Block Kit blocks (`markdown` / `table`)
13
- - When the input contains multiple tables, a list of messages that satisfies the "one table per message" rule
12
+ - Slack Block Kit blocks (`markdown`, `table`, `rich_text`, `image`, and `divider`)
13
+ - When the input contains multiple tables or many promoted blocks, a list of messages that satisfies the "one table per message" rule and Slack's per-message block-count limit
14
14
 
15
15
  ## Design target
16
16
 
17
17
  This parser does not try to reproduce full CommonMark, HTML, or rich-document rendering.
18
- Its goal is to produce Slack messages that read naturally when delivered through Slack Block Kit `markdown` and `table` blocks.
18
+ Its goal is to produce Slack messages that read naturally when delivered through Slack Block Kit blocks.
19
19
 
20
20
  When exact Markdown fidelity conflicts with Slack readability, readable Slack output takes priority.
21
21
 
@@ -31,10 +31,10 @@ When exact Markdown fidelity conflicts with Slack readability, readable Slack ou
31
31
  6. Split the text into table regions and non-table regions
32
32
  7. Build blocks for each region:
33
33
  - Table regions: parse inline cell styling and generate a `table` block. If conversion fails, such as when there are fewer than two candidate lines or the parse result is empty, fall back to a `markdown` block.
34
- - Non-table regions: add zero-width spaces where needed and generate a `markdown` block.
35
- - If `preserve_visual_blank_lines=True`, replace internal blank lines in non-table regions with lines that contain only a non-breaking space before emitting the `markdown` block.
34
+ - Non-table regions: first promote safe standalone Markdown constructs into richer Block Kit blocks, then add zero-width spaces where needed and generate `markdown` blocks for the remaining text.
35
+ - If `preserve_visual_blank_lines=True`, replace internal blank lines in remaining `markdown` blocks with lines that contain only a non-breaking space before emitting the `markdown` block.
36
36
 
37
- `convert_markdown_to_slack_messages` then splits the resulting block list to satisfy the "one table per message" rule.
37
+ `convert_markdown_to_slack_messages` then splits the resulting block list to satisfy the "one table per message" rule and Slack's per-message block-count limit.
38
38
  `convert_markdown_to_slack_payloads` returns the same split blocks plus preview `text` values ready for `chat.postMessage`.
39
39
 
40
40
  ## How Slack behaved in testing
@@ -49,6 +49,7 @@ The behaviors below are based on practical validation against real Slack clients
49
49
  - Bare URLs, `<https://...>` style links, Markdown links, reference-style links, and mailto links
50
50
  - Bullet lists, ordered lists, task lists, and simple one-level blockquotes
51
51
  - Slack `table` blocks
52
+ - Native richer blocks generated from unambiguous standalone Markdown constructs
52
53
 
53
54
  Slack published updated `markdown` block documentation and a changelog entry on March 6, 2026. In the Slack Web workspace validated for this project on April 8, 2026, raw `markdown` blocks rendered:
54
55
 
@@ -73,6 +74,13 @@ Slack still controls when those newer features appear and how they look, so trea
73
74
  - `_..._` and `__...__` are normalized into Slack-friendly `*...*` and `**...**`
74
75
  - Bare URLs are wrapped into Slack-friendly `<https://...>` form before `markdown` block delivery
75
76
  - Malformed Markdown tables are repaired before `table` block generation
77
+ - Unambiguous standalone Markdown constructs are promoted into native Slack blocks:
78
+ - standalone image syntax `![alt](https://...)` to `image`
79
+ - thematic-break lines to `divider`
80
+ - fenced code blocks to `rich_text_preformatted`
81
+ - simple one-level quotes to `rich_text_quote`
82
+ - simple bullet and ordered lists to `rich_text_list`
83
+ - Lists are promoted only when the list starts at the beginning of the text region or after a blank line, each non-blank line in the run is a list item, the list does not use ambiguous 1-3-space nested indentation, the item text does not rely on Markdown backslash escapes, and the run is not followed by an indented continuation paragraph.
76
84
  - Table-like rows inside fenced code blocks are kept out of table parsing
77
85
  - Internal blank lines can optionally be rewritten into placeholder lines so Slack keeps visible paragraph separation
78
86
  - Unsupported Slack angle-bracket tokens such as `<foo>` or raw HTML-like tags are neutralized
@@ -157,16 +165,22 @@ In languages such as Japanese, Chinese, and Korean that do not usually put space
157
165
 
158
166
  ### Target patterns
159
167
 
160
- For each formatting token below, if either adjacent side is not a space, tab, newline, or existing zero-width space, or if the token touches the start or end of a line, the whole token is normally wrapped in a zero-width space (`U+200B`) so Slack recognizes it as a standalone formatting boundary:
168
+ The library inserts zero-width spaces (`U+200B`) only where they are needed to keep Slack's formatting boundaries intact, without changing the visible layout, for each formatting token below:
161
169
 
162
170
  - `` `code` ``: inline code
163
171
  - `**bold**`: bold
164
172
  - `*italic*`: italic
165
173
  - `~~strike~~`: strikethrough
166
174
 
175
+ Rules:
176
+
177
+ - The start and end of a chunk (a line/text boundary, or the edge of a fenced code block) are treated as safe; no zero-width space is added there.
178
+ - When an outer edge is tight against surrounding non-boundary text, only that edge is padded with a zero-width space. The safe (boundary) edge is left clean.
179
+ - When an emphasis marker (`**`, `*`, `~~`) sits directly against punctuation on its inner side (for example `**注意:**` or `**70.9%→83.0%**`), a zero-width space is inserted just *inside* the marker. This makes the marker's inner neighbor a non-punctuation character, so Slack's CommonMark right-/left-flanking check succeeds regardless of what surrounds the token — including before CJK text and CJK punctuation (`、` / `。`), which Slack does not accept as a flanking neighbor. Inline code spans are exempt from this rule because they do not obey flanking rules.
180
+
167
181
  Exception:
168
182
 
169
- - If the token body is English-like text and the only tight neighbors are punctuation characters, the raw token is preserved. This avoids over-correcting spans such as `**APIYI (apiyi.com)**:` that Slack already renders correctly without extra zero-width spaces.
183
+ - If the token body is English-like text and its only tight neighbors are **ASCII** punctuation characters, the raw token is preserved. This avoids over-correcting spans such as `**APIYI (apiyi.com)**:` that Slack already renders correctly without extra zero-width spaces. A non-ASCII punctuation neighbor such as `、` or `。` is not preserved — it is protected by the inner zero-width space described above.
170
184
 
171
185
  ### Excluded regions
172
186
 
@@ -4,8 +4,8 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "slack-markdown-parser"
7
- version = "2.3.2"
8
- description = "Convert LLM Markdown into Slack Block Kit markdown/table messages"
7
+ version = "2.4.1"
8
+ description = "Convert LLM Markdown into Slack Block Kit messages"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
11
11
  license = "MIT"
@@ -1,6 +1,6 @@
1
1
  """slack-markdown-parser public package API."""
2
2
 
3
- __version__ = "2.3.2"
3
+ __version__ = "2.4.1"
4
4
  __license__ = "MIT"
5
5
 
6
6
  from .converter import (