chat_sdk-telegram 0.6.0 → 0.8.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a14fedc4aa2b77c45981da8147e152cb78770d131e1bbe234468655d0b171173
4
- data.tar.gz: 3b35d0c60617dc93afa0b706b70e80f21d5672a4a00e0f7d0db374f49c6318c4
3
+ metadata.gz: 9c7469e27cabb92ba6ed37a198b0b654bd28e41d6be5c6a7d2e869aa422ca242
4
+ data.tar.gz: 6b6c66121c254a6ec4206130f6ff1001275ce84b202ec67995cfdafd2f38add8
5
5
  SHA512:
6
- metadata.gz: b3da00035b7d571f92a05ec573212754999cf553f71608a6cf3473b9410f060951e3324a10ef520faa393dd16a17fe397d77794cdab8b175ab86909c0fc90501
7
- data.tar.gz: fb63c59d2e3a750530ff211f392b35b3003b5afa8e7bb7f7c277149bebc6d32ca4cc69f85c473428be9419359b1162a6d7ed7843472343069cbeef503b6255f7
6
+ metadata.gz: 6f13191588083d918d717038d6946270de24fc34b578120009045c27c4bc64d1800f444846af8db9734e80edf8ae03c9eb26f2e33a149f422ba59f469eaf22b1
7
+ data.tar.gz: 61425a3e878f398cd1222d6827bee44a1e84ab035103c3606f734856fb8588b322c97945d274aaa23e59ab0f67602f09143a712c919174c4c9a56509eac2df2b
@@ -0,0 +1,124 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ChatSDK
4
+ module Telegram
5
+ class FormatConverter < ChatSDK::Format::Converter
6
+ SPECIAL_CHARS = %w[_ * [ ] ( ) ~ \\ ` > # + - = | { } . !].freeze
7
+ ESCAPE_RE = Regexp.union(SPECIAL_CHARS).freeze
8
+
9
+ # Telegram MarkdownV2 → standard Markdown
10
+ def to_markdown(platform_text)
11
+ text = platform_text.to_s
12
+ return "" if text.empty?
13
+
14
+ # Convert Telegram user links: [text](tg://user?id=123) → @123
15
+ text = text.gsub(/\[([^\]]*)\]\(tg:\/\/user\?id=(\d+)\)/, '@\2')
16
+
17
+ # Strip underline markers: __text__ → text
18
+ # Use a loop to handle nested cases
19
+ text = text.gsub(/(?<!_)__(?!_)(.+?)(?<!_)__(?!_)/m, '\1')
20
+
21
+ # Strip spoiler markers: ||text|| → text
22
+ text = text.gsub(/\|\|(.+?)\|\|/m, '\1')
23
+
24
+ # Unescape all backslash-escaped characters
25
+ text.gsub(/\\(.)/, '\1')
26
+ end
27
+
28
+ # Standard Markdown → Telegram MarkdownV2
29
+ def from_markdown(markdown)
30
+ text = markdown.to_s
31
+ return "" if text.empty?
32
+
33
+ parts = split_code_segments(text)
34
+ parts.map.with_index { |part, i| i.odd? ? part : escape_special_chars(part) }.join
35
+ end
36
+
37
+ private
38
+
39
+ # Splits text into alternating [text, code, text, code, ...] segments.
40
+ # Odd-indexed segments are code blocks/inline code and are NOT escaped.
41
+ def split_code_segments(text)
42
+ text.split(/(```[\s\S]*?```|`[^`]+`)/)
43
+ end
44
+
45
+ # Escape Telegram MarkdownV2 special chars outside of markdown syntax.
46
+ # Preserves bold (**), italic (*), strikethrough (~~), links, etc.
47
+ def escape_special_chars(text)
48
+ result = +""
49
+ i = 0
50
+ chars = text.chars
51
+
52
+ while i < chars.length
53
+ char = chars[i]
54
+
55
+ # Bold: **text** — pass through
56
+ if char == "*" && chars[i + 1] == "*"
57
+ close = text.index("**", i + 2)
58
+ if close
59
+ inner = text[(i + 2)...close]
60
+ result << "**#{escape_special_chars(inner)}**"
61
+ i = close + 2
62
+ next
63
+ end
64
+ end
65
+
66
+ # Italic: *text* (single asterisk, not preceded/followed by another *)
67
+ if char == "*" && chars[i + 1] != "*"
68
+ close = find_single_asterisk_close(chars, i + 1)
69
+ if close
70
+ inner = chars[(i + 1)...close].join
71
+ result << "*#{escape_special_chars(inner)}*"
72
+ i = close + 1
73
+ next
74
+ end
75
+ end
76
+
77
+ # Strikethrough: ~~text~~
78
+ if char == "~" && chars[i + 1] == "~"
79
+ close = text.index("~~", i + 2)
80
+ if close
81
+ inner = text[(i + 2)...close]
82
+ result << "~~#{escape_special_chars(inner)}~~"
83
+ i = close + 2
84
+ next
85
+ end
86
+ end
87
+
88
+ # Links: [text](url) — pass through
89
+ if char == "["
90
+ link_match = text[i..].match(/\A\[([^\]]*)\]\(([^)]*)\)/)
91
+ if link_match
92
+ result << link_match[0]
93
+ i += link_match[0].length
94
+ next
95
+ end
96
+ end
97
+
98
+ # Escape special characters
99
+ result << if SPECIAL_CHARS.include?(char)
100
+ "\\#{char}"
101
+ else
102
+ char
103
+ end
104
+
105
+ i += 1
106
+ end
107
+
108
+ result
109
+ end
110
+
111
+ # Find closing single * that isn't part of **
112
+ def find_single_asterisk_close(chars, start)
113
+ i = start
114
+ while i < chars.length
115
+ if chars[i] == "*" && chars[i + 1] != "*" && (i == start || chars[i - 1] != "*")
116
+ return i
117
+ end
118
+ i += 1
119
+ end
120
+ nil
121
+ end
122
+ end
123
+ end
124
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chat_sdk-telegram
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Quentin Rousseau
@@ -48,6 +48,7 @@ files:
48
48
  - lib/chat_sdk/telegram/adapter.rb
49
49
  - lib/chat_sdk/telegram/api_client.rb
50
50
  - lib/chat_sdk/telegram/event_parser.rb
51
+ - lib/chat_sdk/telegram/format_converter.rb
51
52
  - lib/chat_sdk/telegram/keyboard_renderer.rb
52
53
  homepage: https://github.com/rootlyhq/chat-sdk
53
54
  licenses: