slack-markdown-parser 2.0.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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 slack-markdown-parser contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,189 @@
1
+ Metadata-Version: 2.4
2
+ Name: slack-markdown-parser
3
+ Version: 2.0.2
4
+ Summary: Convert LLM Markdown into Slack Block Kit markdown/table messages
5
+ Author: darkgaldragon
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/darkgaldragon/slack-markdown-parser
8
+ Project-URL: Source, https://github.com/darkgaldragon/slack-markdown-parser
9
+ Project-URL: Issues, https://github.com/darkgaldragon/slack-markdown-parser/issues
10
+ Keywords: slack,markdown,block-kit,table,llm
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
19
+ Requires-Python: >=3.10
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Provides-Extra: dev
23
+ Requires-Dist: black>=24.0.0; extra == "dev"
24
+ Requires-Dist: build>=1.2.0; extra == "dev"
25
+ Requires-Dist: pip-audit>=2.7.0; extra == "dev"
26
+ Requires-Dist: pytest>=8.0.0; extra == "dev"
27
+ Requires-Dist: pytest-cov>=5.0.0; extra == "dev"
28
+ Requires-Dist: ruff>=0.6.0; extra == "dev"
29
+ Requires-Dist: twine>=5.1.0; extra == "dev"
30
+ Dynamic: license-file
31
+
32
+ # slack-markdown-parser
33
+
34
+ `slack-markdown-parser` is a Python library that converts standard Markdown generated by LLMs into Slack Block Kit messages built from `markdown` and `table` blocks.
35
+
36
+ ## Why this library exists
37
+
38
+ Many Slack AI bots have traditionally converted model output into Slack-specific `mrkdwn`, but that approach creates a few recurring problems:
39
+
40
+ - Conversion overhead: LLMs naturally generate standard Markdown, so `mrkdwn` usually requires extra transformation logic or prompt constraints.
41
+ - Unstable formatting in languages without word spacing: in Japanese and similar scripts, Slack can fail to interpret `*`, `~`, and related markers correctly, exposing the raw punctuation.
42
+ - No table syntax in `mrkdwn`: Markdown tables need custom fallback rendering if you stay in the old format.
43
+
44
+ ## Design approach
45
+
46
+ This library leans on Slack Block Kit's `markdown` block for standard Markdown and `table` block for tables.
47
+
48
+ | Problem | Approach |
49
+ |---|---|
50
+ | Conversion overhead | Send standard Markdown through Slack `markdown` blocks without rewriting it into `mrkdwn`. |
51
+ | Formatting instability | Insert zero-width spaces (ZWSP, U+200B) around formatting tokens when needed so Slack parses inline styling more reliably without visible extra spaces. |
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
+
54
+ ## Features
55
+
56
+ - Convert standard Markdown into Slack `markdown` blocks
57
+ - Convert Markdown tables into Slack `table` blocks
58
+ - Repair common LLM table issues such as missing outer pipes, missing separator rows, mismatched column counts, and empty cells
59
+ - Split output into multiple Slack messages when needed to satisfy Slack's "one table per message" constraint
60
+ - Add ZWSP around inline formatting tokens to reduce rendering issues outside fenced code blocks
61
+ - Build fallback text for `chat.postMessage.text` from generated blocks
62
+
63
+ ## Requirements
64
+
65
+ - Your Slack integration must support Block Kit payloads with `markdown` and `table` blocks.
66
+ - This library does not help when your delivery path only accepts plain `text` or `mrkdwn` strings.
67
+
68
+ ## Installation
69
+
70
+ ```bash
71
+ pip install slack-markdown-parser
72
+ ```
73
+
74
+ ## Quick start
75
+
76
+ ```python
77
+ from slack_markdown_parser import (
78
+ build_fallback_text_from_blocks,
79
+ convert_markdown_to_slack_messages,
80
+ )
81
+
82
+ markdown = """
83
+ # Weekly Report
84
+
85
+ | Team | Status |
86
+ |---|---|
87
+ | API | **On track** |
88
+ | UI | *In progress* |
89
+ """
90
+
91
+ for blocks in convert_markdown_to_slack_messages(markdown):
92
+ payload = {
93
+ "blocks": blocks,
94
+ "text": build_fallback_text_from_blocks(blocks) or "report",
95
+ }
96
+ print(payload)
97
+ ```
98
+
99
+ `convert_markdown_to_slack_messages` automatically splits output into multiple messages when the input contains multiple tables.
100
+
101
+ ## Rendering example
102
+
103
+ Example input:
104
+
105
+ ````markdown
106
+ # Weekly Product Update
107
+
108
+ This week we worked on **search performance** and *UI polish*. The old flow is ~~scheduled for removal~~.
109
+ The detailed log ID is `run-20260305-02`.
110
+ Reference: https://example.com/changelog
111
+
112
+ - Improved **API response time**
113
+ - Increased *cache hit rate*
114
+ - Adjusted timeout settings
115
+ - Stabilized batch processing
116
+ - Unified retry counts
117
+ - Updated documentation
118
+
119
+ Category | Status | Owner
120
+ API | **In progress** | Team A
121
+ UI | *Under review* | Team B
122
+ QA | ~~On hold~~ | Team C
123
+
124
+ > Note: production rollout is scheduled for 2026-03-08 10:00 JST
125
+
126
+ 1. Finalize release notes
127
+ 1. Unify change labels
128
+ 2. Add impact notes
129
+ 2. Tune monitoring alert thresholds
130
+ 1. Update the `warning` threshold
131
+ 3. Re-check QA
132
+
133
+ ```bash
134
+ ./deploy.sh production
135
+ ```
136
+ ````
137
+
138
+ Example Slack bot rendering (`markdown` + `table` blocks):
139
+
140
+ ![Slack BOT rendering example](Example_en.png)
141
+
142
+ ## Public API
143
+
144
+ ### Main functions
145
+
146
+ | Function | Description |
147
+ |---|---|
148
+ | `convert_markdown_to_slack_messages(markdown_text) -> list[list[dict]]` | Convert Markdown into Slack messages already split around table blocks. |
149
+ | `convert_markdown_to_slack_blocks(markdown_text) -> list[dict]` | Convert Markdown into a flat Block Kit block list. |
150
+ | `build_fallback_text_from_blocks(blocks) -> str` | Build fallback text suitable for `chat.postMessage.text`. |
151
+ | `blocks_to_plain_text(blocks) -> str` | Convert blocks into plain text. |
152
+
153
+ ### Utility functions
154
+
155
+ | Function | Description |
156
+ |---|---|
157
+ | `normalize_markdown_tables(markdown_text) -> str` | Normalize Markdown table syntax before conversion. |
158
+ | `add_zero_width_spaces_to_markdown(text) -> str` | Insert ZWSP around formatting tokens where Slack needs stronger boundaries. |
159
+ | `decode_html_entities(text) -> str` | Decode HTML entities before parsing. |
160
+ | `strip_zero_width_spaces(text) -> str` | Remove ZWSP (`U+200B`) and BOM (`U+FEFF`) while preserving join-control characters such as ZWJ. |
161
+
162
+ ### Lower-level exported helpers
163
+
164
+ These are also part of the public package surface:
165
+
166
+ - `add_zero_width_spaces`
167
+ - `convert_markdown_text_to_blocks`
168
+ - `extract_plain_text_from_table_cell`
169
+ - `markdown_table_to_slack_table`
170
+ - `parse_markdown_table`
171
+ - `split_blocks_by_table`
172
+ - `split_markdown_into_segments`
173
+
174
+ ## Specification and scope
175
+
176
+ - Behavior spec: [docs/spec.md](docs/spec.md)
177
+ - Japanese behavior spec: [docs/spec-ja.md](docs/spec-ja.md)
178
+ - Non-goals:
179
+ - Generating Slack `mrkdwn` strings
180
+ - Supporting clients or MCP tools that can only send `mrkdwn`
181
+
182
+ ## Contact
183
+
184
+ - GitHub Issues / Pull Requests
185
+ - X: [@darkgaldragon](https://x.com/darkgaldragon)
186
+
187
+ ## License
188
+
189
+ MIT
@@ -0,0 +1,158 @@
1
+ # slack-markdown-parser
2
+
3
+ `slack-markdown-parser` is a Python library that converts standard Markdown generated by LLMs into Slack Block Kit messages built from `markdown` and `table` blocks.
4
+
5
+ ## Why this library exists
6
+
7
+ Many Slack AI bots have traditionally converted model output into Slack-specific `mrkdwn`, but that approach creates a few recurring problems:
8
+
9
+ - Conversion overhead: LLMs naturally generate standard Markdown, so `mrkdwn` usually requires extra transformation logic or prompt constraints.
10
+ - Unstable formatting in languages without word spacing: in Japanese and similar scripts, Slack can fail to interpret `*`, `~`, and related markers correctly, exposing the raw punctuation.
11
+ - No table syntax in `mrkdwn`: Markdown tables need custom fallback rendering if you stay in the old format.
12
+
13
+ ## Design approach
14
+
15
+ This library leans on Slack Block Kit's `markdown` block for standard Markdown and `table` block for tables.
16
+
17
+ | Problem | Approach |
18
+ |---|---|
19
+ | Conversion overhead | Send standard Markdown through Slack `markdown` blocks without rewriting it into `mrkdwn`. |
20
+ | Formatting instability | Insert zero-width spaces (ZWSP, U+200B) around formatting tokens when needed so Slack parses inline styling more reliably without visible extra spaces. |
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
+
23
+ ## Features
24
+
25
+ - Convert standard Markdown into Slack `markdown` blocks
26
+ - Convert Markdown tables into Slack `table` blocks
27
+ - Repair common LLM table issues such as missing outer pipes, missing separator rows, mismatched column counts, and empty cells
28
+ - Split output into multiple Slack messages when needed to satisfy Slack's "one table per message" constraint
29
+ - Add ZWSP around inline formatting tokens to reduce rendering issues outside fenced code blocks
30
+ - Build fallback text for `chat.postMessage.text` from generated blocks
31
+
32
+ ## Requirements
33
+
34
+ - Your Slack integration must support Block Kit payloads with `markdown` and `table` blocks.
35
+ - This library does not help when your delivery path only accepts plain `text` or `mrkdwn` strings.
36
+
37
+ ## Installation
38
+
39
+ ```bash
40
+ pip install slack-markdown-parser
41
+ ```
42
+
43
+ ## Quick start
44
+
45
+ ```python
46
+ from slack_markdown_parser import (
47
+ build_fallback_text_from_blocks,
48
+ convert_markdown_to_slack_messages,
49
+ )
50
+
51
+ markdown = """
52
+ # Weekly Report
53
+
54
+ | Team | Status |
55
+ |---|---|
56
+ | API | **On track** |
57
+ | UI | *In progress* |
58
+ """
59
+
60
+ for blocks in convert_markdown_to_slack_messages(markdown):
61
+ payload = {
62
+ "blocks": blocks,
63
+ "text": build_fallback_text_from_blocks(blocks) or "report",
64
+ }
65
+ print(payload)
66
+ ```
67
+
68
+ `convert_markdown_to_slack_messages` automatically splits output into multiple messages when the input contains multiple tables.
69
+
70
+ ## Rendering example
71
+
72
+ Example input:
73
+
74
+ ````markdown
75
+ # Weekly Product Update
76
+
77
+ This week we worked on **search performance** and *UI polish*. The old flow is ~~scheduled for removal~~.
78
+ The detailed log ID is `run-20260305-02`.
79
+ Reference: https://example.com/changelog
80
+
81
+ - Improved **API response time**
82
+ - Increased *cache hit rate*
83
+ - Adjusted timeout settings
84
+ - Stabilized batch processing
85
+ - Unified retry counts
86
+ - Updated documentation
87
+
88
+ Category | Status | Owner
89
+ API | **In progress** | Team A
90
+ UI | *Under review* | Team B
91
+ QA | ~~On hold~~ | Team C
92
+
93
+ > Note: production rollout is scheduled for 2026-03-08 10:00 JST
94
+
95
+ 1. Finalize release notes
96
+ 1. Unify change labels
97
+ 2. Add impact notes
98
+ 2. Tune monitoring alert thresholds
99
+ 1. Update the `warning` threshold
100
+ 3. Re-check QA
101
+
102
+ ```bash
103
+ ./deploy.sh production
104
+ ```
105
+ ````
106
+
107
+ Example Slack bot rendering (`markdown` + `table` blocks):
108
+
109
+ ![Slack BOT rendering example](Example_en.png)
110
+
111
+ ## Public API
112
+
113
+ ### Main functions
114
+
115
+ | Function | Description |
116
+ |---|---|
117
+ | `convert_markdown_to_slack_messages(markdown_text) -> list[list[dict]]` | Convert Markdown into Slack messages already split around table blocks. |
118
+ | `convert_markdown_to_slack_blocks(markdown_text) -> list[dict]` | Convert Markdown into a flat Block Kit block list. |
119
+ | `build_fallback_text_from_blocks(blocks) -> str` | Build fallback text suitable for `chat.postMessage.text`. |
120
+ | `blocks_to_plain_text(blocks) -> str` | Convert blocks into plain text. |
121
+
122
+ ### Utility functions
123
+
124
+ | Function | Description |
125
+ |---|---|
126
+ | `normalize_markdown_tables(markdown_text) -> str` | Normalize Markdown table syntax before conversion. |
127
+ | `add_zero_width_spaces_to_markdown(text) -> str` | Insert ZWSP around formatting tokens where Slack needs stronger boundaries. |
128
+ | `decode_html_entities(text) -> str` | Decode HTML entities before parsing. |
129
+ | `strip_zero_width_spaces(text) -> str` | Remove ZWSP (`U+200B`) and BOM (`U+FEFF`) while preserving join-control characters such as ZWJ. |
130
+
131
+ ### Lower-level exported helpers
132
+
133
+ These are also part of the public package surface:
134
+
135
+ - `add_zero_width_spaces`
136
+ - `convert_markdown_text_to_blocks`
137
+ - `extract_plain_text_from_table_cell`
138
+ - `markdown_table_to_slack_table`
139
+ - `parse_markdown_table`
140
+ - `split_blocks_by_table`
141
+ - `split_markdown_into_segments`
142
+
143
+ ## Specification and scope
144
+
145
+ - Behavior spec: [docs/spec.md](docs/spec.md)
146
+ - Japanese behavior spec: [docs/spec-ja.md](docs/spec-ja.md)
147
+ - Non-goals:
148
+ - Generating Slack `mrkdwn` strings
149
+ - Supporting clients or MCP tools that can only send `mrkdwn`
150
+
151
+ ## Contact
152
+
153
+ - GitHub Issues / Pull Requests
154
+ - X: [@darkgaldragon](https://x.com/darkgaldragon)
155
+
156
+ ## License
157
+
158
+ MIT
@@ -0,0 +1,57 @@
1
+ [build-system]
2
+ requires = ["setuptools>=69", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "slack-markdown-parser"
7
+ version = "2.0.2"
8
+ description = "Convert LLM Markdown into Slack Block Kit markdown/table messages"
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = "MIT"
12
+ authors = [
13
+ {name = "darkgaldragon"}
14
+ ]
15
+ keywords = ["slack", "markdown", "block-kit", "table", "llm"]
16
+ classifiers = [
17
+ "Development Status :: 4 - Beta",
18
+ "Intended Audience :: Developers",
19
+ "Programming Language :: Python :: 3",
20
+ "Programming Language :: Python :: 3.10",
21
+ "Programming Language :: Python :: 3.11",
22
+ "Programming Language :: Python :: 3.12",
23
+ "Programming Language :: Python :: 3.13",
24
+ "Topic :: Software Development :: Libraries :: Python Modules",
25
+ ]
26
+ dependencies = []
27
+
28
+ [project.optional-dependencies]
29
+ dev = [
30
+ "black>=24.0.0",
31
+ "build>=1.2.0",
32
+ "pip-audit>=2.7.0",
33
+ "pytest>=8.0.0",
34
+ "pytest-cov>=5.0.0",
35
+ "ruff>=0.6.0",
36
+ "twine>=5.1.0",
37
+ ]
38
+
39
+ [project.urls]
40
+ Homepage = "https://github.com/darkgaldragon/slack-markdown-parser"
41
+ Source = "https://github.com/darkgaldragon/slack-markdown-parser"
42
+ Issues = "https://github.com/darkgaldragon/slack-markdown-parser/issues"
43
+
44
+ [tool.setuptools.packages.find]
45
+ include = ["slack_markdown_parser*"]
46
+
47
+ [tool.black]
48
+ line-length = 88
49
+ target-version = ["py310"]
50
+
51
+ [tool.ruff]
52
+ line-length = 88
53
+ target-version = "py310"
54
+
55
+ [tool.ruff.lint]
56
+ select = ["E", "F", "I", "UP", "B"]
57
+ ignore = ["E501", "UP006", "UP035", "UP045"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,40 @@
1
+ """slack-markdown-parser public package API."""
2
+
3
+ __version__ = "2.0.2"
4
+ __license__ = "MIT"
5
+
6
+ from .converter import (
7
+ add_zero_width_spaces,
8
+ add_zero_width_spaces_to_markdown,
9
+ blocks_to_plain_text,
10
+ build_fallback_text_from_blocks,
11
+ convert_markdown_text_to_blocks,
12
+ convert_markdown_to_slack_blocks,
13
+ convert_markdown_to_slack_messages,
14
+ decode_html_entities,
15
+ extract_plain_text_from_table_cell,
16
+ markdown_table_to_slack_table,
17
+ normalize_markdown_tables,
18
+ parse_markdown_table,
19
+ split_blocks_by_table,
20
+ split_markdown_into_segments,
21
+ strip_zero_width_spaces,
22
+ )
23
+
24
+ __all__ = [
25
+ "add_zero_width_spaces",
26
+ "add_zero_width_spaces_to_markdown",
27
+ "blocks_to_plain_text",
28
+ "build_fallback_text_from_blocks",
29
+ "convert_markdown_text_to_blocks",
30
+ "convert_markdown_to_slack_blocks",
31
+ "convert_markdown_to_slack_messages",
32
+ "decode_html_entities",
33
+ "extract_plain_text_from_table_cell",
34
+ "markdown_table_to_slack_table",
35
+ "normalize_markdown_tables",
36
+ "parse_markdown_table",
37
+ "split_blocks_by_table",
38
+ "split_markdown_into_segments",
39
+ "strip_zero_width_spaces",
40
+ ]