@circlesac/mack 26.2.2 → 26.2.3

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.
@@ -26,11 +26,16 @@ var slack_1 = require("../slack");
26
26
  var validation_1 = require("../validation");
27
27
  var recursionDepth = 0;
28
28
  /**
29
- * Escapes &, <, > for Slack mrkdwn format.
29
+ * Escapes &, <, > for Slack mrkdwn format while preserving Slack special
30
+ * patterns: <@U…>, <#C…>, <!here>, <!channel>, <!everyone>, <https://…>.
30
31
  * Only used in the section/mrkdwn code path (not rich_text).
31
32
  */
33
+ var SLACK_MRKDWN_PATTERN = /(<(?:@[A-Z0-9]+(?:\|[^>]+)?|#[A-Z0-9]+(?:\|[^>]+)?|![a-z]+(?:\^[^>]+)*(?:\|[^>]+)?|https?:\/\/[^>]+)>)/g;
32
34
  function escapeForMrkdwn(text) {
33
- return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
35
+ return text
36
+ .split(SLACK_MRKDWN_PATTERN)
37
+ .map(function (part, i) { return (i % 2 === 1 ? part : part.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;")); })
38
+ .join("");
34
39
  }
35
40
  function parsePlainText(element) {
36
41
  var _a;
@@ -59,8 +64,16 @@ function parseMrkdwn(element) {
59
64
  (0, validation_1.validateRecursionDepth)(recursionDepth);
60
65
  switch (element.type) {
61
66
  case "link": {
62
- var href = element.href && (0, validation_1.validateUrl)(element.href) ? element.href : "";
63
- if (!href) {
67
+ var href = element.href || "";
68
+ // Handle Slack pipe format: <url|text> parsed as autolink by marked
69
+ var pipeIndex = href.indexOf("|");
70
+ if (pipeIndex > 0) {
71
+ var url = href.slice(0, pipeIndex);
72
+ if ((0, validation_1.validateUrl)(url)) {
73
+ return "<".concat(url, "|").concat(href.slice(pipeIndex + 1), ">");
74
+ }
75
+ }
76
+ if (!(0, validation_1.validateUrl)(href)) {
64
77
  return element.tokens.flatMap(function (child) { return parseMrkdwn(child); }).join("");
65
78
  }
66
79
  return "<".concat(href, "|").concat(element.tokens.flatMap(function (child) { return parseMrkdwn(child); }).join(""), "> ");
package/package.json CHANGED
@@ -38,5 +38,5 @@
38
38
  "test": "vitest run"
39
39
  },
40
40
  "types": "build/src/index.d.ts",
41
- "version": "26.2.2"
41
+ "version": "26.2.3"
42
42
  }
@@ -39,11 +39,17 @@ type PhrasingToken =
39
39
  let recursionDepth = 0
40
40
 
41
41
  /**
42
- * Escapes &, <, > for Slack mrkdwn format.
42
+ * Escapes &, <, > for Slack mrkdwn format while preserving Slack special
43
+ * patterns: <@U…>, <#C…>, <!here>, <!channel>, <!everyone>, <https://…>.
43
44
  * Only used in the section/mrkdwn code path (not rich_text).
44
45
  */
46
+ const SLACK_MRKDWN_PATTERN = /(<(?:@[A-Z0-9]+(?:\|[^>]+)?|#[A-Z0-9]+(?:\|[^>]+)?|![a-z]+(?:\^[^>]+)*(?:\|[^>]+)?|https?:\/\/[^>]+)>)/g
47
+
45
48
  function escapeForMrkdwn(text: string): string {
46
- return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;")
49
+ return text
50
+ .split(SLACK_MRKDWN_PATTERN)
51
+ .map((part, i) => (i % 2 === 1 ? part : part.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;")))
52
+ .join("")
47
53
  }
48
54
 
49
55
  function parsePlainText(element: PhrasingToken): string[] {
@@ -78,8 +84,16 @@ function parseMrkdwn(element: Exclude<PhrasingToken, marked.Tokens.Image>): stri
78
84
 
79
85
  switch (element.type) {
80
86
  case "link": {
81
- const href = element.href && validateUrl(element.href) ? element.href : ""
82
- if (!href) {
87
+ const href = element.href || ""
88
+ // Handle Slack pipe format: <url|text> parsed as autolink by marked
89
+ const pipeIndex = href.indexOf("|")
90
+ if (pipeIndex > 0) {
91
+ const url = href.slice(0, pipeIndex)
92
+ if (validateUrl(url)) {
93
+ return `<${url}|${href.slice(pipeIndex + 1)}>`
94
+ }
95
+ }
96
+ if (!validateUrl(href)) {
83
97
  return element.tokens.flatMap((child) => parseMrkdwn(child as Exclude<PhrasingToken, marked.Tokens.Image>)).join("")
84
98
  }
85
99
  return `<${href}|${element.tokens.flatMap((child) => parseMrkdwn(child as Exclude<PhrasingToken, marked.Tokens.Image>)).join("")}> `
@@ -489,8 +489,8 @@ i18n with plurals support and easy syntax.`
489
489
  const blocks = await markdownToBlocks("Hello <@U12345> how are you?")
490
490
  const allText = JSON.stringify(blocks)
491
491
  expect(allText).toContain('"type":"section"')
492
- // User mentions in section blocks use mrkdwn format
493
- expect(allText).toContain("&lt;@U12345&gt;")
492
+ // User mentions in section blocks are preserved as Slack mrkdwn syntax
493
+ expect(allText).toContain("<@U12345>")
494
494
  })
495
495
 
496
496
  it("should parse slack formatting in list items", async () => {