Bug Description
slackMrkdwnToMarkdown converts Slack bold to markdown bold with
markdown.replace(/(?<![_*\\])\*([^*\n]+)\*(?![_*])/g, "**$1**");
The pattern matches any two asterisks on the same line, whatever surrounds them. A message that uses * as a multiplication sign or a wildcard has each matched asterisk doubled. The rule also runs over inline code spans, so the contents of `…` are changed.
Slack's own renderer does not show these messages as bold: its mrkdwn bold needs a non-space character directly inside each marker.
Steps to Reproduce
- In Slack, send the bot
cost is 2 * 3 seats and 4 * 5 licenses, or a message with an asterisk inside inline code such as run `rm -rf *` then 5 * 3.
- Read
message.text and stringifyMarkdown(message.formatted) in the handler, or run the code sample below, which calls the same converter the adapter uses.
Expected Behavior
Both messages come through with their asterisks unchanged and no strong node. this is *bold* text still converts to **bold**.
Actual Behavior
Input (event.text) |
message.text |
stringifyMarkdown |
cost is 2 * 3 seats and 4 * 5 licenses |
cost is 2 ** 3 seats and 4 ** 5 licenses |
cost is 2 \*\* 3 seats and 4 \*\* 5 licenses |
run `rm -rf *` then 5 * 3 |
run rm -rf ** then 5 ** 3 |
run `rm -rf **` then 5 \*\* 3 |
In the second row the match starts at the asterisk inside the code span and ends at the one outside it, so the code span's content changes from rm -rf * to rm -rf **.
Code Sample
import { SlackFormatConverter } from "@chat-adapter/slack";
import { stringifyMarkdown, toPlainText } from "chat";
const converter = new SlackFormatConverter();
for (const input of ["cost is 2 * 3 seats and 4 * 5 licenses", "run `rm -rf *` then 5 * 3"]) {
const ast = converter.toAst(input);
console.log(toPlainText(ast));
console.log(stringifyMarkdown(ast));
}
Chat SDK Version
4.30.0
Node.js Version
22.21.1
Platform Adapter
Microsoft Teams, Slack
Operating System
Linux
Additional Context
Possible approaches.
- Require a non-space character after the opening asterisk and before the closing one:
/(?<![_*\\])\*(\S(?:[^*\n]*\S)?)\*(?![_*])/g. On the inputs above it leaves both messages unchanged and still converts *bold*, *a* and *b c*, and *x*. The strikethrough rule (~…~) has the same shape and would take the same change.
- Skip inline code spans. 4.40.0 already splits the input on code fences (
convertMrkdwnWithCodeFences) so fenced code is not rewritten; inline `…` spans still are.
- When the event carries
rich_text blocks, bold is unambiguous there (style.bold on the text element), so reading formatting from blocks would avoid the regex for user-typed messages.
Bug Description
slackMrkdwnToMarkdownconverts Slack bold to markdown bold withThe pattern matches any two asterisks on the same line, whatever surrounds them. A message that uses
*as a multiplication sign or a wildcard has each matched asterisk doubled. The rule also runs over inline code spans, so the contents of`…`are changed.Slack's own renderer does not show these messages as bold: its mrkdwn bold needs a non-space character directly inside each marker.
Steps to Reproduce
cost is 2 * 3 seats and 4 * 5 licenses, or a message with an asterisk inside inline code such asrun `rm -rf *` then 5 * 3.message.textandstringifyMarkdown(message.formatted)in the handler, or run the code sample below, which calls the same converter the adapter uses.Expected Behavior
Both messages come through with their asterisks unchanged and no
strongnode.this is *bold* textstill converts to**bold**.Actual Behavior
event.text)message.textstringifyMarkdowncost is 2 * 3 seats and 4 * 5 licensescost is 2 ** 3 seats and 4 ** 5 licensescost is 2 \*\* 3 seats and 4 \*\* 5 licensesrun `rm -rf *` then 5 * 3run rm -rf ** then 5 ** 3run `rm -rf **` then 5 \*\* 3In the second row the match starts at the asterisk inside the code span and ends at the one outside it, so the code span's content changes from
rm -rf *torm -rf **.Code Sample
Chat SDK Version
4.30.0
Node.js Version
22.21.1
Platform Adapter
Microsoft Teams, Slack
Operating System
Linux
Additional Context
Possible approaches.
/(?<![_*\\])\*(\S(?:[^*\n]*\S)?)\*(?![_*])/g. On the inputs above it leaves both messages unchanged and still converts*bold*,*a* and *b c*, and*x*. The strikethrough rule (~…~) has the same shape and would take the same change.convertMrkdwnWithCodeFences) so fenced code is not rewritten; inline`…`spans still are.rich_textblocks, bold is unambiguous there (style.boldon the text element), so reading formatting fromblockswould avoid the regex for user-typed messages.