slack-markdown-parser 2.2.4__tar.gz → 2.2.5__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.4 → slack_markdown_parser-2.2.5}/CHANGELOG.md +6 -0
- {slack_markdown_parser-2.2.4 → slack_markdown_parser-2.2.5}/PKG-INFO +2 -2
- {slack_markdown_parser-2.2.4 → slack_markdown_parser-2.2.5}/README-ja.md +1 -1
- {slack_markdown_parser-2.2.4 → slack_markdown_parser-2.2.5}/README.md +1 -1
- {slack_markdown_parser-2.2.4 → slack_markdown_parser-2.2.5}/docs/spec-ja.md +5 -1
- {slack_markdown_parser-2.2.4 → slack_markdown_parser-2.2.5}/docs/spec.md +5 -1
- {slack_markdown_parser-2.2.4 → slack_markdown_parser-2.2.5}/pyproject.toml +1 -1
- {slack_markdown_parser-2.2.4 → slack_markdown_parser-2.2.5}/slack_markdown_parser/__init__.py +1 -1
- {slack_markdown_parser-2.2.4 → slack_markdown_parser-2.2.5}/slack_markdown_parser/converter.py +50 -0
- {slack_markdown_parser-2.2.4 → slack_markdown_parser-2.2.5}/slack_markdown_parser.egg-info/PKG-INFO +2 -2
- {slack_markdown_parser-2.2.4 → slack_markdown_parser-2.2.5}/tests/test_converter.py +14 -0
- {slack_markdown_parser-2.2.4 → slack_markdown_parser-2.2.5}/CONTRIBUTING.md +0 -0
- {slack_markdown_parser-2.2.4 → slack_markdown_parser-2.2.5}/LICENSE +0 -0
- {slack_markdown_parser-2.2.4 → slack_markdown_parser-2.2.5}/MANIFEST.in +0 -0
- {slack_markdown_parser-2.2.4 → slack_markdown_parser-2.2.5}/docs/slack-client-manual-checklist.md +0 -0
- {slack_markdown_parser-2.2.4 → slack_markdown_parser-2.2.5}/docs/slack-nested-modifier-findings.md +0 -0
- {slack_markdown_parser-2.2.4 → slack_markdown_parser-2.2.5}/docs/slack-render-test-workflow.md +0 -0
- {slack_markdown_parser-2.2.4 → slack_markdown_parser-2.2.5}/setup.cfg +0 -0
- {slack_markdown_parser-2.2.4 → slack_markdown_parser-2.2.5}/slack_markdown_parser/py.typed +0 -0
- {slack_markdown_parser-2.2.4 → slack_markdown_parser-2.2.5}/slack_markdown_parser.egg-info/SOURCES.txt +0 -0
- {slack_markdown_parser-2.2.4 → slack_markdown_parser-2.2.5}/slack_markdown_parser.egg-info/dependency_links.txt +0 -0
- {slack_markdown_parser-2.2.4 → slack_markdown_parser-2.2.5}/slack_markdown_parser.egg-info/requires.txt +0 -0
- {slack_markdown_parser-2.2.4 → slack_markdown_parser-2.2.5}/slack_markdown_parser.egg-info/top_level.txt +0 -0
- {slack_markdown_parser-2.2.4 → slack_markdown_parser-2.2.5}/tests/fixtures/llm_markdown_p0_corpus.md +0 -0
- {slack_markdown_parser-2.2.4 → slack_markdown_parser-2.2.5}/tests/fixtures/slack_cjk_inner_code_matrix.md +0 -0
- {slack_markdown_parser-2.2.4 → slack_markdown_parser-2.2.5}/tests/fixtures/slack_nested_modifier_matrix.md +0 -0
- {slack_markdown_parser-2.2.4 → slack_markdown_parser-2.2.5}/tests/fixtures/slack_nested_modifier_matrix_parens.md +0 -0
- {slack_markdown_parser-2.2.4 → slack_markdown_parser-2.2.5}/tests/fixtures/slack_nested_modifier_matrix_quotes.md +0 -0
- {slack_markdown_parser-2.2.4 → slack_markdown_parser-2.2.5}/tests/test_llm_markdown_p0_corpus.py +0 -0
- {slack_markdown_parser-2.2.4 → slack_markdown_parser-2.2.5}/tests/test_nested_modifier_matrix.py +0 -0
|
@@ -6,6 +6,12 @@ The format is based on Keep a Changelog, and the project follows Semantic Versio
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [2.2.5] - 2026-03-14
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- Preserved raw English-like emphasis when it only touches surrounding punctuation, avoiding unnecessary ZWSP around cases such as `**APIYI (apiyi.com)**:` that Slack already renders correctly on its own.
|
|
14
|
+
|
|
9
15
|
## [2.2.4] - 2026-03-11
|
|
10
16
|
|
|
11
17
|
### Changed
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: slack-markdown-parser
|
|
3
|
-
Version: 2.2.
|
|
3
|
+
Version: 2.2.5
|
|
4
4
|
Summary: Convert LLM Markdown into Slack Block Kit markdown/table messages
|
|
5
5
|
Author: darkgaldragon
|
|
6
6
|
License-Expression: MIT
|
|
@@ -61,7 +61,7 @@ If Slack itself does not support a construct in `markdown` blocks, this library
|
|
|
61
61
|
- Repair common LLM table issues such as missing outer pipes, missing separator rows, mismatched column counts, and empty cells
|
|
62
62
|
- Split output into multiple Slack messages when needed to satisfy Slack's "one table per message" constraint
|
|
63
63
|
- Sanitize ANSI/control characters and neutralize invalid Slack angle-bracket tokens before block generation
|
|
64
|
-
- Add ZWSP around inline formatting tokens to reduce rendering issues outside fenced code blocks
|
|
64
|
+
- Add ZWSP around inline formatting tokens to reduce rendering issues outside fenced code blocks, while preserving English-like punctuation-only boundaries that Slack already renders reliably
|
|
65
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
|
|
66
66
|
- Support Markdown and Slack-style links inside table cells
|
|
67
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
|
|
@@ -30,7 +30,7 @@ Slack の `markdown` ブロック自体が対応していない構文は、古
|
|
|
30
30
|
- LLM が生成する多様な Markdown テーブルで起こり得る記法の揺れ(外枠パイプ不足、セパレータ行不足、列数不一致、空セル)を検知し自動補完。Slack `table` ブロックの `invalid_blocks` エラーを未然に回避
|
|
31
31
|
- テーブルごとにメッセージを自動分割(Slack の「1メッセージ1テーブル」制約に対応)
|
|
32
32
|
- ANSI escape / 制御文字を除去し、不正な Slack 角括弧トークンを自動で無害化
|
|
33
|
-
- 装飾記号の前後に ZWSP
|
|
33
|
+
- 装飾記号の前後に ZWSP を付与して表示崩れを抑制(フェンスドコードブロック内は除外、インラインコードは付与対象)。ただし英語系で周囲が句読点だけのケースは、Slack がそのまま安定描画できる場合に ZWSP を増やさない
|
|
34
34
|
- 日本語・中国語・韓国語の密着文脈で、インラインコードを内包する装飾には可視スペースを補って Slack 表示を安定化
|
|
35
35
|
- テーブルセル内の Markdown link / Slack link を認識
|
|
36
36
|
- `chat.postMessage.text` 用の fallback テキストを生成(表示安定化のために入れた ZWSP や人工的な可視スペースは通知文では自然な形に正規化)
|
|
@@ -30,7 +30,7 @@ If Slack itself does not support a construct in `markdown` blocks, this library
|
|
|
30
30
|
- Repair common LLM table issues such as missing outer pipes, missing separator rows, mismatched column counts, and empty cells
|
|
31
31
|
- Split output into multiple Slack messages when needed to satisfy Slack's "one table per message" constraint
|
|
32
32
|
- Sanitize ANSI/control characters and neutralize invalid Slack angle-bracket tokens before block generation
|
|
33
|
-
- Add ZWSP around inline formatting tokens to reduce rendering issues outside fenced code blocks
|
|
33
|
+
- Add ZWSP around inline formatting tokens to reduce rendering issues outside fenced code blocks, while preserving English-like punctuation-only boundaries that Slack already renders reliably
|
|
34
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
|
|
35
35
|
- Support Markdown and Slack-style links inside table cells
|
|
36
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
|
|
@@ -145,13 +145,17 @@ LLM は外枠パイプの省略、セパレータ行の欠落、列数の不一
|
|
|
145
145
|
|
|
146
146
|
### 対象パターン
|
|
147
147
|
|
|
148
|
-
以下の装飾記号について、前後のどちらか一方でも隣接文字がスペース・タブ・改行・ZWSP
|
|
148
|
+
以下の装飾記号について、前後のどちらか一方でも隣接文字がスペース・タブ・改行・ZWSP でない場合、または行頭・行末に接している場合、通常は装飾トークン全体を ZWSP(U+200B)で囲って Slack に独立した境界として認識させる:
|
|
149
149
|
|
|
150
150
|
- `` `code` `` — インラインコード
|
|
151
151
|
- `**bold**` — 太字
|
|
152
152
|
- `*italic*` — 斜体
|
|
153
153
|
- `~~strike~~` — 取消線
|
|
154
154
|
|
|
155
|
+
例外:
|
|
156
|
+
|
|
157
|
+
- 装飾の中身が英語系テキストで、密着している隣接文字が句読点だけの場合は、元のトークンをそのまま維持する。`**APIYI (apiyi.com)**:` のように Slack が素のままで安定描画できるケースで、過剰な ZWSP を入れないため。
|
|
158
|
+
|
|
155
159
|
### 除外範囲
|
|
156
160
|
|
|
157
161
|
- **フェンスドコードブロック**(`` ``` ... ``` `` および `~~~ ... ~~~`)内は一切変更しない
|
|
@@ -144,13 +144,17 @@ In languages such as Japanese that do not use spaces between words, formatting m
|
|
|
144
144
|
|
|
145
145
|
### Target patterns
|
|
146
146
|
|
|
147
|
-
For each formatting token below, if either adjacent side is not a space, tab, newline, or existing ZWSP, or if the token touches the start or end of a line, the whole token is wrapped in ZWSP (`U+200B`) so Slack recognizes it as a standalone formatting boundary:
|
|
147
|
+
For each formatting token below, if either adjacent side is not a space, tab, newline, or existing ZWSP, or if the token touches the start or end of a line, the whole token is normally wrapped in ZWSP (`U+200B`) so Slack recognizes it as a standalone formatting boundary:
|
|
148
148
|
|
|
149
149
|
- `` `code` ``: inline code
|
|
150
150
|
- `**bold**`: bold
|
|
151
151
|
- `*italic*`: italic
|
|
152
152
|
- `~~strike~~`: strikethrough
|
|
153
153
|
|
|
154
|
+
Exception:
|
|
155
|
+
|
|
156
|
+
- 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 ZWSP.
|
|
157
|
+
|
|
154
158
|
### Excluded regions
|
|
155
159
|
|
|
156
160
|
- Fenced code blocks (both `` ``` ... ``` `` and `~~~ ... ~~~`) are never modified
|
{slack_markdown_parser-2.2.4 → slack_markdown_parser-2.2.5}/slack_markdown_parser/converter.py
RENAMED
|
@@ -199,6 +199,52 @@ def _find_inline_code_span_end(text: str, start: int) -> int | None:
|
|
|
199
199
|
return closing + len(delimiter)
|
|
200
200
|
|
|
201
201
|
|
|
202
|
+
def _is_punctuation_like(char: str, boundary_chars: set[str]) -> bool:
|
|
203
|
+
return bool(char) and char not in boundary_chars and not char.isalnum()
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def _should_preserve_raw_punctuation_emphasis(
|
|
207
|
+
source: str,
|
|
208
|
+
start: int,
|
|
209
|
+
end: int,
|
|
210
|
+
token_text: str,
|
|
211
|
+
boundary_chars: set[str],
|
|
212
|
+
) -> bool:
|
|
213
|
+
tight_chars = []
|
|
214
|
+
before_char = source[start - 1] if start > 0 else ""
|
|
215
|
+
after_char = source[end] if end < len(source) else ""
|
|
216
|
+
|
|
217
|
+
if before_char and before_char not in boundary_chars:
|
|
218
|
+
tight_chars.append(before_char)
|
|
219
|
+
if after_char and after_char not in boundary_chars:
|
|
220
|
+
tight_chars.append(after_char)
|
|
221
|
+
|
|
222
|
+
if not tight_chars:
|
|
223
|
+
return False
|
|
224
|
+
if any(not _is_punctuation_like(char, boundary_chars) for char in tight_chars):
|
|
225
|
+
return False
|
|
226
|
+
if any(_is_han_or_kana_char(char) or _is_hangul_char(char) for char in token_text):
|
|
227
|
+
return False
|
|
228
|
+
|
|
229
|
+
left_idx = start - 1
|
|
230
|
+
while left_idx >= 0 and source[left_idx] in boundary_chars:
|
|
231
|
+
left_idx -= 1
|
|
232
|
+
if left_idx >= 0 and (
|
|
233
|
+
_is_han_or_kana_char(source[left_idx]) or _is_hangul_char(source[left_idx])
|
|
234
|
+
):
|
|
235
|
+
return False
|
|
236
|
+
|
|
237
|
+
right_idx = end
|
|
238
|
+
while right_idx < len(source) and source[right_idx] in boundary_chars:
|
|
239
|
+
right_idx += 1
|
|
240
|
+
if right_idx < len(source) and (
|
|
241
|
+
_is_han_or_kana_char(source[right_idx]) or _is_hangul_char(source[right_idx])
|
|
242
|
+
):
|
|
243
|
+
return False
|
|
244
|
+
|
|
245
|
+
return True
|
|
246
|
+
|
|
247
|
+
|
|
202
248
|
def normalize_bare_urls_for_slack_markdown(text: str) -> str:
|
|
203
249
|
"""Wrap bare URLs in autolink syntax for stable Slack markdown rendering."""
|
|
204
250
|
if not text:
|
|
@@ -369,6 +415,10 @@ def _format_markdown_with_spacing_metadata(text: str) -> tuple[str, List[int]]:
|
|
|
369
415
|
after_safe = end < len(source) and source[end] in boundary_chars
|
|
370
416
|
if before_safe and after_safe:
|
|
371
417
|
return match.group(0)
|
|
418
|
+
if _should_preserve_raw_punctuation_emphasis(
|
|
419
|
+
source, start, end, match.group(0), boundary_chars
|
|
420
|
+
):
|
|
421
|
+
return match.group(0)
|
|
372
422
|
|
|
373
423
|
# When either outer edge is tightly coupled to surrounding text or
|
|
374
424
|
# punctuation, wrap the whole token so Slack can treat the decoration
|
{slack_markdown_parser-2.2.4 → slack_markdown_parser-2.2.5}/slack_markdown_parser.egg-info/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: slack-markdown-parser
|
|
3
|
-
Version: 2.2.
|
|
3
|
+
Version: 2.2.5
|
|
4
4
|
Summary: Convert LLM Markdown into Slack Block Kit markdown/table messages
|
|
5
5
|
Author: darkgaldragon
|
|
6
6
|
License-Expression: MIT
|
|
@@ -61,7 +61,7 @@ If Slack itself does not support a construct in `markdown` blocks, this library
|
|
|
61
61
|
- Repair common LLM table issues such as missing outer pipes, missing separator rows, mismatched column counts, and empty cells
|
|
62
62
|
- Split output into multiple Slack messages when needed to satisfy Slack's "one table per message" constraint
|
|
63
63
|
- Sanitize ANSI/control characters and neutralize invalid Slack angle-bracket tokens before block generation
|
|
64
|
-
- Add ZWSP around inline formatting tokens to reduce rendering issues outside fenced code blocks
|
|
64
|
+
- Add ZWSP around inline formatting tokens to reduce rendering issues outside fenced code blocks, while preserving English-like punctuation-only boundaries that Slack already renders reliably
|
|
65
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
|
|
66
66
|
- Support Markdown and Slack-style links inside table cells
|
|
67
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
|
|
@@ -361,6 +361,20 @@ def test_bold_with_tight_boundary_on_left_is_wrapped_on_both_sides() -> None:
|
|
|
361
361
|
)
|
|
362
362
|
|
|
363
363
|
|
|
364
|
+
def test_english_bold_with_punctuation_on_right_stays_raw() -> None:
|
|
365
|
+
text = "• **APIYI (apiyi.com)**: OpenAI互換"
|
|
366
|
+
converted = add_zero_width_spaces_to_markdown(text)
|
|
367
|
+
|
|
368
|
+
assert converted == text
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
def test_english_bold_with_japanese_period_stays_raw() -> None:
|
|
372
|
+
text = "• **APIYI (apiyi.com)**。"
|
|
373
|
+
converted = add_zero_width_spaces_to_markdown(text)
|
|
374
|
+
|
|
375
|
+
assert converted == text
|
|
376
|
+
|
|
377
|
+
|
|
364
378
|
def test_blocks_to_plain_text_and_fallback_generation() -> None:
|
|
365
379
|
raw = """# Title
|
|
366
380
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{slack_markdown_parser-2.2.4 → slack_markdown_parser-2.2.5}/docs/slack-client-manual-checklist.md
RENAMED
|
File without changes
|
{slack_markdown_parser-2.2.4 → slack_markdown_parser-2.2.5}/docs/slack-nested-modifier-findings.md
RENAMED
|
File without changes
|
{slack_markdown_parser-2.2.4 → slack_markdown_parser-2.2.5}/docs/slack-render-test-workflow.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{slack_markdown_parser-2.2.4 → slack_markdown_parser-2.2.5}/tests/fixtures/llm_markdown_p0_corpus.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{slack_markdown_parser-2.2.4 → slack_markdown_parser-2.2.5}/tests/test_llm_markdown_p0_corpus.py
RENAMED
|
File without changes
|
{slack_markdown_parser-2.2.4 → slack_markdown_parser-2.2.5}/tests/test_nested_modifier_matrix.py
RENAMED
|
File without changes
|