114 lines
3.2 KiB
TypeScript
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,
|
|
];
|