@atlaskit/editor-wikimarkup-transformer
Version:
Wiki markup transformer for JIRA and Confluence
74 lines (71 loc) • 3.33 kB
JavaScript
import { macroKeywordTokenMap } from '../../parser/tokenize/keyword';
import { code } from '../marks/code';
import { textColor } from '../marks/color';
import { em } from '../marks/em';
import { link } from '../marks/link';
import { strike } from '../marks/strike';
import { strong } from '../marks/strong';
import { subsup } from '../marks/subsup';
import { underline } from '../marks/underline';
/**
* The order of the mapping matters.
* For example, textColor will be a macro {color} so
* we want to process other marks before it.
*/
const markEncoderMapping = new Map([['em', em], ['strike', strike], ['strong', strong], ['subsup', subsup], ['underline', underline], ['textColor', textColor], ['link', link], ['code', code]]);
/**
* ADFEXP-131: Improved logic for escaping metacharacters "[" and "!"
* Before this change, any instance of "[" and "!" was being escaped
* "[" is used for mentions
* "!" is used for media
*/
const MENTION_ESCAPE_PATTERN = '(\\[~)'; // Matches pattern like [~
const MEDIA_ESCAPE_PATTERN = '(![^ !]+)(!)'; // Matches non space content between two consecutive "!" e.g. !filename.txt!
const MEDIA_GROUP_ESCAPE_PATTERN = '(\\[\\^[^ ]+)(\\])'; // Matches non space content between two consecutive "[^" "]" e.g. [^filename.txt]
/**
* Checks if the node's content needs to be escaped before continuing processing.
* Currently, the `code` mark and `codeBlock` nodes handle their own escaping, and
* therefore, should not be escaped here.
*
* @param node the current node to encode
* @param parent the parent node, if exist
* @returns true if the node should have its text escaped when encoding to wikimarkup.
*/
const isEscapeNeeded = (node, parent) => {
return !(parent && parent.type.name === 'codeBlock' || node.marks.find(m => m.type.name === 'code') !== undefined);
};
/**
* ESS-2569: Removing the backsalshes from the regex
* ADFEXP-131: Improved logic for escaping metacharacters "[" and "!"
*/
function escapingWikiFormatter(text) {
const pattern = [MENTION_ESCAPE_PATTERN,
// eslint-disable-next-line @atlassian/perf-linting/no-expensive-split-replace -- Ignored via go/ees017 (to be fixed)
...macroKeywordTokenMap.map(macro => `(${macro.regex.source.replace('^', '')})`)].join('|');
return text
// Ignored via go/ees005
// eslint-disable-next-line require-unicode-regexp
.replace(new RegExp(pattern, 'g'), '\\$&')
// Ignored via go/ees005
// eslint-disable-next-line require-unicode-regexp
.replace(new RegExp(MEDIA_ESCAPE_PATTERN, 'g'), '\\$1\\$2') // Extra step required for media as currently both ends need to be escaped e.q. !filename.txt!
// Ignored via go/ees005
// eslint-disable-next-line require-unicode-regexp
.replace(new RegExp(MEDIA_GROUP_ESCAPE_PATTERN, 'g'), '\\$1\\$2');
}
export const text = (node, {
parent
} = {}) => {
// Ignored via go/ees005
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
// Ignored via go/ees005
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
let result = isEscapeNeeded(node, parent) ? escapingWikiFormatter(node.text) : node.text;
markEncoderMapping.forEach((encoder, markName) => {
const mark = node.marks.find(m => m.type.name === markName);
if (mark) {
result = encoder(result, mark.attrs);
}
});
return result;
};