Building Slack integration
This commit is contained in:
53
backend/lib/slackText.ts
Normal file
53
backend/lib/slackText.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* Slack delivers mrkdwn, not plain text. Link syntax and HTML entities that
|
||||
* survive into a note degrade embedding quality and read as noise on a sticky,
|
||||
* so they are unwrapped here. Pure and dependency-free so both the normalizer
|
||||
* and the API client can use it.
|
||||
*/
|
||||
|
||||
const ENTITIES: Record<string, string> = {
|
||||
'&': '&',
|
||||
'<': '<',
|
||||
'>': '>',
|
||||
};
|
||||
|
||||
const unescapeEntities = (text: string): string =>
|
||||
text.replace(/&(?:amp|lt|gt);/g, (match) => ENTITIES[match] ?? match);
|
||||
|
||||
const splitOnce = (value: string, separator: string): [string, string | undefined] => {
|
||||
const index = value.indexOf(separator);
|
||||
if (index === -1) return [value, undefined];
|
||||
return [value.slice(0, index), value.slice(index + separator.length)];
|
||||
};
|
||||
|
||||
const BROADCASTS: readonly string[] = ['here', 'channel', 'everyone'];
|
||||
|
||||
const MARKUP = /<([^<>]*)>/g;
|
||||
|
||||
const unwrap = (inner: string): string => {
|
||||
const [target, rawLabel] = splitOnce(inner, '|');
|
||||
const label = rawLabel !== undefined && rawLabel.length > 0 ? rawLabel : undefined;
|
||||
|
||||
if (target.startsWith('@')) return `@${label ?? target.slice(1)}`;
|
||||
if (target.startsWith('#')) return `#${label ?? target.slice(1)}`;
|
||||
|
||||
if (target.startsWith('!')) {
|
||||
const special = target.slice(1);
|
||||
if (BROADCASTS.includes(special)) return `@${special}`;
|
||||
return label ?? `@${special}`;
|
||||
}
|
||||
|
||||
if (target.startsWith('mailto:')) return label ?? target.slice('mailto:'.length);
|
||||
|
||||
return label ?? target;
|
||||
};
|
||||
|
||||
/**
|
||||
* Entities are unescaped only after markup is unwrapped. Slack escapes a
|
||||
* literal `<` as `<` precisely so it is not read as markup, and reversing
|
||||
* that order would turn user text into parsed link syntax.
|
||||
*/
|
||||
export const cleanSlackText = (input: string): string =>
|
||||
unescapeEntities(input.replace(MARKUP, (_match, inner: string) => unwrap(inner)))
|
||||
.replace(/[ \t]+$/gm, '')
|
||||
.trim();
|
||||
Reference in New Issue
Block a user