pleroma/app/soapbox/features/compose/editor/transformers/index.ts
marcin mikołajczak e76a9ec8aa wip
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2023-04-18 23:50:26 +02:00

114 lines
3.2 KiB
TypeScript

// Adapted from: https://github.com/facebook/lexical/issues/2715#issuecomment-1209090485
import {
BOLD_ITALIC_UNDERSCORE,
BOLD_ITALIC_STAR,
BOLD_STAR,
BOLD_UNDERSCORE,
STRIKETHROUGH,
INLINE_CODE,
HEADING,
QUOTE,
ORDERED_LIST,
UNORDERED_LIST,
LINK,
TextMatchTransformer,
} from '@lexical/markdown';
const replaceEscapedChars = (text: string): string => {
// convert "\*" to "*", "\_" to "_", "\~" to "~", ...
return text
.replaceAll('\\*', '*')
.replaceAll('\\_', '_')
.replaceAll('\\-', '-')
.replaceAll('\\#', '#')
.replaceAll('\\>', '>')
.replaceAll('\\+', '+')
.replaceAll('\\~', '~');
};
const replaceUnescapedChars = (text: string, regexes: RegExp[]): string => {
// convert "*" to "", "_" to "", "~" to "" (all chars, which are not escaped - means with "\" in front)
for (const regex of regexes) {
text = text.replaceAll(regex, '');
}
return text;
};
const UNESCAPE_ITALIC_UNDERSCORE_IMPORT_REGEX =
/([\_])(?<!(?:\1|\w).)(?![_*\s])(.*?[^_*\s])(?=\1)([\_])(?!\w|\3)/;
const UNESCAPE_ITALIC_UNDERSCORE_REGEX =
/([\_])(?<!(?:\1|\w).)(?![_*\s])(.*?[^_*\s])(?=\1)([\_])(?!\w|\3)/;
export const UNESCAPE_ITALIC_UNDERSCORE: TextMatchTransformer = {
dependencies: [],
export: () => null,
importRegExp: UNESCAPE_ITALIC_UNDERSCORE_IMPORT_REGEX,
regExp: UNESCAPE_ITALIC_UNDERSCORE_REGEX,
replace: (textNode, _) => {
const notEscapedUnderscoreRegex = /(?<![\\]{1})[\_]{1}/g;
const textContent = replaceUnescapedChars(textNode.getTextContent(), [
notEscapedUnderscoreRegex,
]);
textNode.setTextContent(replaceEscapedChars(textContent));
textNode.setFormat('italic');
},
trigger: '_',
type: 'text-match',
};
const UNESCAPE_ITALIC_STAR_IMPORT_REGEX =
/([\*])(?<!(?:\1|\w).)(?![_*\s])(.*?[^_*\s])(?=\1)([\*])(?!\w|\3)/;
const UNESCAPE_ITALIC_STAR_REGEX =
/([\*])(?<!(?:\1|\w).)(?![_*\s])(.*?[^_*\s])(?=\1)([\*])(?!\w|\3)/;
export const UNESCAPE_ITALIC_STAR: TextMatchTransformer = {
dependencies: [],
export: () => null,
importRegExp: UNESCAPE_ITALIC_STAR_IMPORT_REGEX,
regExp: UNESCAPE_ITALIC_STAR_REGEX,
replace: (textNode, _) => {
const notEscapedStarRegex = /(?<![\\]{1})[\*]{1}/g;
const textContent = replaceUnescapedChars(textNode.getTextContent(), [
notEscapedStarRegex,
]);
textNode.setTextContent(replaceEscapedChars(textContent));
textNode.setFormat('italic');
},
trigger: '*',
type: 'text-match',
};
const UNESCAPE_BACKSLASH_IMPORT_REGEX = /(\\(?:\\\\)?).*?\1*[\~\*\_\{\}\[\]\(\)\#\+\-\.\!]/;
const UNESCAPE_BACKSLASH_REGEX = /(\\(?:\\\\)?).*?\1*[\~\*\_\{\}\[\]\(\)\#\+\-\.\!]$/;
export const UNESCAPE_BACKSLASH: TextMatchTransformer = {
dependencies: [],
export: () => null,
importRegExp: UNESCAPE_BACKSLASH_IMPORT_REGEX,
regExp: UNESCAPE_BACKSLASH_REGEX,
replace: (textNode, _) => {
if (textNode) {
textNode.setTextContent(replaceEscapedChars(textNode.getTextContent()));
}
},
trigger: '\\',
type: 'text-match',
};
export const TO_WYSIWYG_TRANSFORMERS = [
UNESCAPE_BACKSLASH,
BOLD_ITALIC_UNDERSCORE,
BOLD_ITALIC_STAR,
BOLD_STAR,
BOLD_UNDERSCORE,
STRIKETHROUGH,
UNESCAPE_ITALIC_UNDERSCORE,
UNESCAPE_ITALIC_STAR,
INLINE_CODE,
HEADING,
QUOTE,
ORDERED_LIST,
UNORDERED_LIST,
LINK,
];