@capybara-hq/plugin-telegram 0.1.0-rc.3 → 0.1.0-rc.5

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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "name": "telegram",
4
- "version": "0.1.0-rc.3",
4
+ "version": "0.1.0-rc.5",
5
5
  "publisher": "Capybara",
6
6
  "description": {
7
7
  "en": "Telegram (channel@1 bot over the Bot API: long polling or webhook, inline keyboard cards)",
@@ -17,7 +17,7 @@
17
17
  "entry": "./dist/index.mjs",
18
18
  "manifest": {
19
19
  "name": "telegram",
20
- "version": "0.1.0-rc.3",
20
+ "version": "0.1.0-rc.5",
21
21
  "sdk": "^0.1.0-rc.4",
22
22
  "provides": [
23
23
  "channel@1"
package/dist/index.mjs CHANGED
@@ -265,6 +265,102 @@ import {
265
265
  renderCardAsText
266
266
  } from "@capybara-hq/plugin-sdk";
267
267
 
268
+ // src/tables.ts
269
+ var FENCE_OPEN = /^\s*(?:```|~~~)/;
270
+ var FENCE_CLOSE = /^\s*(```|~~~)\s*$/;
271
+ var DELIM_CELL = /^:?-+:?$/;
272
+ function splitRow(line) {
273
+ let s = line.trim();
274
+ if (!/(^|[^\\])\|/.test(s)) return void 0;
275
+ if (s.startsWith("|")) s = s.slice(1);
276
+ if (s.endsWith("|") && !s.endsWith("\\|")) s = s.slice(0, -1);
277
+ const cells = [];
278
+ let cur = "";
279
+ for (let i = 0; i < s.length; i++) {
280
+ const c = s[i];
281
+ if (c === "\\" && s[i + 1] === "|") {
282
+ cur += "|";
283
+ i++;
284
+ } else if (c === "|") {
285
+ cells.push(cur.trim());
286
+ cur = "";
287
+ } else cur += c;
288
+ }
289
+ cells.push(cur.trim());
290
+ return cells;
291
+ }
292
+ var candidate = (line) => !/^\s{4,}/.test(line) && !/^\s*>/.test(line);
293
+ function delimiterRow(line, width) {
294
+ if (line === void 0 || !candidate(line)) return false;
295
+ const cells = splitRow(line);
296
+ return cells !== void 0 && cells.length === width && cells.every((c) => DELIM_CELL.test(c));
297
+ }
298
+ var fit = (cells, width) => Array.from({ length: width }, (_, i) => cells[i] ?? "");
299
+ function segmentTables(md) {
300
+ const lines = md.replace(/\r\n?/g, "\n").split("\n");
301
+ const out = [];
302
+ let text = [];
303
+ const flushText = () => {
304
+ if (text.length > 0) out.push({ kind: "text", lines: text });
305
+ text = [];
306
+ };
307
+ let inFence = false;
308
+ for (let i = 0; i < lines.length; i++) {
309
+ const line = lines[i];
310
+ if (inFence ? FENCE_CLOSE.test(line) : FENCE_OPEN.test(line)) {
311
+ inFence = !inFence;
312
+ text.push(line);
313
+ continue;
314
+ }
315
+ const header = !inFence && candidate(line) ? splitRow(line) : void 0;
316
+ if (!header || !delimiterRow(lines[i + 1], header.length)) {
317
+ text.push(line);
318
+ continue;
319
+ }
320
+ const rows = [];
321
+ let j = i + 2;
322
+ for (; j < lines.length; j++) {
323
+ const l = lines[j];
324
+ if (l.trim() === "" || FENCE_OPEN.test(l) || !candidate(l)) break;
325
+ const cells = splitRow(l);
326
+ if (!cells) break;
327
+ rows.push(fit(cells, header.length));
328
+ }
329
+ flushText();
330
+ out.push({ kind: "table", table: { header, rows } });
331
+ i = j - 1;
332
+ }
333
+ flushText();
334
+ return out;
335
+ }
336
+ var BR = /<br\s*\/?>/gi;
337
+ var CJK_END = /[⺀-鿿가-힯豈-﫿＀-￯]$/u;
338
+ var INDENT = " ";
339
+ var pair = (h, v) => h === "" ? v : `${h}${CJK_END.test(h) ? ":" : ": "}${v}`;
340
+ var lead = (cell) => /`|\*\*|__/.test(cell) ? cell : `**${cell}**`;
341
+ function tableToListMarkdown(t) {
342
+ const clean = (s) => s.replace(BR, " / ").trim();
343
+ const header = t.header.map(clean);
344
+ if (t.rows.length === 0) return [header.filter((h) => h !== "").join(" · ")];
345
+ const out = [];
346
+ for (const raw of t.rows) {
347
+ const [first = "", ...rest] = raw.map(clean);
348
+ const head = first === "" ? "" : lead(first);
349
+ const items = rest.flatMap((v, i) => v === "" ? [] : [pair(header[i + 1] ?? "", v)]);
350
+ if (head === "" && items.length === 0) continue;
351
+ if (header.length === 2) {
352
+ out.push(`- ${[head, rest[0] ?? ""].filter((s) => s !== "").join(" — ")}`);
353
+ continue;
354
+ }
355
+ out.push(`- ${head === "" ? items.shift() ?? "" : head}`);
356
+ for (const it of items) out.push(`${INDENT}${it}`);
357
+ }
358
+ return out;
359
+ }
360
+ function tablesToLists(md) {
361
+ return segmentTables(md).flatMap((s) => s.kind === "text" ? s.lines : tableToListMarkdown(s.table)).join("\n");
362
+ }
363
+
268
364
  // src/html.ts
269
365
  var TEXT_LIMIT = 4096;
270
366
  function escapeHtml(s) {
@@ -347,7 +443,7 @@ function codeBlock(lang, lines) {
347
443
  return l === "" ? `<pre>${body}</pre>` : `<pre><code class="language-${l}">${body}</code></pre>`;
348
444
  }
349
445
  function markdownToTelegramHtml(md) {
350
- const lines = md.replace(/\r\n?/g, "\n").replaceAll("\0", "").split("\n");
446
+ const lines = tablesToLists(md.replace(/\r\n?/g, "\n").replaceAll("\0", "")).split("\n");
351
447
  const out = [];
352
448
  let fence;
353
449
  let quote;
@@ -410,12 +506,12 @@ function truncateHtml(html, limit = TEXT_LIMIT) {
410
506
  const closing = /(?:<\/[a-z-]+>)*$/.exec(head)?.[0] ?? "";
411
507
  return `${head.slice(0, head.length - closing.length)}…${closing}`;
412
508
  }
413
- function fitHtml(lead, body, limit = TEXT_LIMIT) {
509
+ function fitHtml(lead2, body, limit = TEXT_LIMIT) {
414
510
  const sep = "\n\n";
415
- if (lead === "") return truncateHtml(body, limit);
416
- if (body === "") return truncateHtml(lead, limit);
511
+ if (lead2 === "") return truncateHtml(body, limit);
512
+ if (body === "") return truncateHtml(lead2, limit);
417
513
  const room = limit - visibleLength(body) - sep.length;
418
- if (room >= 2) return `${truncateHtml(lead, room)}${sep}${body}`;
514
+ if (room >= 2) return `${truncateHtml(lead2, room)}${sep}${body}`;
419
515
  return truncateHtml(body, limit);
420
516
  }
421
517
  function splitHtml(html, limit = TEXT_LIMIT) {
@@ -426,6 +522,7 @@ function splitHtml(html, limit = TEXT_LIMIT) {
426
522
  let stack = [];
427
523
  let prefix = "";
428
524
  let cand;
525
+ let nl;
429
526
  const emit = (toks, count, at) => {
430
527
  if (count > 0) parts.push(prefix + toks.map((t) => t.text).join("") + closers(at));
431
528
  };
@@ -439,6 +536,7 @@ function splitHtml(html, limit = TEXT_LIMIT) {
439
536
  continue;
440
537
  }
441
538
  if (vis + t.len > limit) {
539
+ if (nl && nl.vis >= limit / 2) cand = nl;
442
540
  if (cand && cand.vis >= limit / 2) {
443
541
  emit(cur.slice(0, cand.i), cand.vis, cand.stack);
444
542
  const rest = cur.slice(cand.i + 1);
@@ -452,8 +550,10 @@ function splitHtml(html, limit = TEXT_LIMIT) {
452
550
  cur = [];
453
551
  }
454
552
  cand = void 0;
553
+ nl = void 0;
455
554
  }
456
555
  if (/^\s$/.test(t.text)) cand = { i: cur.length, vis, stack: [...stack] };
556
+ if (t.text === "\n") nl = cand;
457
557
  cur.push(t);
458
558
  vis += t.len;
459
559
  }
@@ -1045,14 +1145,14 @@ function createTelegramChannel(o) {
1045
1145
  return text === "" ? [] : splitHtml(markdownToTelegramHtml(message.text)).map((html) => ({ html }));
1046
1146
  }
1047
1147
  const dup = cards.some((c) => cardHeadline(c, locale)?.trim() === text);
1048
- const lead = text === "" || dup ? "" : markdownToTelegramHtml(message.text);
1049
- const fit = (p, leading) => ({
1148
+ const lead2 = text === "" || dup ? "" : markdownToTelegramHtml(message.text);
1149
+ const fit2 = (p, leading) => ({
1050
1150
  ...p,
1051
1151
  html: fitHtml(leading, p.html),
1052
- ...p.withoutUrlButtons && { withoutUrlButtons: fit(p.withoutUrlButtons, leading) }
1152
+ ...p.withoutUrlButtons && { withoutUrlButtons: fit2(p.withoutUrlButtons, leading) }
1053
1153
  });
1054
1154
  const posts = await renderCards(cards, locale, cardTokenStore(o.kv, botId), o.log);
1055
- return posts.map((p, i) => fit(p, i === 0 ? lead : ""));
1155
+ return posts.map((p, i) => fit2(p, i === 0 ? lead2 : ""));
1056
1156
  }
1057
1157
  async function withUrlButtonFallback(post, attempt) {
1058
1158
  try {
@@ -1242,7 +1342,7 @@ function createTelegramChannel(o) {
1242
1342
  // src/index.ts
1243
1343
  var index_default = defineExtension({
1244
1344
  name: "telegram",
1245
- version: "0.1.0-rc.3",
1345
+ version: "0.1.0-rc.5",
1246
1346
  sdk: "^0.1.0-rc.4",
1247
1347
  provides: [CHANNEL_EXTENSION_POINT],
1248
1348
  permissions: { network: ["api.telegram.org"] },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capybara-hq/plugin-telegram",
3
- "version": "0.1.0-rc.3",
3
+ "version": "0.1.0-rc.5",
4
4
  "type": "module",
5
5
  "license": "Apache-2.0",
6
6
  "description": "Telegram (channel@1 bot over the Bot API: long polling or webhook, inline keyboard cards)",