slack-markdown-parser 2.2.1__tar.gz → 2.2.2__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.
- {slack_markdown_parser-2.2.1 → slack_markdown_parser-2.2.2}/CHANGELOG.md +11 -4
- {slack_markdown_parser-2.2.1 → slack_markdown_parser-2.2.2}/PKG-INFO +37 -3
- {slack_markdown_parser-2.2.1 → slack_markdown_parser-2.2.2}/README-ja.md +37 -2
- {slack_markdown_parser-2.2.1 → slack_markdown_parser-2.2.2}/README.md +36 -2
- slack_markdown_parser-2.2.2/docs/slack-client-manual-checklist.md +53 -0
- slack_markdown_parser-2.2.2/docs/slack-nested-modifier-findings.md +59 -0
- slack_markdown_parser-2.2.2/docs/slack-render-test-workflow.md +117 -0
- {slack_markdown_parser-2.2.1 → slack_markdown_parser-2.2.2}/docs/spec-ja.md +43 -1
- {slack_markdown_parser-2.2.1 → slack_markdown_parser-2.2.2}/docs/spec.md +43 -1
- {slack_markdown_parser-2.2.1 → slack_markdown_parser-2.2.2}/pyproject.toml +1 -1
- {slack_markdown_parser-2.2.1 → slack_markdown_parser-2.2.2}/slack_markdown_parser/__init__.py +1 -1
- {slack_markdown_parser-2.2.1 → slack_markdown_parser-2.2.2}/slack_markdown_parser/converter.py +363 -25
- {slack_markdown_parser-2.2.1 → slack_markdown_parser-2.2.2}/slack_markdown_parser.egg-info/PKG-INFO +37 -3
- {slack_markdown_parser-2.2.1 → slack_markdown_parser-2.2.2}/slack_markdown_parser.egg-info/SOURCES.txt +9 -1
- slack_markdown_parser-2.2.2/tests/fixtures/slack_cjk_inner_code_matrix.md +275 -0
- slack_markdown_parser-2.2.2/tests/fixtures/slack_nested_modifier_matrix.md +365 -0
- slack_markdown_parser-2.2.2/tests/fixtures/slack_nested_modifier_matrix_parens.md +365 -0
- slack_markdown_parser-2.2.2/tests/fixtures/slack_nested_modifier_matrix_quotes.md +365 -0
- {slack_markdown_parser-2.2.1 → slack_markdown_parser-2.2.2}/tests/test_converter.py +235 -0
- slack_markdown_parser-2.2.2/tests/test_nested_modifier_matrix.py +86 -0
- {slack_markdown_parser-2.2.1 → slack_markdown_parser-2.2.2}/CONTRIBUTING.md +0 -0
- {slack_markdown_parser-2.2.1 → slack_markdown_parser-2.2.2}/LICENSE +0 -0
- {slack_markdown_parser-2.2.1 → slack_markdown_parser-2.2.2}/MANIFEST.in +0 -0
- {slack_markdown_parser-2.2.1 → slack_markdown_parser-2.2.2}/setup.cfg +0 -0
- {slack_markdown_parser-2.2.1 → slack_markdown_parser-2.2.2}/slack_markdown_parser/py.typed +0 -0
- {slack_markdown_parser-2.2.1 → slack_markdown_parser-2.2.2}/slack_markdown_parser.egg-info/dependency_links.txt +0 -0
- {slack_markdown_parser-2.2.1 → slack_markdown_parser-2.2.2}/slack_markdown_parser.egg-info/requires.txt +0 -0
- {slack_markdown_parser-2.2.1 → slack_markdown_parser-2.2.2}/slack_markdown_parser.egg-info/top_level.txt +0 -0
- {slack_markdown_parser-2.2.1 → slack_markdown_parser-2.2.2}/tests/fixtures/llm_markdown_p0_corpus.md +0 -0
- {slack_markdown_parser-2.2.1 → slack_markdown_parser-2.2.2}/tests/test_llm_markdown_p0_corpus.py +0 -0
|
@@ -6,15 +6,22 @@ The format is based on Keep a Changelog, and the project follows Semantic Versio
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [2.2.2] - 2026-03-10
|
|
10
|
+
|
|
9
11
|
### Added
|
|
10
12
|
|
|
11
|
-
- Added
|
|
12
|
-
- Added the `py.typed` marker and packaging rules for docs and tests in source distributions.
|
|
13
|
+
- Added Slack render-test tooling, generated regression fixtures, and maintainer docs for validating real Slack client rendering across Web, desktop, and mobile.
|
|
13
14
|
|
|
14
15
|
### Changed
|
|
15
16
|
|
|
16
|
-
-
|
|
17
|
-
-
|
|
17
|
+
- Refreshed the README and behavior spec to distinguish Slack renderer limitations from parser-owned normalization and repair behavior.
|
|
18
|
+
- Clarified locale-aware formatting behavior and added public examples for the Slack render-test workflow.
|
|
19
|
+
|
|
20
|
+
### Fixed
|
|
21
|
+
|
|
22
|
+
- Stabilized nested inline-code emphasis rendering across English, Japanese, Chinese, and Korean contexts, including existing-ZWSP boundaries and CJK italic/strike cases.
|
|
23
|
+
- Preserved user-authored spacing in fallback text while removing parser-inserted rendering-only padding.
|
|
24
|
+
- Wrapped bare URLs into Slack-friendly autolink form before sending `markdown` blocks so adjacent lines no longer collapse into malformed angle-link text.
|
|
18
25
|
|
|
19
26
|
## [2.2.1] - 2026-03-07
|
|
20
27
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: slack-markdown-parser
|
|
3
|
-
Version: 2.2.
|
|
3
|
+
Version: 2.2.2
|
|
4
4
|
Summary: Convert LLM Markdown into Slack Block Kit markdown/table messages
|
|
5
5
|
Author: darkgaldragon
|
|
6
6
|
License-Expression: MIT
|
|
@@ -48,9 +48,12 @@ This library leans on Slack Block Kit's `markdown` block for standard Markdown a
|
|
|
48
48
|
| Problem | Approach |
|
|
49
49
|
|---|---|
|
|
50
50
|
| Conversion overhead | Send standard Markdown through Slack `markdown` blocks without rewriting it into `mrkdwn`. |
|
|
51
|
-
| Formatting instability |
|
|
51
|
+
| Formatting instability | Prefer zero-width spaces (ZWSP, U+200B) around formatting tokens, and fall back to locale-aware visible-space padding for CJK nested inline-code cases where Slack rendering still breaks. |
|
|
52
52
|
| No table syntax in `mrkdwn` | Detect Markdown tables and convert them into Slack `table` blocks, including repair of common LLM-generated table inconsistencies. |
|
|
53
53
|
|
|
54
|
+
The target is natural rendering on Slack, not full CommonMark or HTML fidelity.
|
|
55
|
+
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`.
|
|
56
|
+
|
|
54
57
|
## Features
|
|
55
58
|
|
|
56
59
|
- Convert standard Markdown into Slack `markdown` blocks
|
|
@@ -59,10 +62,38 @@ This library leans on Slack Block Kit's `markdown` block for standard Markdown a
|
|
|
59
62
|
- Split output into multiple Slack messages when needed to satisfy Slack's "one table per message" constraint
|
|
60
63
|
- Sanitize ANSI/control characters and neutralize invalid Slack angle-bracket tokens before block generation
|
|
61
64
|
- Add ZWSP around inline formatting tokens to reduce rendering issues outside fenced code blocks
|
|
65
|
+
- Use locale-aware visible-space padding for nested inline-code emphasis in dense Japanese, Chinese, and Korean text when Slack requires stronger boundaries than ZWSP alone
|
|
62
66
|
- Support Markdown and Slack-style links inside table cells
|
|
63
|
-
- Build fallback text for `chat.postMessage.text` from generated blocks
|
|
67
|
+
- Build fallback text for `chat.postMessage.text` from generated blocks, normalizing synthetic ZWSP and any parser-inserted visible-space padding used only for rendering stability
|
|
64
68
|
- Accept raw LLM Markdown without tightly constraining the model prompt, using best-effort sanitize and table repair before Slack delivery
|
|
65
69
|
|
|
70
|
+
## Observed Slack behavior
|
|
71
|
+
|
|
72
|
+
The library is built around how Slack actually renders `markdown` and `table` blocks in practice.
|
|
73
|
+
|
|
74
|
+
Reliable in current Slack rendering:
|
|
75
|
+
|
|
76
|
+
- `**bold**`, `*italic*`, `~~strike~~`, inline code, and fenced code blocks
|
|
77
|
+
- Bare URLs, autolinks, Markdown links, reference-style links, and mailto links
|
|
78
|
+
- Bullet lists, ordered lists, task lists, and simple blockquotes
|
|
79
|
+
- Explicit Slack `table` blocks generated from Markdown tables
|
|
80
|
+
|
|
81
|
+
Known Slack-side limitations:
|
|
82
|
+
|
|
83
|
+
- Heading syntax (`#`, setext headings) renders as plain text rather than true heading levels
|
|
84
|
+
- Nested blockquotes are weak compared with full Markdown renderers
|
|
85
|
+
- Horizontal rules render more like line text than semantic separators
|
|
86
|
+
- Markdown image syntax does not become an embedded image in `markdown` blocks
|
|
87
|
+
- Math, raw HTML, HTML comments, `<details>`, admonition syntax, and Mermaid are rendered as plain text or code, not as rich features
|
|
88
|
+
|
|
89
|
+
What this library compensates for:
|
|
90
|
+
|
|
91
|
+
- Normalizes underscore emphasis (`_..._`, `__...__`) into Slack-friendly asterisk emphasis
|
|
92
|
+
- Wraps bare URLs into Slack-friendly autolink form before sending `markdown` blocks
|
|
93
|
+
- Repairs malformed LLM-generated tables before converting them into Slack `table` blocks
|
|
94
|
+
- Keeps table-like rows inside fenced code blocks out of table normalization
|
|
95
|
+
- Neutralizes invalid Slack angle-bracket tokens such as raw HTML-like tags
|
|
96
|
+
|
|
66
97
|
## Requirements
|
|
67
98
|
|
|
68
99
|
- Your Slack integration must support Block Kit payloads with `markdown` and `table` blocks.
|
|
@@ -175,6 +206,9 @@ These are also part of the public package surface:
|
|
|
175
206
|
|
|
176
207
|
- Behavior spec: [docs/spec.md](docs/spec.md)
|
|
177
208
|
- Japanese behavior spec: [docs/spec-ja.md](docs/spec-ja.md)
|
|
209
|
+
- Slack render-test workflow: [docs/slack-render-test-workflow.md](docs/slack-render-test-workflow.md)
|
|
210
|
+
- Nested-modifier findings: [docs/slack-nested-modifier-findings.md](docs/slack-nested-modifier-findings.md)
|
|
211
|
+
- Desktop/mobile manual checklist: [docs/slack-client-manual-checklist.md](docs/slack-client-manual-checklist.md)
|
|
178
212
|
- Non-goals:
|
|
179
213
|
- Generating Slack `mrkdwn` strings
|
|
180
214
|
- Supporting clients or MCP tools that can only send `mrkdwn`
|
|
@@ -17,9 +17,12 @@ Slack Block Kit の `markdown` ブロック(標準 Markdown 構文をそのま
|
|
|
17
17
|
| 課題 | 解決手段 |
|
|
18
18
|
|---|---|
|
|
19
19
|
| 変換コスト | `markdown` ブロックが標準 Markdown をそのまま受け付けるため、LLM 出力を変換せず利用可能 |
|
|
20
|
-
| 装飾崩れ |
|
|
20
|
+
| 装飾崩れ | 基本は ZWSP(ゼロ幅スペース U+200B)で装飾境界を補強し、CJK の密着文脈でインラインコードを内包する装飾が崩れる場合のみ、言語別ルールで可視スペースも使ってレンダリングを安定化する |
|
|
21
21
|
| テーブル非対応 | Markdown テーブルを検知して `table` ブロックに変換。LLM の出力する多様なテーブル記法の揺れも自動補完し `invalid_blocks` エラーを回避 |
|
|
22
22
|
|
|
23
|
+
このライブラリの目標は、CommonMark や HTML を完全再現することではなく、Slack 上で自然に読める表示を作ることです。
|
|
24
|
+
Slack の `markdown` ブロック自体が対応していない構文は、古い `mrkdwn` へ無理に書き換えるより、安全なプレーンテキスト表示や `table` ブロック化を優先します。
|
|
25
|
+
|
|
23
26
|
## 主な機能
|
|
24
27
|
|
|
25
28
|
- 標準 Markdown テキストを `markdown` ブロックに変換
|
|
@@ -28,10 +31,38 @@ Slack Block Kit の `markdown` ブロック(標準 Markdown 構文をそのま
|
|
|
28
31
|
- テーブルごとにメッセージを自動分割(Slack の「1メッセージ1テーブル」制約に対応)
|
|
29
32
|
- ANSI escape / 制御文字を除去し、不正な Slack 角括弧トークンを自動で無害化
|
|
30
33
|
- 装飾記号の前後に ZWSP を付与して表示崩れを抑制(フェンスドコードブロック内は除外、インラインコードは付与対象)
|
|
34
|
+
- 日本語・中国語・韓国語の密着文脈で、インラインコードを内包する装飾には可視スペースを補って Slack 表示を安定化
|
|
31
35
|
- テーブルセル内の Markdown link / Slack link を認識
|
|
32
|
-
- `chat.postMessage.text` 用の fallback
|
|
36
|
+
- `chat.postMessage.text` 用の fallback テキストを生成(表示安定化のために入れた ZWSP や人工的な可視スペースは通知文では自然な形に正規化)
|
|
33
37
|
- モデル側で Markdown を厳密に制御しなくてもよいよう、Slack 送信前にベストエフォートでサニタイズとテーブル補完を行う
|
|
34
38
|
|
|
39
|
+
## 実測ベースの Slack 挙動
|
|
40
|
+
|
|
41
|
+
本ライブラリは、Slack の `markdown` / `table` ブロックが実際にどう見えるかを前提に設計しています。
|
|
42
|
+
|
|
43
|
+
現在の Slack で安定して表示されるもの:
|
|
44
|
+
|
|
45
|
+
- `**bold**`, `*italic*`, `~~strike~~`, インラインコード, フェンスドコード
|
|
46
|
+
- bare URL, autolink, Markdown link, 参照リンク, mailto link
|
|
47
|
+
- 箇条書き, 番号付きリスト, タスクリスト, 単純な引用
|
|
48
|
+
- Markdown テーブルを変換した明示的な Slack `table` ブロック
|
|
49
|
+
|
|
50
|
+
Slack 側の制約として残るもの:
|
|
51
|
+
|
|
52
|
+
- `#` 見出しや setext 見出しは、真の見出しレベルではなくプレーンテキスト寄りに表示される
|
|
53
|
+
- 多段引用はフル Markdown レンダラほどきれいに出ない
|
|
54
|
+
- 水平線は semantic な区切りではなく線テキスト寄りに見える
|
|
55
|
+
- Markdown 画像記法は `markdown` ブロック内では埋め込み画像にならない
|
|
56
|
+
- 数式, 生 HTML, HTML comment, `<details>`, admonition 記法, Mermaid はリッチ機能としては扱われず、テキストまたはコードとして表示される
|
|
57
|
+
|
|
58
|
+
本ライブラリが吸収するもの:
|
|
59
|
+
|
|
60
|
+
- underscore 装飾 (`_..._`, `__...__`) を Slack 互換の asterisk 装飾へ正規化
|
|
61
|
+
- bare URL を Slack の `markdown` ブロックで安定する autolink 形式へ正規化
|
|
62
|
+
- LLM が崩したテーブル記法を補完して Slack `table` ブロックへ変換
|
|
63
|
+
- フェンスドコード内の table 風行をテーブル正規化対象から除外
|
|
64
|
+
- 生 HTML 風タグなど、不正な Slack angle token を無害化
|
|
65
|
+
|
|
35
66
|
## 利用前提
|
|
36
67
|
|
|
37
68
|
- Slack Block Kit の `blocks` で `markdown` / `table` ブロックを送信できる実装が必要です。
|
|
@@ -131,6 +162,10 @@ QA | ~~保留~~ | Team C
|
|
|
131
162
|
## 仕様
|
|
132
163
|
|
|
133
164
|
- 挙動仕様: [docs/spec-ja.md](docs/spec-ja.md)
|
|
165
|
+
- 英語仕様: [docs/spec.md](docs/spec.md)
|
|
166
|
+
- Slack 実レンダリング検証手順: [docs/slack-render-test-workflow.md](docs/slack-render-test-workflow.md)
|
|
167
|
+
- nested modifier 実測メモ: [docs/slack-nested-modifier-findings.md](docs/slack-nested-modifier-findings.md)
|
|
168
|
+
- Desktop / mobile 手動確認: [docs/slack-client-manual-checklist.md](docs/slack-client-manual-checklist.md)
|
|
134
169
|
- 非対応:
|
|
135
170
|
- `mrkdwn` 文字列の生成
|
|
136
171
|
- `mrkdwn` のみ送信可能なクライアント/MCP ツール
|
|
@@ -17,9 +17,12 @@ This library leans on Slack Block Kit's `markdown` block for standard Markdown a
|
|
|
17
17
|
| Problem | Approach |
|
|
18
18
|
|---|---|
|
|
19
19
|
| Conversion overhead | Send standard Markdown through Slack `markdown` blocks without rewriting it into `mrkdwn`. |
|
|
20
|
-
| Formatting instability |
|
|
20
|
+
| Formatting instability | Prefer zero-width spaces (ZWSP, U+200B) around formatting tokens, and fall back to locale-aware visible-space padding for CJK nested inline-code cases where Slack rendering still breaks. |
|
|
21
21
|
| No table syntax in `mrkdwn` | Detect Markdown tables and convert them into Slack `table` blocks, including repair of common LLM-generated table inconsistencies. |
|
|
22
22
|
|
|
23
|
+
The target is natural rendering on Slack, not full CommonMark or HTML fidelity.
|
|
24
|
+
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
|
+
|
|
23
26
|
## Features
|
|
24
27
|
|
|
25
28
|
- Convert standard Markdown into Slack `markdown` blocks
|
|
@@ -28,10 +31,38 @@ This library leans on Slack Block Kit's `markdown` block for standard Markdown a
|
|
|
28
31
|
- Split output into multiple Slack messages when needed to satisfy Slack's "one table per message" constraint
|
|
29
32
|
- Sanitize ANSI/control characters and neutralize invalid Slack angle-bracket tokens before block generation
|
|
30
33
|
- Add ZWSP around inline formatting tokens to reduce rendering issues outside fenced code blocks
|
|
34
|
+
- Use locale-aware visible-space padding for nested inline-code emphasis in dense Japanese, Chinese, and Korean text when Slack requires stronger boundaries than ZWSP alone
|
|
31
35
|
- Support Markdown and Slack-style links inside table cells
|
|
32
|
-
- Build fallback text for `chat.postMessage.text` from generated blocks
|
|
36
|
+
- Build fallback text for `chat.postMessage.text` from generated blocks, normalizing synthetic ZWSP and any parser-inserted visible-space padding used only for rendering stability
|
|
33
37
|
- Accept raw LLM Markdown without tightly constraining the model prompt, using best-effort sanitize and table repair before Slack delivery
|
|
34
38
|
|
|
39
|
+
## Observed Slack behavior
|
|
40
|
+
|
|
41
|
+
The library is built around how Slack actually renders `markdown` and `table` blocks in practice.
|
|
42
|
+
|
|
43
|
+
Reliable in current Slack rendering:
|
|
44
|
+
|
|
45
|
+
- `**bold**`, `*italic*`, `~~strike~~`, inline code, and fenced code blocks
|
|
46
|
+
- Bare URLs, autolinks, Markdown links, reference-style links, and mailto links
|
|
47
|
+
- Bullet lists, ordered lists, task lists, and simple blockquotes
|
|
48
|
+
- Explicit Slack `table` blocks generated from Markdown tables
|
|
49
|
+
|
|
50
|
+
Known Slack-side limitations:
|
|
51
|
+
|
|
52
|
+
- Heading syntax (`#`, setext headings) renders as plain text rather than true heading levels
|
|
53
|
+
- Nested blockquotes are weak compared with full Markdown renderers
|
|
54
|
+
- Horizontal rules render more like line text than semantic separators
|
|
55
|
+
- Markdown image syntax does not become an embedded image in `markdown` blocks
|
|
56
|
+
- Math, raw HTML, HTML comments, `<details>`, admonition syntax, and Mermaid are rendered as plain text or code, not as rich features
|
|
57
|
+
|
|
58
|
+
What this library compensates for:
|
|
59
|
+
|
|
60
|
+
- Normalizes underscore emphasis (`_..._`, `__...__`) into Slack-friendly asterisk emphasis
|
|
61
|
+
- Wraps bare URLs into Slack-friendly autolink form before sending `markdown` blocks
|
|
62
|
+
- Repairs malformed LLM-generated tables before converting them into Slack `table` blocks
|
|
63
|
+
- Keeps table-like rows inside fenced code blocks out of table normalization
|
|
64
|
+
- Neutralizes invalid Slack angle-bracket tokens such as raw HTML-like tags
|
|
65
|
+
|
|
35
66
|
## Requirements
|
|
36
67
|
|
|
37
68
|
- Your Slack integration must support Block Kit payloads with `markdown` and `table` blocks.
|
|
@@ -144,6 +175,9 @@ These are also part of the public package surface:
|
|
|
144
175
|
|
|
145
176
|
- Behavior spec: [docs/spec.md](docs/spec.md)
|
|
146
177
|
- Japanese behavior spec: [docs/spec-ja.md](docs/spec-ja.md)
|
|
178
|
+
- Slack render-test workflow: [docs/slack-render-test-workflow.md](docs/slack-render-test-workflow.md)
|
|
179
|
+
- Nested-modifier findings: [docs/slack-nested-modifier-findings.md](docs/slack-nested-modifier-findings.md)
|
|
180
|
+
- Desktop/mobile manual checklist: [docs/slack-client-manual-checklist.md](docs/slack-client-manual-checklist.md)
|
|
147
181
|
- Non-goals:
|
|
148
182
|
- Generating Slack `mrkdwn` strings
|
|
149
183
|
- Supporting clients or MCP tools that can only send `mrkdwn`
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Slack Client Manual Checklist
|
|
2
|
+
|
|
3
|
+
Use this for quick smoke checks in Slack Desktop and mobile after parser changes.
|
|
4
|
+
|
|
5
|
+
## How to run
|
|
6
|
+
|
|
7
|
+
1. Open the link for each case in Slack Desktop or mobile.
|
|
8
|
+
2. Confirm the expected visible text and formatting.
|
|
9
|
+
3. Mark `PASS` only if all checks below hold.
|
|
10
|
+
|
|
11
|
+
## Pass criteria
|
|
12
|
+
|
|
13
|
+
- Outer emphasis is rendered for the whole target span.
|
|
14
|
+
- Inline code remains monospace.
|
|
15
|
+
- Raw markers such as `**`, `*`, or `~~` are not visible.
|
|
16
|
+
- English cases do not show extra visible spaces before punctuation.
|
|
17
|
+
- Japanese/Chinese/Korean nested-code cases may show visible spaces around the emphasized span when needed; that is expected.
|
|
18
|
+
|
|
19
|
+
## Cases
|
|
20
|
+
|
|
21
|
+
- `manual_en`
|
|
22
|
+
Expected: `Frontend (App.tsx)` is bold, `App.tsx` is code, no extra space before `:`
|
|
23
|
+
Link: paste your `manual_en` permalink here
|
|
24
|
+
|
|
25
|
+
- `manual_ja`
|
|
26
|
+
Expected: `フロントエンド (App.tsx)` is bold, `App.tsx` is code, visible spaces around the bold span are acceptable
|
|
27
|
+
Link: paste your `manual_ja` permalink here
|
|
28
|
+
|
|
29
|
+
- `manual_zh`
|
|
30
|
+
Expected: `外侧(内侧)` span is bold, inner code remains code, visible spaces around the bold span are acceptable
|
|
31
|
+
Link: paste your `manual_zh` permalink here
|
|
32
|
+
|
|
33
|
+
- `manual_ko`
|
|
34
|
+
Expected: `바깥(내부)강조` span is bold, inner code remains code, trailing visible space before `입니다.` is acceptable
|
|
35
|
+
Link: paste your `manual_ko` permalink here
|
|
36
|
+
|
|
37
|
+
- `manual_mix_ja_en`
|
|
38
|
+
Expected: `Frontend (App.tsx)` is bold inside Japanese text, `App.tsx` is code
|
|
39
|
+
Link: paste your `manual_mix_ja_en` permalink here
|
|
40
|
+
|
|
41
|
+
- `manual_mix_ko_en`
|
|
42
|
+
Expected: `Frontend (App.tsx)` is bold inside Korean text, `App.tsx` is code
|
|
43
|
+
Link: paste your `manual_mix_ko_en` permalink here
|
|
44
|
+
|
|
45
|
+
- `manual_mix_en_ja`
|
|
46
|
+
Expected: `機能A (ID-1)` is bold inside English text, `ID-1` is code, no extra visible spaces are introduced
|
|
47
|
+
Link: paste your `manual_mix_en_ja` permalink here
|
|
48
|
+
|
|
49
|
+
## Recording
|
|
50
|
+
|
|
51
|
+
- `PASS`: rendering matches the expectation above
|
|
52
|
+
- `FAIL`: capture which marker leaked or which style was missing
|
|
53
|
+
- If Desktop and mobile differ, record the client and version separately
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Slack Nested Modifier Findings
|
|
2
|
+
|
|
3
|
+
Observed on Slack Web against `#bot-test` on 2026-03-09.
|
|
4
|
+
|
|
5
|
+
## Variants
|
|
6
|
+
|
|
7
|
+
- `plain`: inner content without surrounding punctuation
|
|
8
|
+
- `parens`: inner content wrapped in parentheses
|
|
9
|
+
- `quotes`: inner content wrapped in quotes
|
|
10
|
+
|
|
11
|
+
## Source fixtures
|
|
12
|
+
|
|
13
|
+
- `tests/fixtures/slack_nested_modifier_matrix.md`
|
|
14
|
+
- `tests/fixtures/slack_nested_modifier_matrix_parens.md`
|
|
15
|
+
- `tests/fixtures/slack_nested_modifier_matrix_quotes.md`
|
|
16
|
+
- `tests/fixtures/slack_cjk_inner_code_matrix.md`
|
|
17
|
+
|
|
18
|
+
## Note on private artifacts
|
|
19
|
+
|
|
20
|
+
The concrete Slack permalinks used during validation are intentionally omitted from the public repository. Re-run the workflow in `docs/slack-render-test-workflow.md` inside your own workspace if you want message-level links for manual verification.
|
|
21
|
+
|
|
22
|
+
## Shared result before locale-aware fallback
|
|
23
|
+
|
|
24
|
+
Before the locale-aware visible-space fallback was introduced, all three content variants produced the same high-level outcome:
|
|
25
|
+
|
|
26
|
+
- English boundaries succeeded in `raw` and `parser`
|
|
27
|
+
- Japanese `spaces_both` succeeded in `raw` and `parser`
|
|
28
|
+
- Japanese `outer_zwsp` succeeded in `raw` and `parser`
|
|
29
|
+
- Japanese `tight`, `space_left`, and `space_right` failed in `raw`
|
|
30
|
+
- `parser` improved those Japanese boundary buckets from `0/5` to `4/5`
|
|
31
|
+
- The remaining failures were concentrated in `inner_code`
|
|
32
|
+
|
|
33
|
+
## Focused CJK result
|
|
34
|
+
|
|
35
|
+
Fixture:
|
|
36
|
+
|
|
37
|
+
- `tests/fixtures/slack_cjk_inner_code_matrix.md`
|
|
38
|
+
|
|
39
|
+
This focused matrix contained `ja`, `zh`, and `ko`, testing only:
|
|
40
|
+
|
|
41
|
+
- inner `plain`
|
|
42
|
+
- inner `code`
|
|
43
|
+
|
|
44
|
+
Boundary behavior after improvement:
|
|
45
|
+
|
|
46
|
+
- `ja`, `zh`, and `ko` all still succeeded for `outer_zwsp`
|
|
47
|
+
- `ja`, `zh`, and `ko` all still succeeded for `spaces_both`
|
|
48
|
+
- raw `tight` and raw `space_left` remained fragile across all three locales
|
|
49
|
+
- raw `space_right` remained fragile for `ja` and `zh`, but was already stable for `ko`
|
|
50
|
+
- after the locale-aware fallback, `parser` reached `2/2` success in every tested bucket for `ja`, `zh`, and `ko`
|
|
51
|
+
|
|
52
|
+
Current takeaway:
|
|
53
|
+
|
|
54
|
+
- Treating Chinese like Japanese is reasonable based on current Slack Web behavior.
|
|
55
|
+
- Korean still differs at the raw-rendering level, but the parser can now normalize all tested Korean buckets successfully with a lighter right-side spacing rule.
|
|
56
|
+
- The current parser strategy for nested inline code is:
|
|
57
|
+
- `ja` / `zh`: add visible spaces on whichever outer side is missing
|
|
58
|
+
- `ko`: ensure a visible trailing space when needed
|
|
59
|
+
- English-like boundaries: preserve the original outer formatting span
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# Slack Render Test Workflow
|
|
2
|
+
|
|
3
|
+
This repository includes a minimal local workflow for validating how Slack
|
|
4
|
+
actually renders generated Block Kit `markdown` and `table` output.
|
|
5
|
+
|
|
6
|
+
## Files
|
|
7
|
+
|
|
8
|
+
- `docs/slack-render-test-app-manifest.yaml`
|
|
9
|
+
- Minimal Slack App manifest for a test-only bot
|
|
10
|
+
- `.env.example`
|
|
11
|
+
- Example local environment variables
|
|
12
|
+
- `scripts/post_slack_render_test.py`
|
|
13
|
+
- Local CLI for posting test messages to Slack
|
|
14
|
+
|
|
15
|
+
## Local environment
|
|
16
|
+
|
|
17
|
+
Expected local-only environment variables:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
SLACK_BOT_TOKEN=xoxb-...
|
|
21
|
+
SLACK_TEST_CHANNEL_ID=CXXXXXXXX
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
`SLACK_BOT_TOKEN` is loaded from `.env` by default when using the script.
|
|
25
|
+
|
|
26
|
+
## Test channel
|
|
27
|
+
|
|
28
|
+
- Workspace: your Slack workspace
|
|
29
|
+
- Channel: your dedicated render-test channel
|
|
30
|
+
- Channel ID: e.g. `CXXXXXXXX`
|
|
31
|
+
|
|
32
|
+
The bot must already be installed and invited to the channel.
|
|
33
|
+
|
|
34
|
+
## Commands
|
|
35
|
+
|
|
36
|
+
Post a raw Slack `markdown` block without parser processing:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
python scripts/post_slack_render_test.py \
|
|
40
|
+
--mode raw \
|
|
41
|
+
--text 'from **bold**.'
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Post using `slack_markdown_parser`:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
python scripts/post_slack_render_test.py \
|
|
48
|
+
--mode parser \
|
|
49
|
+
--text 'from **bold**.'
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Preview generated payloads without calling Slack:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
python scripts/post_slack_render_test.py \
|
|
56
|
+
--mode parser \
|
|
57
|
+
--text 'from **bold**.' \
|
|
58
|
+
--dry-run
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Post a markdown file:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
python scripts/post_slack_render_test.py \
|
|
65
|
+
--mode parser \
|
|
66
|
+
--input-file tests/fixtures/llm_markdown_p0_corpus.md
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Generate nested modifier matrix fixtures:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
python scripts/generate_nested_modifier_matrix.py --content-variant plain
|
|
73
|
+
python scripts/generate_nested_modifier_matrix.py --content-variant parens
|
|
74
|
+
python scripts/generate_nested_modifier_matrix.py --content-variant quotes
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Generate focused CJK nested-code fixtures:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
python scripts/generate_nested_modifier_matrix.py \
|
|
81
|
+
--content-variant plain \
|
|
82
|
+
--locales ja,zh,ko \
|
|
83
|
+
--inners plain,code \
|
|
84
|
+
--output tests/fixtures/slack_cjk_inner_code_matrix.md
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Output
|
|
88
|
+
|
|
89
|
+
Each posted message prints JSON like:
|
|
90
|
+
|
|
91
|
+
```json
|
|
92
|
+
{
|
|
93
|
+
"message_index": 1,
|
|
94
|
+
"channel": "CXXXXXXXX",
|
|
95
|
+
"ts": "1773051865.764719",
|
|
96
|
+
"mode": "parser",
|
|
97
|
+
"permalink": "https://your-workspace.slack.com/archives/CXXXXXXXX/p1234567890123456"
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Use the `permalink` to open the exact message in Slack and verify rendering in the
|
|
102
|
+
web UI or via Playwright.
|
|
103
|
+
|
|
104
|
+
## Recommended comparison flow
|
|
105
|
+
|
|
106
|
+
1. Post the same markdown once with `--mode raw`.
|
|
107
|
+
2. Post the same markdown once with `--mode parser`.
|
|
108
|
+
3. Open both permalinks in Slack.
|
|
109
|
+
4. Compare visible rendering, especially for:
|
|
110
|
+
- bold/italic/strike recognition
|
|
111
|
+
- punctuation boundaries
|
|
112
|
+
- Japanese vs English surrounding text
|
|
113
|
+
- fallback text behavior when relevant
|
|
114
|
+
|
|
115
|
+
For desktop/mobile spot checks, use:
|
|
116
|
+
|
|
117
|
+
- `docs/slack-client-manual-checklist.md`
|
|
@@ -12,6 +12,13 @@
|
|
|
12
12
|
- Slack Block Kit ブロック(`markdown` / `table`)
|
|
13
13
|
- 複数テーブル入力時は「1メッセージ1テーブル」を満たすメッセージ群
|
|
14
14
|
|
|
15
|
+
## 設計上の到達点
|
|
16
|
+
|
|
17
|
+
このパーサーは、CommonMark 全体や HTML / リッチドキュメントの完全再現を目標にはしません。
|
|
18
|
+
目的は、Slack Block Kit の `markdown` / `table` ブロックで送ったときに自然に読めるメッセージを作ることです。
|
|
19
|
+
|
|
20
|
+
Markdown としての厳密さより Slack 上での読みやすさが優先される場合は、Slack 側で安定して読める表現を優先します。
|
|
21
|
+
|
|
15
22
|
## 変換パイプライン
|
|
16
23
|
|
|
17
24
|
`convert_markdown_to_slack_blocks` の処理順序:
|
|
@@ -28,6 +35,35 @@
|
|
|
28
35
|
`convert_markdown_to_slack_messages` は上記の結果を「1メッセージ1テーブル」制約に沿って分割します。
|
|
29
36
|
`convert_markdown_to_slack_payloads` は、同じ分割結果に `chat.postMessage.text` 用 fallback を付けた payload 群を返します。
|
|
30
37
|
|
|
38
|
+
## 実測ベースの Slack レンダラ挙動
|
|
39
|
+
|
|
40
|
+
以下は、生成された Block Kit payload を実際の Slack クライアントで確認したときの挙動です。
|
|
41
|
+
|
|
42
|
+
### Slack が比較的きれいに表示できるもの
|
|
43
|
+
|
|
44
|
+
- asterisk 装飾: `*italic*`, `**bold**`
|
|
45
|
+
- 取消線: `~~strike~~`
|
|
46
|
+
- インラインコードとフェンスドコード
|
|
47
|
+
- bare URL, autolink, Markdown link, 参照リンク, mailto link
|
|
48
|
+
- 箇条書き, 番号付きリスト, タスクリスト, 単純な1段引用
|
|
49
|
+
- Slack `table` ブロック
|
|
50
|
+
|
|
51
|
+
### Slack 自体の制約として残るもの
|
|
52
|
+
|
|
53
|
+
- `#`, `##`, `###` や setext 見出しは、本当の見出しレベルではなくプレーンテキスト寄りに表示される
|
|
54
|
+
- 多段引用はフル Markdown レンダラほどきれいに出ない
|
|
55
|
+
- 水平線は semantic な区切りではなく、線テキスト寄りの見え方になる
|
|
56
|
+
- Markdown 画像記法は `markdown` ブロック内では埋め込み画像にならない
|
|
57
|
+
- 数式, 生 HTML, HTML comment, `<details>`, admonition 記法, Mermaid は特別なリッチ表示にならない
|
|
58
|
+
|
|
59
|
+
### このパーサーが補正するもの
|
|
60
|
+
|
|
61
|
+
- `_..._` / `__...__` を Slack 互換の `*...*` / `**...**` に正規化する
|
|
62
|
+
- bare URL は Slack の `markdown` ブロックで安定する autolink 形式(`<https://...>`)へ正規化する
|
|
63
|
+
- 崩れた Markdown テーブルを補完して `table` ブロックへ変換する
|
|
64
|
+
- フェンスドコード内の table 風行をテーブル解析対象から除外する
|
|
65
|
+
- `<foo>` や生 HTML 風タグのような不正な Slack angle token を無害化する
|
|
66
|
+
|
|
31
67
|
## Slack 向けサニタイズルール
|
|
32
68
|
|
|
33
69
|
`sanitize_slack_text` の挙動:
|
|
@@ -105,7 +141,7 @@ LLM は外枠パイプの省略、セパレータ行の欠落、列数の不一
|
|
|
105
141
|
|
|
106
142
|
### 目的
|
|
107
143
|
|
|
108
|
-
日本語等の語間スペースがない文で装飾記号が隣接文字と結合し、Slack
|
|
144
|
+
日本語等の語間スペースがない文で装飾記号が隣接文字と結合し、Slack のレンダリングが崩れる問題を回避します。基本はゼロ幅スペースで境界を補強し、CJK の密着文脈でインラインコードを内包する装飾だけは、Slack 実表示を優先して可視スペースへフォールバックします。
|
|
109
145
|
|
|
110
146
|
### 対象パターン
|
|
111
147
|
|
|
@@ -120,6 +156,10 @@ LLM は外枠パイプの省略、セパレータ行の欠落、列数の不一
|
|
|
120
156
|
|
|
121
157
|
- **フェンスドコードブロック**(`` ``` ... ``` `` および `~~~ ... ~~~`)内は一切変更しない
|
|
122
158
|
- インラインコード(`` `...` ``)は除外**しない**(付与対象)
|
|
159
|
+
- `**bold**`、`*italic*`、`~~strike~~` の内側にネストしたインラインコードには個別の ZWSP を付与しない
|
|
160
|
+
- 英語系の境界では外側の装飾トークンはそのまま維持する
|
|
161
|
+
- 日本語・中国語の密着境界では、外側の装飾トークンの前後で不足している側に可視スペースを補う
|
|
162
|
+
- 韓国語の密着境界では、必要に応じて後ろ側の可視スペースを補い、右側に空白があるケースはそのまま維持する
|
|
123
163
|
|
|
124
164
|
## ZWSP 除去ルール
|
|
125
165
|
|
|
@@ -144,6 +184,7 @@ LLM は外枠パイプの省略、セパレータ行の欠落、列数の不一
|
|
|
144
184
|
`build_fallback_text_from_blocks` は `chat.postMessage.text` に設定する通知プレビュー用テキストを生成:
|
|
145
185
|
|
|
146
186
|
- `markdown` ブロック → ZWSP を除去したテキスト
|
|
187
|
+
- nested inline code の表示安定化のために一時的に入れた可視スペースは、fallback では自然な文に戻す
|
|
147
188
|
- `table` ブロック → 各行のセルテキストを ` | ` で連結
|
|
148
189
|
- 各ブロックの出力を空行で区切って結合
|
|
149
190
|
|
|
@@ -158,3 +199,4 @@ LLM は外枠パイプの省略、セパレータ行の欠落、列数の不一
|
|
|
158
199
|
- `mrkdwn` 文字列の生成
|
|
159
200
|
- 完全な Markdown AST の再現
|
|
160
201
|
- HTML レンダリング互換
|
|
202
|
+
- Slack `markdown` ブロックが本来対応していない構文に、独自のリッチ表示を与えること
|
|
@@ -12,6 +12,13 @@ This document defines the conversion behavior of `slack-markdown-parser`.
|
|
|
12
12
|
- Slack Block Kit blocks (`markdown` / `table`)
|
|
13
13
|
- When the input contains multiple tables, a list of messages that satisfies the "one table per message" rule
|
|
14
14
|
|
|
15
|
+
## Design target
|
|
16
|
+
|
|
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.
|
|
19
|
+
|
|
20
|
+
When Markdown fidelity and Slack readability conflict, readable Slack output takes priority.
|
|
21
|
+
|
|
15
22
|
## Conversion pipeline
|
|
16
23
|
|
|
17
24
|
Processing order in `convert_markdown_to_slack_blocks`:
|
|
@@ -28,6 +35,35 @@ Processing order in `convert_markdown_to_slack_blocks`:
|
|
|
28
35
|
`convert_markdown_to_slack_messages` then splits the resulting block list to satisfy the "one table per message" constraint.
|
|
29
36
|
`convert_markdown_to_slack_payloads` returns the same split blocks plus fallback `text` values ready for `chat.postMessage`.
|
|
30
37
|
|
|
38
|
+
## Observed Slack renderer behavior
|
|
39
|
+
|
|
40
|
+
The following behaviors are based on practical validation against real Slack clients using the generated Block Kit payloads.
|
|
41
|
+
|
|
42
|
+
### Behaviors that Slack currently renders well
|
|
43
|
+
|
|
44
|
+
- Asterisk emphasis: `*italic*`, `**bold**`
|
|
45
|
+
- Strikethrough: `~~strike~~`
|
|
46
|
+
- Inline code and fenced code blocks
|
|
47
|
+
- Bare URLs, autolinks, Markdown links, reference-style links, and mailto links
|
|
48
|
+
- Bullet lists, ordered lists, task lists, and simple one-level blockquotes
|
|
49
|
+
- Slack `table` blocks
|
|
50
|
+
|
|
51
|
+
### Behaviors limited by Slack itself
|
|
52
|
+
|
|
53
|
+
- ATX headings (`#`, `##`, `###`) and setext headings render as plain text rather than true heading levels
|
|
54
|
+
- Nested blockquotes are weaker than in full Markdown renderers
|
|
55
|
+
- Horizontal rules render more like visible line text than semantic separators
|
|
56
|
+
- Markdown image syntax does not become an embedded image inside `markdown` blocks
|
|
57
|
+
- Math, raw HTML, HTML comments, `<details>`, admonition syntax, and Mermaid do not receive special rich rendering
|
|
58
|
+
|
|
59
|
+
### Behaviors this parser compensates for
|
|
60
|
+
|
|
61
|
+
- `_..._` and `__...__` are normalized into Slack-friendly `*...*` and `**...**`
|
|
62
|
+
- Bare URLs are wrapped into Slack-friendly autolink form (`<https://...>`) before `markdown` block delivery
|
|
63
|
+
- Malformed Markdown tables are repaired before `table` block generation
|
|
64
|
+
- Table-like rows inside fenced code blocks are kept out of table parsing
|
|
65
|
+
- Unsupported Slack angle-bracket tokens such as `<foo>` or raw HTML-like tags are neutralized
|
|
66
|
+
|
|
31
67
|
## Slack text sanitize rules
|
|
32
68
|
|
|
33
69
|
Behavior of `sanitize_slack_text`:
|
|
@@ -104,7 +140,7 @@ Behavior of `add_zero_width_spaces_to_markdown`:
|
|
|
104
140
|
|
|
105
141
|
### Purpose
|
|
106
142
|
|
|
107
|
-
In languages such as Japanese that do not use spaces between words, formatting markers can attach directly to surrounding characters and break Slack rendering. This library inserts zero-width spaces
|
|
143
|
+
In languages such as Japanese that do not use spaces between words, formatting markers can attach directly to surrounding characters and break Slack rendering. This library primarily inserts zero-width spaces so Slack gets clearer formatting boundaries without changing the visible layout. For some nested inline-code emphasis cases in dense CJK text, it falls back to visible spaces because current Slack rendering is more reliable with explicit spacing.
|
|
108
144
|
|
|
109
145
|
### Target patterns
|
|
110
146
|
|
|
@@ -119,6 +155,10 @@ For each formatting token below, if either adjacent side is not a space, tab, ne
|
|
|
119
155
|
|
|
120
156
|
- Fenced code blocks (both `` ``` ... ``` `` and `~~~ ... ~~~`) are never modified
|
|
121
157
|
- Inline code (`` `...` ``) is not excluded; it is part of the target set above
|
|
158
|
+
- Inline code nested inside `**bold**`, `*italic*`, or `~~strike~~` is left untouched.
|
|
159
|
+
- For English-like boundaries around those nested combinations, the outer formatting span is preserved as-is.
|
|
160
|
+
- For dense Japanese/Chinese boundaries, visible spaces are inserted on the missing outer side(s) around the outer formatting span.
|
|
161
|
+
- For dense Korean boundaries, a visible trailing space is inserted when needed, while right-space cases are otherwise preserved because Slack already renders them more reliably.
|
|
122
162
|
|
|
123
163
|
## ZWSP removal rules
|
|
124
164
|
|
|
@@ -143,6 +183,7 @@ For each formatting token below, if either adjacent side is not a space, tab, ne
|
|
|
143
183
|
`build_fallback_text_from_blocks` generates preview text for `chat.postMessage.text` as follows:
|
|
144
184
|
|
|
145
185
|
- `markdown` blocks: text with ZWSP removed
|
|
186
|
+
- Parser-inserted visible spaces used only to stabilize nested inline-code emphasis are normalized back out when building plain fallback text
|
|
146
187
|
- `table` blocks: join each row's cell text with ` | `
|
|
147
188
|
- Join block outputs with blank lines between them
|
|
148
189
|
|
|
@@ -157,3 +198,4 @@ For the same input, the library always returns the same output regardless of env
|
|
|
157
198
|
- Generating Slack `mrkdwn` strings
|
|
158
199
|
- Reconstructing a full Markdown AST
|
|
159
200
|
- Matching HTML rendering behavior
|
|
201
|
+
- Recreating rich rendering for constructs Slack does not natively support in `markdown` blocks
|