11import json
2- from typing import Any , Dict , List , Optional , Tuple
2+ from typing import Any , Callable , List , Optional , Tuple
33
4+ from pydantic import BaseModel
45from slack_sdk .models import blocks as slack_blocks
56from tabulate import tabulate
67
1415 Icon ,
1516 IconBlock ,
1617 InlineBlock ,
18+ InlineCodeBlock ,
1719 LineBlock ,
1820 LinesBlock ,
1921 LinkBlock ,
22+ MentionBlock ,
2023 TableBlock ,
2124 TextBlock ,
2225 TextStyle ,
3134}
3235
3336
37+ class FormattedBlockKitMessage (BaseModel ):
38+ blocks : List [dict ]
39+ attachments : List [dict ]
40+
41+
42+ ResolveMentionCallback = Callable [[str ], Optional [str ]]
43+
44+
3445class BlockKitBuilder :
3546 _SECONDARY_FACT_CHUNK_SIZE = 2
3647 _LONGEST_MARKDOWN_SUFFIX_LEN = 3 # length of markdown's code suffix (```)
3748 _MAX_CELL_LENGTH_BY_COLUMN_COUNT = {4 : 11 , 3 : 14 , 2 : 22 , 1 : 40 , 0 : 40 }
3849
39- def __init__ (self ) -> None :
50+ def __init__ (
51+ self , resolve_mention : Optional [ResolveMentionCallback ] = None
52+ ) -> None :
4053 self ._blocks : List [dict ] = []
4154 self ._attachment_blocks : List [dict ] = []
4255 self ._is_divided = False
56+ self ._resolve_mention = resolve_mention or (lambda x : None )
4357
4458 def _format_icon (self , icon : Icon ) -> str :
4559 return ICON_TO_HTML [icon ]
@@ -59,6 +73,16 @@ def _format_inline_block(self, block: InlineBlock) -> str:
5973 return self ._format_text_block (block )
6074 elif isinstance (block , LinkBlock ):
6175 return f"<{ block .url } |{ block .text } >"
76+ elif isinstance (block , InlineCodeBlock ):
77+ return f"`{ block .code } `"
78+ elif isinstance (block , MentionBlock ):
79+ resolved_user = self ._resolve_mention (block .user )
80+ if resolved_user :
81+ return f"<@{ resolved_user } >"
82+ else :
83+ return block .user
84+ elif isinstance (block , LineBlock ):
85+ return self ._format_line_block_text (block )
6286 else :
6387 raise ValueError (f"Unsupported inline block type: { type (block )} " )
6488
@@ -192,12 +216,6 @@ def _add_expandable_block(self, block: ExpandableBlock) -> None:
192216 Expandable blocks are not supported in Slack Block Kit.
193217 However, slack automatically collapses a large section block into an expandable block.
194218 """
195- self ._add_block (
196- {
197- "type" : "section" ,
198- "text" : self ._format_markdown_section_text (f"*{ block .title } *" ),
199- }
200- )
201219 self ._add_message_blocks (block .body )
202220
203221 def _add_message_block (self , block : MessageBlock ) -> None :
@@ -239,25 +257,28 @@ def _get_final_blocks(
239257 else :
240258 return [], self ._blocks
241259
242- def build (self , message : MessageBody ) -> Dict [ str , Any ] :
260+ def build (self , message : MessageBody ) -> FormattedBlockKitMessage :
243261 self ._blocks = []
244262 self ._attachment_blocks = []
245263 self ._add_message_blocks (message .blocks )
246264 color_code = COLOR_MAP .get (message .color ) if message .color else None
247265 blocks , attachment_blocks = self ._get_final_blocks (message .color )
248- built_message = {
249- " blocks" : blocks ,
250- " attachments" : [
266+ built_message = FormattedBlockKitMessage (
267+ blocks = blocks ,
268+ attachments = [
251269 {
252270 "blocks" : attachment_blocks ,
253271 }
254272 ],
255- }
273+ )
256274 if color_code :
257- built_message ["attachments" ][0 ]["color" ] = color_code
275+ for attachment in built_message .attachments :
276+ attachment ["color" ] = color_code
258277 return built_message
259278
260279
261- def format_block_kit (message : MessageBody ) -> Dict [str , Any ]:
262- builder = BlockKitBuilder ()
280+ def format_block_kit (
281+ message : MessageBody , resolve_mention : Optional [ResolveMentionCallback ] = None
282+ ) -> FormattedBlockKitMessage :
283+ builder = BlockKitBuilder (resolve_mention )
263284 return builder .build (message )
0 commit comments