Skip to content

Commit

Permalink
rename 'shouldKeepWhiteSpace' to 'shouldKeepRawInput' & implement sep…
Browse files Browse the repository at this point in the history
…erate functions for raw input replacements
  • Loading branch information
robertKozik committed Dec 20, 2023
1 parent c6bb3cf commit 38a44f9
Showing 1 changed file with 45 additions and 16 deletions.
61 changes: 45 additions & 16 deletions lib/ExpensiMark.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ export default class ExpensiMark {
const group = textWithinFences.replace(/(?:(?![\n\r])\s)/g, ' ');
return `<pre>${group}</pre>`;
},
rawInputReplacement: (match, __, textWithinFences) => {
const withinFences = match.replace(/(?:&#x60;&#x60;&#x60;)([\s\S]*?)(?:&#x60;&#x60;&#x60;)/g, '$1');
const group = textWithinFences.replace(/(?:(?![\n\r])\s)/g, '&#32;');
return `<pre data-code-raw="${_.escape(withinFences)}">${group}</pre>`;
}
},

/**
Expand All @@ -59,11 +64,11 @@ export default class ExpensiMark {
*/
{
name: 'email',
process: (textToProcess, replacement) => {
process: (textToProcess, replacement, shouldKeepRawInput) => {
const regex = new RegExp(
`(?!\\[\\s*\\])\\[([^[\\]]*)]\\((mailto:)?${CONST.REG_EXP.MARKDOWN_EMAIL}\\)`, 'gim'
);
return this.modifyTextForEmailLinks(regex, textToProcess, replacement);
return this.modifyTextForEmailLinks(regex, textToProcess, replacement, shouldKeepRawInput);
},
replacement: (match, g1, g2) => {
if (g1.match(CONST.REG_EXP.EMOJIS) || !g1.trim()) {
Expand All @@ -74,12 +79,21 @@ export default class ExpensiMark {
const formattedLabel = label === href ? g2 : label;
return `<a href="${href}">${formattedLabel}</a>`;
},
rawInputReplacement: (match, g1, g2, g3) => {
if (g1.match(CONST.REG_EXP.EMOJIS) || !g1.trim()) {
return match;
}

const dataRawHref = g2 ? g2 + g3 : g3;
const href = `mailto:${g3}`;
return `<a href="${href}" data-raw-href="${dataRawHref}" data-link-variant="labeled">${g1}</a>`;
}
},

{
name: 'heading1',
process: (textToProcess, replacement, shouldKeepWhitespace = false) => {
const regexp = shouldKeepWhitespace ? /^# ( *(?! )(?:(?!<pre>|\n|\r\n).)+)/gm : /^# +(?! )((?:(?!<pre>|\n|\r\n).)+)/gm;
process: (textToProcess, replacement, shouldKeepRawInput = false) => {
const regexp = shouldKeepRawInput ? /^# ( *(?! )(?:(?!<pre>|\n|\r\n).)+)/gm : /^# +(?! )((?:(?!<pre>|\n|\r\n).)+)/gm;
return textToProcess.replace(regexp, replacement);
},
replacement: '<h1>$1</h1>',
Expand All @@ -100,6 +114,12 @@ export default class ExpensiMark {
}
return `<a href="${Str.sanitizeURL(g2)}" target="_blank" rel="noreferrer noopener">${g1.trim()}</a>`;
},
rawInputReplacement: (match, g1, g2) => {
if (g1.match(CONST.REG_EXP.EMOJIS) || !g1.trim()) {
return match;
}
return `<a href="${Str.sanitizeURL(g2)}" data-raw-href="${g2}" data-link-variant="labeled" target="_blank" rel="noreferrer noopener">${g1.trim()}</a>`;
}
},

/**
Expand Down Expand Up @@ -162,6 +182,10 @@ export default class ExpensiMark {
const href = Str.sanitizeURL(g2);
return `${g1}<a href="${href}" target="_blank" rel="noreferrer noopener">${g2}</a>${g1}`;
},
rawInputReplacement: (_match, g1, g2) => {
const href = Str.sanitizeURL(g2);
return `${g1}<a href="${href}" data-raw-href="${g2}" data-link-variant="auto" target="_blank" rel="noreferrer noopener">${g2}</a>${g1}`;
}
},

{
Expand All @@ -170,24 +194,24 @@ export default class ExpensiMark {
// We also want to capture a blank line before or after the quote so that we do not add extra spaces.
// block quotes naturally appear on their own line. Blockquotes should not appear in code fences or
// inline code blocks. A single prepending space should be stripped if it exists
process: (textToProcess, replacement, shouldKeepWhitespace = false) => {
process: (textToProcess, replacement, shouldKeepRawInput = false) => {
const regex = new RegExp(
/^&gt; *(?! )(?![^<]*(?:<\/pre>|<\/code>))([^\v\n\r]+)/gm,
);
if (shouldKeepWhitespace) {
return textToProcess.replace(regex, g1 => replacement(g1, shouldKeepWhitespace));
if (shouldKeepRawInput) {
return textToProcess.replace(regex, g1 => replacement(g1, shouldKeepRawInput));
}
return this.modifyTextForQuote(regex, textToProcess, replacement);
},
replacement: (g1, shouldKeepWhitespace = false) => {
replacement: (g1, shouldKeepRawInput = false) => {
// We want to enable 2 options of nested heading inside the blockquote: "># heading" and "> # heading".
// To do this we need to parse body of the quote without first space
let isStartingWithSpace = false;
const textToReplace = g1.replace(/^&gt;( )?/gm, (match, g2) => {
isStartingWithSpace = !!g2;
return '';
});
const replacedText = this.replace(textToReplace, {filterRules: ['heading1'], shouldEscapeText: false, shouldKeepWhitespace});
const replacedText = this.replace(textToReplace, {filterRules: ['heading1'], shouldEscapeText: false, shouldKeepRawInput});
return `<blockquote>${isStartingWithSpace ? ' ' : ''}${replacedText}</blockquote>`;
},
},
Expand Down Expand Up @@ -228,6 +252,7 @@ export default class ExpensiMark {
'gim',
),
replacement: '$1<a href="mailto:$2">$2</a>',
rawInputReplacement: '$1<a href="mailto:$2" data-raw-href="$2" data-link-variant="auto">$2</a>',
},

{
Expand Down Expand Up @@ -437,10 +462,10 @@ export default class ExpensiMark {
*
* @returns {String}
*/
replace(text, {filterRules = [], shouldEscapeText = true, shouldKeepWhitespace = false} = {}) {
replace(text, {filterRules = [], shouldEscapeText = true, shouldKeepRawInput = false} = {}) {
// This ensures that any html the user puts into the comment field shows as raw html
let replacedText = shouldEscapeText ? _.escape(text) : text;
const excludeRules = shouldKeepWhitespace ? _.union(this.shouldKeepWhitespaceRules, filterRules) : filterRules;
const excludeRules = shouldKeepRawInput ? _.union(this.shouldKeepWhitespaceRules, filterRules) : filterRules;
const rules = _.isEmpty(excludeRules) ? this.rules : _.filter(this.rules, rule => _.contains(excludeRules, rule.name));

try {
Expand All @@ -449,11 +474,11 @@ export default class ExpensiMark {
if (rule.pre) {
replacedText = rule.pre(replacedText);
}

const replacementFunction = shouldKeepRawInput && rule.rawInputReplacement ? rule.rawInputReplacement : rule.replacement;
if (rule.process) {
replacedText = rule.process(replacedText, rule.replacement, shouldKeepWhitespace);
replacedText = rule.process(replacedText, replacementFunction, shouldKeepRawInput);
} else {
replacedText = replacedText.replace(rule.regex, rule.replacement);
replacedText = replacedText.replace(rule.regex, replacementFunction);
}

// Post-process text after applying regex
Expand Down Expand Up @@ -585,10 +610,11 @@ export default class ExpensiMark {
* @param {RegExp} regex
* @param {String} textToCheck
* @param {Function} replacement
* @param {Boolean} shouldKeepRawInput
*
* @returns {String}
*/
modifyTextForEmailLinks(regex, textToCheck, replacement) {
modifyTextForEmailLinks(regex, textToCheck, replacement, shouldKeepRawInput) {
let match = regex.exec(textToCheck);
let replacedText = '';
let startIndex = 0;
Expand All @@ -602,7 +628,10 @@ export default class ExpensiMark {
filterRules: ['bold', 'strikethrough', 'italic'],
shouldEscapeText: false,
});
replacedText = replacedText.concat(replacement(match[0], linkText, match[3]));

// rawInputReplacment needs to be called with additional parameters from match
const replacedMatch = shouldKeepRawInput ? replacement(match[0], linkText, match[2], match[3]) : replacement(match[0], linkText, match[3]);
replacedText = replacedText.concat(replacedMatch);
startIndex = match.index + (match[0].length);

// Now we move to the next match that the js regex found in the text
Expand Down

0 comments on commit 38a44f9

Please sign in to comment.