slack-markdown-parser 2.0.2__tar.gz → 2.2.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.
- slack_markdown_parser-2.2.1/CHANGELOG.md +62 -0
- slack_markdown_parser-2.2.1/CONTRIBUTING.md +53 -0
- slack_markdown_parser-2.2.1/MANIFEST.in +10 -0
- {slack_markdown_parser-2.0.2/slack_markdown_parser.egg-info → slack_markdown_parser-2.2.1}/PKG-INFO +17 -8
- slack_markdown_parser-2.2.1/README-ja.md +154 -0
- {slack_markdown_parser-2.0.2 → slack_markdown_parser-2.2.1}/README.md +16 -7
- slack_markdown_parser-2.2.1/docs/spec-ja.md +160 -0
- slack_markdown_parser-2.2.1/docs/spec.md +159 -0
- {slack_markdown_parser-2.0.2 → slack_markdown_parser-2.2.1}/pyproject.toml +4 -1
- {slack_markdown_parser-2.0.2 → slack_markdown_parser-2.2.1}/slack_markdown_parser/__init__.py +7 -1
- {slack_markdown_parser-2.0.2 → slack_markdown_parser-2.2.1}/slack_markdown_parser/converter.py +294 -50
- slack_markdown_parser-2.2.1/slack_markdown_parser/py.typed +1 -0
- {slack_markdown_parser-2.0.2 → slack_markdown_parser-2.2.1/slack_markdown_parser.egg-info}/PKG-INFO +17 -8
- {slack_markdown_parser-2.0.2 → slack_markdown_parser-2.2.1}/slack_markdown_parser.egg-info/SOURCES.txt +10 -1
- slack_markdown_parser-2.2.1/tests/fixtures/llm_markdown_p0_corpus.md +121 -0
- {slack_markdown_parser-2.0.2 → slack_markdown_parser-2.2.1}/tests/test_converter.py +170 -2
- slack_markdown_parser-2.2.1/tests/test_llm_markdown_p0_corpus.py +49 -0
- {slack_markdown_parser-2.0.2 → slack_markdown_parser-2.2.1}/LICENSE +0 -0
- {slack_markdown_parser-2.0.2 → slack_markdown_parser-2.2.1}/setup.cfg +0 -0
- {slack_markdown_parser-2.0.2 → slack_markdown_parser-2.2.1}/slack_markdown_parser.egg-info/dependency_links.txt +0 -0
- {slack_markdown_parser-2.0.2 → slack_markdown_parser-2.2.1}/slack_markdown_parser.egg-info/requires.txt +0 -0
- {slack_markdown_parser-2.0.2 → slack_markdown_parser-2.2.1}/slack_markdown_parser.egg-info/top_level.txt +0 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on Keep a Changelog, and the project follows Semantic Versioning.
|
|
6
|
+
|
|
7
|
+
## [Unreleased]
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- Added a contributor guide, issue templates, and a pull request template.
|
|
12
|
+
- Added the `py.typed` marker and packaging rules for docs and tests in source distributions.
|
|
13
|
+
|
|
14
|
+
### Changed
|
|
15
|
+
|
|
16
|
+
- CI now runs the test suite on Python 3.10, 3.11, 3.12, and 3.13.
|
|
17
|
+
- `.gitignore` no longer ignores the entire `tests/` directory, so new tests and sample fixtures can be tracked.
|
|
18
|
+
|
|
19
|
+
## [2.2.1] - 2026-03-07
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
|
|
23
|
+
- Normalized underscore emphasis (`_..._`, `__...__`) into Slack-compatible asterisk emphasis before table parsing.
|
|
24
|
+
- Excluded fenced code blocks from table normalization and segment splitting so table-like rows inside code fences stay in `markdown` blocks.
|
|
25
|
+
- Extended fenced-code preservation to tilde fences (`~~~ ... ~~~`) when inserting ZWSP.
|
|
26
|
+
- Improved heading-plus-table rescue so inputs like `### Heading ... Header A | Header B` preserve multi-word first header cells more naturally.
|
|
27
|
+
|
|
28
|
+
## [2.0.2] - 2026-03-06
|
|
29
|
+
|
|
30
|
+
### Changed
|
|
31
|
+
|
|
32
|
+
- Improved public API wording and refreshed the English and Japanese README files.
|
|
33
|
+
- Clarified project scope for `mrkdwn`-only clients and fallback text behavior.
|
|
34
|
+
- Refined validation samples and screenshots in the documentation.
|
|
35
|
+
|
|
36
|
+
### Fixed
|
|
37
|
+
|
|
38
|
+
- Improved ZWSP padding around punctuation-adjacent Markdown.
|
|
39
|
+
- Expanded parser edge-case handling and related documentation.
|
|
40
|
+
|
|
41
|
+
## [2.0.1] - 2026-03-05
|
|
42
|
+
|
|
43
|
+
### Added
|
|
44
|
+
|
|
45
|
+
- Added initial GitHub Actions coverage for tests and package builds.
|
|
46
|
+
- Added OSS-facing documentation and a real rendering example in the README.
|
|
47
|
+
|
|
48
|
+
### Changed
|
|
49
|
+
|
|
50
|
+
- Trimmed the repository to the core distributable package and refreshed maintainer contact details.
|
|
51
|
+
- Updated GitHub Actions dependencies to newer major versions.
|
|
52
|
+
|
|
53
|
+
### Fixed
|
|
54
|
+
|
|
55
|
+
- Added ZWSP padding for inline code markers when adjacent to surrounding text.
|
|
56
|
+
|
|
57
|
+
## [2.0.0] - 2026-03-05
|
|
58
|
+
|
|
59
|
+
### Added
|
|
60
|
+
|
|
61
|
+
- Published the packaged OSS release of `slack-markdown-parser`.
|
|
62
|
+
- Added packaging metadata, documentation, and review/reference materials for the open-source release.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Thanks for your interest in improving `slack-markdown-parser`.
|
|
4
|
+
Small fixes, bug reports, documentation updates, and tests are all welcome.
|
|
5
|
+
English and Japanese contributions are both welcome.
|
|
6
|
+
|
|
7
|
+
## Development setup
|
|
8
|
+
|
|
9
|
+
This project supports Python 3.10 through 3.13.
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
python -m venv .venv
|
|
13
|
+
source .venv/bin/activate
|
|
14
|
+
python -m pip install --upgrade pip
|
|
15
|
+
pip install -e ".[dev]"
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Local checks
|
|
19
|
+
|
|
20
|
+
Run these commands before opening a pull request:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
python -m pytest -q
|
|
24
|
+
python -m ruff check .
|
|
25
|
+
python -m black --check .
|
|
26
|
+
python -m build
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
If you are changing Markdown parsing behavior, please add or update automated tests in `tests/`.
|
|
30
|
+
|
|
31
|
+
## Pull requests
|
|
32
|
+
|
|
33
|
+
- Keep changes focused and explain the user-facing impact.
|
|
34
|
+
- Add or update tests when parser behavior changes.
|
|
35
|
+
- Update `README.md`, `README-ja.md`, or `docs/spec*.md` when public behavior or examples change.
|
|
36
|
+
- Conventional Commits are encouraged for commit messages, but not required for contributors.
|
|
37
|
+
- Make sure CI passes before requesting review.
|
|
38
|
+
|
|
39
|
+
## Reporting issues
|
|
40
|
+
|
|
41
|
+
Use the GitHub issue templates when possible.
|
|
42
|
+
Helpful reports usually include:
|
|
43
|
+
|
|
44
|
+
- A short description of the problem
|
|
45
|
+
- A minimal Markdown sample that reproduces it
|
|
46
|
+
- Expected output and actual output
|
|
47
|
+
- Python version and installation method
|
|
48
|
+
- Slack rendering details if the issue is UI-specific
|
|
49
|
+
|
|
50
|
+
## Release notes
|
|
51
|
+
|
|
52
|
+
Project maintainers keep release history in `CHANGELOG.md`.
|
|
53
|
+
If your pull request affects users, please include a short changelog note in the PR description.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
include LICENSE
|
|
2
|
+
include README.md
|
|
3
|
+
include README-ja.md
|
|
4
|
+
include CONTRIBUTING.md
|
|
5
|
+
include CHANGELOG.md
|
|
6
|
+
recursive-include docs *.md
|
|
7
|
+
prune docs/_internal
|
|
8
|
+
recursive-include tests *.py *.md
|
|
9
|
+
recursive-include slack_markdown_parser py.typed
|
|
10
|
+
global-exclude __pycache__ *.py[cod]
|
{slack_markdown_parser-2.0.2/slack_markdown_parser.egg-info → slack_markdown_parser-2.2.1}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: slack-markdown-parser
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.2.1
|
|
4
4
|
Summary: Convert LLM Markdown into Slack Block Kit markdown/table messages
|
|
5
5
|
Author: darkgaldragon
|
|
6
6
|
License-Expression: MIT
|
|
@@ -57,8 +57,11 @@ This library leans on Slack Block Kit's `markdown` block for standard Markdown a
|
|
|
57
57
|
- Convert Markdown tables into Slack `table` blocks
|
|
58
58
|
- Repair common LLM table issues such as missing outer pipes, missing separator rows, mismatched column counts, and empty cells
|
|
59
59
|
- Split output into multiple Slack messages when needed to satisfy Slack's "one table per message" constraint
|
|
60
|
+
- Sanitize ANSI/control characters and neutralize invalid Slack angle-bracket tokens before block generation
|
|
60
61
|
- Add ZWSP around inline formatting tokens to reduce rendering issues outside fenced code blocks
|
|
62
|
+
- Support Markdown and Slack-style links inside table cells
|
|
61
63
|
- Build fallback text for `chat.postMessage.text` from generated blocks
|
|
64
|
+
- Accept raw LLM Markdown without tightly constraining the model prompt, using best-effort sanitize and table repair before Slack delivery
|
|
62
65
|
|
|
63
66
|
## Requirements
|
|
64
67
|
|
|
@@ -75,8 +78,7 @@ pip install slack-markdown-parser
|
|
|
75
78
|
|
|
76
79
|
```python
|
|
77
80
|
from slack_markdown_parser import (
|
|
78
|
-
|
|
79
|
-
convert_markdown_to_slack_messages,
|
|
81
|
+
convert_markdown_to_slack_payloads,
|
|
80
82
|
)
|
|
81
83
|
|
|
82
84
|
markdown = """
|
|
@@ -88,11 +90,7 @@ markdown = """
|
|
|
88
90
|
| UI | *In progress* |
|
|
89
91
|
"""
|
|
90
92
|
|
|
91
|
-
for
|
|
92
|
-
payload = {
|
|
93
|
-
"blocks": blocks,
|
|
94
|
-
"text": build_fallback_text_from_blocks(blocks) or "report",
|
|
95
|
-
}
|
|
93
|
+
for payload in convert_markdown_to_slack_payloads(markdown):
|
|
96
94
|
print(payload)
|
|
97
95
|
```
|
|
98
96
|
|
|
@@ -146,6 +144,7 @@ Example Slack bot rendering (`markdown` + `table` blocks):
|
|
|
146
144
|
| Function | Description |
|
|
147
145
|
|---|---|
|
|
148
146
|
| `convert_markdown_to_slack_messages(markdown_text) -> list[list[dict]]` | Convert Markdown into Slack messages already split around table blocks. |
|
|
147
|
+
| `convert_markdown_to_slack_payloads(markdown_text) -> list[dict]` | Convert Markdown into Slack-ready payloads with both `blocks` and fallback `text`. |
|
|
149
148
|
| `convert_markdown_to_slack_blocks(markdown_text) -> list[dict]` | Convert Markdown into a flat Block Kit block list. |
|
|
150
149
|
| `build_fallback_text_from_blocks(blocks) -> str` | Build fallback text suitable for `chat.postMessage.text`. |
|
|
151
150
|
| `blocks_to_plain_text(blocks) -> str` | Convert blocks into plain text. |
|
|
@@ -157,6 +156,7 @@ Example Slack bot rendering (`markdown` + `table` blocks):
|
|
|
157
156
|
| `normalize_markdown_tables(markdown_text) -> str` | Normalize Markdown table syntax before conversion. |
|
|
158
157
|
| `add_zero_width_spaces_to_markdown(text) -> str` | Insert ZWSP around formatting tokens where Slack needs stronger boundaries. |
|
|
159
158
|
| `decode_html_entities(text) -> str` | Decode HTML entities before parsing. |
|
|
159
|
+
| `sanitize_slack_text(text) -> str` | Remove ANSI/control noise and neutralize invalid Slack angle-bracket tokens. |
|
|
160
160
|
| `strip_zero_width_spaces(text) -> str` | Remove ZWSP (`U+200B`) and BOM (`U+FEFF`) while preserving join-control characters such as ZWJ. |
|
|
161
161
|
|
|
162
162
|
### Lower-level exported helpers
|
|
@@ -179,6 +179,15 @@ These are also part of the public package surface:
|
|
|
179
179
|
- Generating Slack `mrkdwn` strings
|
|
180
180
|
- Supporting clients or MCP tools that can only send `mrkdwn`
|
|
181
181
|
|
|
182
|
+
## Contributing
|
|
183
|
+
|
|
184
|
+
Contributions, bug reports, and documentation improvements are welcome.
|
|
185
|
+
Please read [CONTRIBUTING.md](CONTRIBUTING.md) before opening an issue or pull request.
|
|
186
|
+
|
|
187
|
+
## Changelog
|
|
188
|
+
|
|
189
|
+
Version history is maintained in [CHANGELOG.md](CHANGELOG.md).
|
|
190
|
+
|
|
182
191
|
## Contact
|
|
183
192
|
|
|
184
193
|
- GitHub Issues / Pull Requests
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# slack-markdown-parser
|
|
2
|
+
|
|
3
|
+
LLM が生成する標準的な Markdown を Slack Block Kit(`markdown` + `table` ブロック)に変換する Python ライブラリです。
|
|
4
|
+
|
|
5
|
+
## 背景
|
|
6
|
+
|
|
7
|
+
Slack で AI BOT を運用する場合、従来は Slack 独自の `mrkdwn` 形式に変換していましたが、以下の課題がありました。
|
|
8
|
+
|
|
9
|
+
- **変換コスト**: LLM は標準 Markdown を出力するため、`mrkdwn` に合わせる変換ロジックやプロンプト制御が必要
|
|
10
|
+
- **装飾崩れ**: 日本語のように語間スペースがない文では、`mrkdwn` の装飾記号(`*`, `~` など)が正しくレンダリングされず記号がそのまま露出することがあり、ロジックやプロンプトでの制御も難しい
|
|
11
|
+
- **テーブル非対応**: `mrkdwn` にはテーブル構文がなく、リストへ変換するなどの代替処理が必要
|
|
12
|
+
|
|
13
|
+
## 設計方針
|
|
14
|
+
|
|
15
|
+
Slack Block Kit の `markdown` ブロック(標準 Markdown 構文をそのまま受け付ける)と `table` ブロックを活用し、上記の課題を解消します。
|
|
16
|
+
|
|
17
|
+
| 課題 | 解決手段 |
|
|
18
|
+
|---|---|
|
|
19
|
+
| 変換コスト | `markdown` ブロックが標準 Markdown をそのまま受け付けるため、LLM 出力を変換せず利用可能 |
|
|
20
|
+
| 装飾崩れ | 装飾記号の前後に ZWSP(ゼロ幅スペース U+200B)を自動挿入してレンダリングを安定化。通常の半角スペースではなくゼロ幅スペースを使うことで、見た目上の不自然な空白を生じさせずに Slack の装飾解析を補助する |
|
|
21
|
+
| テーブル非対応 | Markdown テーブルを検知して `table` ブロックに変換。LLM の出力する多様なテーブル記法の揺れも自動補完し `invalid_blocks` エラーを回避 |
|
|
22
|
+
|
|
23
|
+
## 主な機能
|
|
24
|
+
|
|
25
|
+
- 標準 Markdown テキストを `markdown` ブロックに変換
|
|
26
|
+
- Markdown テーブルを `table` ブロックに変換(セル内の太字・斜体・取消線・インラインコードを認識)
|
|
27
|
+
- LLM が生成する多様な Markdown テーブルで起こり得る記法の揺れ(外枠パイプ不足、セパレータ行不足、列数不一致、空セル)を検知し自動補完。Slack `table` ブロックの `invalid_blocks` エラーを未然に回避
|
|
28
|
+
- テーブルごとにメッセージを自動分割(Slack の「1メッセージ1テーブル」制約に対応)
|
|
29
|
+
- ANSI escape / 制御文字を除去し、不正な Slack 角括弧トークンを自動で無害化
|
|
30
|
+
- 装飾記号の前後に ZWSP を付与して表示崩れを抑制(フェンスドコードブロック内は除外、インラインコードは付与対象)
|
|
31
|
+
- テーブルセル内の Markdown link / Slack link を認識
|
|
32
|
+
- `chat.postMessage.text` 用の fallback テキストを生成(ブロック内容をプレーンテキスト化して通知プレビュー等に利用)
|
|
33
|
+
- モデル側で Markdown を厳密に制御しなくてもよいよう、Slack 送信前にベストエフォートでサニタイズとテーブル補完を行う
|
|
34
|
+
|
|
35
|
+
## 利用前提
|
|
36
|
+
|
|
37
|
+
- Slack Block Kit の `blocks` で `markdown` / `table` ブロックを送信できる実装が必要です。
|
|
38
|
+
- `text` / `mrkdwn` のみ送信可能な経路(例: 一部の Slack MCP ツール)では利用できません。
|
|
39
|
+
|
|
40
|
+
## インストール
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
pip install slack-markdown-parser
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## 最小利用例
|
|
47
|
+
|
|
48
|
+
```python
|
|
49
|
+
from slack_markdown_parser import (
|
|
50
|
+
convert_markdown_to_slack_payloads,
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
markdown = """
|
|
54
|
+
# Weekly Report
|
|
55
|
+
|
|
56
|
+
| Team | Status |
|
|
57
|
+
|---|---|
|
|
58
|
+
| API | **On track** |
|
|
59
|
+
| UI | *In progress* |
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
for payload in convert_markdown_to_slack_payloads(markdown):
|
|
63
|
+
print(payload)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
`convert_markdown_to_slack_messages` は、複数テーブルを含む入力を Slack 制約に合わせて複数メッセージへ分割します。
|
|
67
|
+
|
|
68
|
+
## 入出力イメージ
|
|
69
|
+
|
|
70
|
+
検証テキスト:
|
|
71
|
+
|
|
72
|
+
````markdown
|
|
73
|
+
# 週次プロダクト更新
|
|
74
|
+
|
|
75
|
+
今週は**検索速度改善**と*UI調整*を進めました。旧仕様は~~廃止予定~~です。
|
|
76
|
+
詳細ログIDは`run-20260305-02`です。
|
|
77
|
+
参考: https://example.com/changelog
|
|
78
|
+
|
|
79
|
+
- APIの**レスポンス改善**
|
|
80
|
+
- *キャッシュヒット率*を改善
|
|
81
|
+
- タイムアウト設定を調整
|
|
82
|
+
- バッチ処理の安定化
|
|
83
|
+
- リトライ回数を統一
|
|
84
|
+
- ドキュメント更新
|
|
85
|
+
|
|
86
|
+
カテゴリ | 状況 | 担当
|
|
87
|
+
API | **進行中** | Team A
|
|
88
|
+
UI | *確認中* | Team B
|
|
89
|
+
QA | ~~保留~~ | Team C
|
|
90
|
+
|
|
91
|
+
> 注意: 本番反映は 3/8 10:00 JST を予定
|
|
92
|
+
|
|
93
|
+
1. リリースノート最終確認
|
|
94
|
+
1. 変更点の表記統一
|
|
95
|
+
2. 影響範囲の追記
|
|
96
|
+
2. 監視アラートしきい値調整
|
|
97
|
+
1. `warning`閾値の更新
|
|
98
|
+
3. QA再確認
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
./deploy.sh production
|
|
102
|
+
```
|
|
103
|
+
````
|
|
104
|
+
|
|
105
|
+
実際のSlack BOTでの表示例(`markdown` + `table` ブロック):
|
|
106
|
+
|
|
107
|
+

|
|
108
|
+
|
|
109
|
+
## ライブラリの公開インターフェース
|
|
110
|
+
|
|
111
|
+
### メイン関数(公開関数)
|
|
112
|
+
|
|
113
|
+
| 関数 | 説明 |
|
|
114
|
+
|---|---|
|
|
115
|
+
| `convert_markdown_to_slack_messages(markdown_text) → list[list[dict]]` | Markdown をテーブル分割済みのメッセージ群に変換(主要エントリポイント) |
|
|
116
|
+
| `convert_markdown_to_slack_payloads(markdown_text) → list[dict]` | `blocks` と fallback `text` を含む Slack 送信用 payload 群へ変換 |
|
|
117
|
+
| `convert_markdown_to_slack_blocks(markdown_text) → list[dict]` | Markdown を Block Kit ブロックのリストに変換 |
|
|
118
|
+
| `build_fallback_text_from_blocks(blocks) → str` | ブロックから `chat.postMessage.text` 用 fallback テキストを生成 |
|
|
119
|
+
| `blocks_to_plain_text(blocks) → str` | ブロックからプレーンテキストを生成 |
|
|
120
|
+
|
|
121
|
+
### ユーティリティ関数(公開関数)
|
|
122
|
+
|
|
123
|
+
| 関数 | 説明 |
|
|
124
|
+
|---|---|
|
|
125
|
+
| `normalize_markdown_tables(markdown_text) → str` | テーブル記法を正規化(パイプ補完、セパレータ生成、列数調整) |
|
|
126
|
+
| `add_zero_width_spaces_to_markdown(text) → str` | 装飾記号の前後に ZWSP を挿入(フェンスドコードブロック内は除外) |
|
|
127
|
+
| `decode_html_entities(text) → str` | HTML エンティティをデコード |
|
|
128
|
+
| `sanitize_slack_text(text) → str` | ANSI / 制御文字を除去し、不正な Slack 角括弧トークンを無害化 |
|
|
129
|
+
| `strip_zero_width_spaces(text) → str` | ZWSP (U+200B) と BOM (U+FEFF) を除去(ZWJ 等の結合制御文字は保持) |
|
|
130
|
+
|
|
131
|
+
## 仕様
|
|
132
|
+
|
|
133
|
+
- 挙動仕様: [docs/spec-ja.md](docs/spec-ja.md)
|
|
134
|
+
- 非対応:
|
|
135
|
+
- `mrkdwn` 文字列の生成
|
|
136
|
+
- `mrkdwn` のみ送信可能なクライアント/MCP ツール
|
|
137
|
+
|
|
138
|
+
## コントリビュート
|
|
139
|
+
|
|
140
|
+
不具合報告、ドキュメント改善、コードの提案を歓迎します。
|
|
141
|
+
Issue / Pull Request を作成する前に [CONTRIBUTING.md](CONTRIBUTING.md) を参照してください。
|
|
142
|
+
|
|
143
|
+
## 変更履歴
|
|
144
|
+
|
|
145
|
+
リリース履歴は [CHANGELOG.md](CHANGELOG.md) で管理しています。
|
|
146
|
+
|
|
147
|
+
## 連絡先
|
|
148
|
+
|
|
149
|
+
- GitHub Issue / Pull Request
|
|
150
|
+
- X: [@darkgaldragon](https://x.com/darkgaldragon)
|
|
151
|
+
|
|
152
|
+
## ライセンス
|
|
153
|
+
|
|
154
|
+
MIT
|
|
@@ -26,8 +26,11 @@ This library leans on Slack Block Kit's `markdown` block for standard Markdown a
|
|
|
26
26
|
- Convert Markdown tables into Slack `table` blocks
|
|
27
27
|
- Repair common LLM table issues such as missing outer pipes, missing separator rows, mismatched column counts, and empty cells
|
|
28
28
|
- Split output into multiple Slack messages when needed to satisfy Slack's "one table per message" constraint
|
|
29
|
+
- Sanitize ANSI/control characters and neutralize invalid Slack angle-bracket tokens before block generation
|
|
29
30
|
- Add ZWSP around inline formatting tokens to reduce rendering issues outside fenced code blocks
|
|
31
|
+
- Support Markdown and Slack-style links inside table cells
|
|
30
32
|
- Build fallback text for `chat.postMessage.text` from generated blocks
|
|
33
|
+
- Accept raw LLM Markdown without tightly constraining the model prompt, using best-effort sanitize and table repair before Slack delivery
|
|
31
34
|
|
|
32
35
|
## Requirements
|
|
33
36
|
|
|
@@ -44,8 +47,7 @@ pip install slack-markdown-parser
|
|
|
44
47
|
|
|
45
48
|
```python
|
|
46
49
|
from slack_markdown_parser import (
|
|
47
|
-
|
|
48
|
-
convert_markdown_to_slack_messages,
|
|
50
|
+
convert_markdown_to_slack_payloads,
|
|
49
51
|
)
|
|
50
52
|
|
|
51
53
|
markdown = """
|
|
@@ -57,11 +59,7 @@ markdown = """
|
|
|
57
59
|
| UI | *In progress* |
|
|
58
60
|
"""
|
|
59
61
|
|
|
60
|
-
for
|
|
61
|
-
payload = {
|
|
62
|
-
"blocks": blocks,
|
|
63
|
-
"text": build_fallback_text_from_blocks(blocks) or "report",
|
|
64
|
-
}
|
|
62
|
+
for payload in convert_markdown_to_slack_payloads(markdown):
|
|
65
63
|
print(payload)
|
|
66
64
|
```
|
|
67
65
|
|
|
@@ -115,6 +113,7 @@ Example Slack bot rendering (`markdown` + `table` blocks):
|
|
|
115
113
|
| Function | Description |
|
|
116
114
|
|---|---|
|
|
117
115
|
| `convert_markdown_to_slack_messages(markdown_text) -> list[list[dict]]` | Convert Markdown into Slack messages already split around table blocks. |
|
|
116
|
+
| `convert_markdown_to_slack_payloads(markdown_text) -> list[dict]` | Convert Markdown into Slack-ready payloads with both `blocks` and fallback `text`. |
|
|
118
117
|
| `convert_markdown_to_slack_blocks(markdown_text) -> list[dict]` | Convert Markdown into a flat Block Kit block list. |
|
|
119
118
|
| `build_fallback_text_from_blocks(blocks) -> str` | Build fallback text suitable for `chat.postMessage.text`. |
|
|
120
119
|
| `blocks_to_plain_text(blocks) -> str` | Convert blocks into plain text. |
|
|
@@ -126,6 +125,7 @@ Example Slack bot rendering (`markdown` + `table` blocks):
|
|
|
126
125
|
| `normalize_markdown_tables(markdown_text) -> str` | Normalize Markdown table syntax before conversion. |
|
|
127
126
|
| `add_zero_width_spaces_to_markdown(text) -> str` | Insert ZWSP around formatting tokens where Slack needs stronger boundaries. |
|
|
128
127
|
| `decode_html_entities(text) -> str` | Decode HTML entities before parsing. |
|
|
128
|
+
| `sanitize_slack_text(text) -> str` | Remove ANSI/control noise and neutralize invalid Slack angle-bracket tokens. |
|
|
129
129
|
| `strip_zero_width_spaces(text) -> str` | Remove ZWSP (`U+200B`) and BOM (`U+FEFF`) while preserving join-control characters such as ZWJ. |
|
|
130
130
|
|
|
131
131
|
### Lower-level exported helpers
|
|
@@ -148,6 +148,15 @@ These are also part of the public package surface:
|
|
|
148
148
|
- Generating Slack `mrkdwn` strings
|
|
149
149
|
- Supporting clients or MCP tools that can only send `mrkdwn`
|
|
150
150
|
|
|
151
|
+
## Contributing
|
|
152
|
+
|
|
153
|
+
Contributions, bug reports, and documentation improvements are welcome.
|
|
154
|
+
Please read [CONTRIBUTING.md](CONTRIBUTING.md) before opening an issue or pull request.
|
|
155
|
+
|
|
156
|
+
## Changelog
|
|
157
|
+
|
|
158
|
+
Version history is maintained in [CHANGELOG.md](CHANGELOG.md).
|
|
159
|
+
|
|
151
160
|
## Contact
|
|
152
161
|
|
|
153
162
|
- GitHub Issues / Pull Requests
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
# パーサー挙動仕様
|
|
2
|
+
|
|
3
|
+
このドキュメントは `slack-markdown-parser` の変換挙動を定義します。
|
|
4
|
+
|
|
5
|
+
## 入力
|
|
6
|
+
|
|
7
|
+
- UTF-8 の Markdown 文字列
|
|
8
|
+
- 不正形テーブル、HTML エンティティ、プレーンテキスト混在を許容
|
|
9
|
+
|
|
10
|
+
## 出力
|
|
11
|
+
|
|
12
|
+
- Slack Block Kit ブロック(`markdown` / `table`)
|
|
13
|
+
- 複数テーブル入力時は「1メッセージ1テーブル」を満たすメッセージ群
|
|
14
|
+
|
|
15
|
+
## 変換パイプライン
|
|
16
|
+
|
|
17
|
+
`convert_markdown_to_slack_blocks` の処理順序:
|
|
18
|
+
|
|
19
|
+
1. **HTML エンティティデコード** — `>`, `&` 等を元の文字に復元
|
|
20
|
+
2. **Slack 向けサニタイズ** — ANSI / 制御文字を除去し、不正な Slack 角括弧トークンを無害化
|
|
21
|
+
3. **underscore 装飾正規化** — `_..._` / `__...__` を Slack 互換の `*...*` / `**...**` に変換
|
|
22
|
+
4. **テーブル正規化** — 後述のルールで不正形テーブルを補完
|
|
23
|
+
5. **セグメント分割** — テーブル領域(`|...|` 行の連続)と非テーブル領域に分割
|
|
24
|
+
6. **ブロック生成** — セグメント種別ごとに処理:
|
|
25
|
+
- テーブル領域 → セル装飾を解析し `table` ブロックを生成。変換に失敗した場合(テーブル候補行が2行未満、パース結果が空など)は `markdown` ブロックにフォールバック
|
|
26
|
+
- 非テーブル領域 → ZWSP を付与して `markdown` ブロックを生成
|
|
27
|
+
|
|
28
|
+
`convert_markdown_to_slack_messages` は上記の結果を「1メッセージ1テーブル」制約に沿って分割します。
|
|
29
|
+
`convert_markdown_to_slack_payloads` は、同じ分割結果に `chat.postMessage.text` 用 fallback を付けた payload 群を返します。
|
|
30
|
+
|
|
31
|
+
## Slack 向けサニタイズルール
|
|
32
|
+
|
|
33
|
+
`sanitize_slack_text` の挙動:
|
|
34
|
+
|
|
35
|
+
- ANSI escape を除去する
|
|
36
|
+
- 一般的な制御文字を除去する
|
|
37
|
+
- 有効な Slack 角括弧トークンは保持する
|
|
38
|
+
- 例: リンク、メンション、チャンネル参照、`<!here>`、`<!subteam^...>`、`<!date^...>`
|
|
39
|
+
- Slack の特殊記法として解釈できない `<foo>` のようなトークンは `<foo>` に変換して無害化する
|
|
40
|
+
- これには `<div>` や `<span>` のような生 HTML 風タグも含まれ、Slack 特殊記法として解釈されないよう自動で無害化する
|
|
41
|
+
|
|
42
|
+
## underscore 装飾正規化ルール
|
|
43
|
+
|
|
44
|
+
`normalize_underscore_emphasis` の挙動:
|
|
45
|
+
|
|
46
|
+
- `_text_` を `*text*` に変換する
|
|
47
|
+
- `__text__` を `**text**` に変換する
|
|
48
|
+
- 変換対象は ASCII 英数字の単語境界に埋まっていない装飾用途の underscore に限定する
|
|
49
|
+
- `snake_case` のような識別子は保持する
|
|
50
|
+
- `\_escaped\_` は保持する
|
|
51
|
+
- bare URL、Markdown リンク、Slack angle token、インラインコード内の underscore は保持する
|
|
52
|
+
- フェンスドコードブロック(`` ``` `` / `~~~`)内の underscore は保持する
|
|
53
|
+
|
|
54
|
+
## テーブル正規化ルール
|
|
55
|
+
|
|
56
|
+
LLM は外枠パイプの省略、セパレータ行の欠落、列数の不一致など多様なテーブル記法を生成します。これらをそのまま Slack `table` ブロックに渡すと `invalid_blocks` エラーになるため、`normalize_markdown_tables` で事前に補完します。
|
|
57
|
+
|
|
58
|
+
### テーブル候補の判定
|
|
59
|
+
|
|
60
|
+
- 連続する `|` 含有行を候補としてバッファリング
|
|
61
|
+
- 以下のいずれかで「テーブル」と判定:
|
|
62
|
+
- セパレータ行(`|---|---|` 形式)を含む
|
|
63
|
+
- 2行以上のデータ行があり、列数が一致または差が1以内で、最大列数が2以上
|
|
64
|
+
|
|
65
|
+
### 正規化処理
|
|
66
|
+
|
|
67
|
+
- 外枠パイプが欠けている行は `|...|` 形式に補完
|
|
68
|
+
- セパレータ行が欠けていればヘッダ直後に自動生成
|
|
69
|
+
- 各行の列数はヘッダ幅に合わせて不足分を空セルで補完、超過分を切り詰め
|
|
70
|
+
- 空セルは `table` ブロック生成時に `-` に置換
|
|
71
|
+
- `# 見出し |a|b|` 形式は見出し行とテーブル行に分離(見出し内のインラインコードに含まれるパイプは無視)
|
|
72
|
+
- `### Heading ... Header A | Header B` のように見出しと表ヘッダが1行に潰れている場合、次行の列形状を手がかりに first header cell を推定する
|
|
73
|
+
- フェンスドコードブロック(`` ``` `` / `~~~`)内の行はテーブル候補として扱わない
|
|
74
|
+
|
|
75
|
+
### セル内パイプの保持
|
|
76
|
+
|
|
77
|
+
- Slack リンク `<url|text>` 内のパイプはセル区切りとして扱わない
|
|
78
|
+
- インラインコード `` `...` `` 内のパイプもセル区切りとして扱わない
|
|
79
|
+
- エスケープされたパイプ `\|` はセル区切りとして扱わず、表示時にバックスラッシュを除去して `|` として出力
|
|
80
|
+
|
|
81
|
+
## テーブルセル装飾
|
|
82
|
+
|
|
83
|
+
セル内で次のインライン装飾を認識し、Slack `rich_text` 要素のスタイルに変換:
|
|
84
|
+
|
|
85
|
+
| 記法 | スタイル |
|
|
86
|
+
|---|---|
|
|
87
|
+
| `**text**` | bold |
|
|
88
|
+
| `*text*` | italic |
|
|
89
|
+
| `~~text~~` | strike |
|
|
90
|
+
| `` `text` `` | code |
|
|
91
|
+
|
|
92
|
+
複数装飾のネストはプレーンテキストとして保持します。
|
|
93
|
+
|
|
94
|
+
加えて、セル内では次のリンク記法を認識します。
|
|
95
|
+
|
|
96
|
+
| 記法 | 出力 |
|
|
97
|
+
|---|---|
|
|
98
|
+
| `[label](https://example.com)` | Slack rich-text link |
|
|
99
|
+
| `<https://example.com|label>` | Slack rich-text link |
|
|
100
|
+
| `<https://example.com>` | Slack rich-text link |
|
|
101
|
+
|
|
102
|
+
## ZWSP(ゼロ幅スペース)付与ルール
|
|
103
|
+
|
|
104
|
+
`add_zero_width_spaces_to_markdown` の挙動:
|
|
105
|
+
|
|
106
|
+
### 目的
|
|
107
|
+
|
|
108
|
+
日本語等の語間スペースがない文で装飾記号が隣接文字と結合し、Slack のレンダリングが崩れる問題を回避します。通常の半角スペースではなくゼロ幅スペースを使うことで、見た目上の不自然な空白を生じさせずに Slack の装飾解析を補助します。
|
|
109
|
+
|
|
110
|
+
### 対象パターン
|
|
111
|
+
|
|
112
|
+
以下の装飾記号について、前後のどちらか一方でも隣接文字がスペース・タブ・改行・ZWSP でない場合、または行頭・行末に接している場合、装飾トークン全体を ZWSP(U+200B)で囲って Slack に独立した境界として認識させる:
|
|
113
|
+
|
|
114
|
+
- `` `code` `` — インラインコード
|
|
115
|
+
- `**bold**` — 太字
|
|
116
|
+
- `*italic*` — 斜体
|
|
117
|
+
- `~~strike~~` — 取消線
|
|
118
|
+
|
|
119
|
+
### 除外範囲
|
|
120
|
+
|
|
121
|
+
- **フェンスドコードブロック**(`` ``` ... ``` `` および `~~~ ... ~~~`)内は一切変更しない
|
|
122
|
+
- インラインコード(`` `...` ``)は除外**しない**(付与対象)
|
|
123
|
+
|
|
124
|
+
## ZWSP 除去ルール
|
|
125
|
+
|
|
126
|
+
`strip_zero_width_spaces` はテーブルセル生成時および fallback テキスト生成時に呼ばれ、本ライブラリが挿入した制御文字を除去します。
|
|
127
|
+
|
|
128
|
+
### 除去対象
|
|
129
|
+
|
|
130
|
+
| コードポイント | 名称 | 除去理由 |
|
|
131
|
+
|---|---|---|
|
|
132
|
+
| U+200B | ZWSP(ゼロ幅スペース) | 本ライブラリが装飾安定化のために挿入したもの |
|
|
133
|
+
| U+FEFF | BOM(バイト順マーク) | エンコーディング由来の不要な制御文字 |
|
|
134
|
+
|
|
135
|
+
### 除去しない文字
|
|
136
|
+
|
|
137
|
+
| コードポイント | 名称 | 保持理由 |
|
|
138
|
+
|---|---|---|
|
|
139
|
+
| U+200C | ZWNJ(ゼロ幅非接合子) | ペルシャ語・ヒンディー語等の語形制御に使用 |
|
|
140
|
+
| U+200D | ZWJ(ゼロ幅接合子) | 結合絵文字(👨💻 = 👨+ZWJ+💻)の接着剤として使用。除去すると絵文字が分解される |
|
|
141
|
+
|
|
142
|
+
## fallback テキスト
|
|
143
|
+
|
|
144
|
+
`build_fallback_text_from_blocks` は `chat.postMessage.text` に設定する通知プレビュー用テキストを生成:
|
|
145
|
+
|
|
146
|
+
- `markdown` ブロック → ZWSP を除去したテキスト
|
|
147
|
+
- `table` ブロック → 各行のセルテキストを ` | ` で連結
|
|
148
|
+
- 各ブロックの出力を空行で区切って結合
|
|
149
|
+
|
|
150
|
+
テーブルセル内リンクの fallback テキストは、ラベルがあればラベル、なければ URL を使います。
|
|
151
|
+
|
|
152
|
+
## 決定性
|
|
153
|
+
|
|
154
|
+
同一入力に対して、環境差分に依存せず常に同一の出力を返します。
|
|
155
|
+
|
|
156
|
+
## 非ゴール
|
|
157
|
+
|
|
158
|
+
- `mrkdwn` 文字列の生成
|
|
159
|
+
- 完全な Markdown AST の再現
|
|
160
|
+
- HTML レンダリング互換
|