@atlaskit/editor-wikimarkup-transformer
Version:
Wiki markup transformer for JIRA and Confluence
182 lines (177 loc) • 4.94 kB
JavaScript
import { isBlank, isDigit, isNotBlank, StringBuffer } from '../../utils/text';
/*
* This implementation is ported from JIRA with minimal modifications
* It uses a mutable "StringBuffer" to parse links. It would be ideal to
* move this to operating on immutable strings instead if possible
*
* TODO: CS-596 Replace string buffer usage with strings
*/
function trimIfPossible(s) {
if (s === null) {
return null;
}
return s.trim();
}
function extractLinkBody(buffer) {
const indexOfBang = buffer.indexOf('!');
const indexOfPipe = buffer.indexOf('|');
const lastIndexOfBang = buffer.lastIndexOf('!');
const notEscaped = indexOfBang === -1 || indexOfBang > indexOfPipe || indexOfBang === lastIndexOfBang;
if (notEscaped) {
return divideOn(buffer, '|');
}
const body = new StringBuffer();
let inEscape = false;
for (let i = 0; i < buffer.length(); i++) {
const c = buffer.charAt(i);
if (c === '!') {
inEscape = !inEscape;
}
if (c === '|' && !inEscape) {
buffer.delete(0, i + 1);
return body.toString();
}
body.append(c);
}
return null;
}
function divideAfterLast(buffer, divider) {
if (buffer.length() === 0) {
return null;
}
return divideAfter(buffer, buffer.lastIndexOf(divider));
}
function divideAfter(buffer, index) {
if (typeof index === 'string') {
index = buffer.indexOf(index);
}
if (index < 0) {
return null;
} else if (index === buffer.length() - 1) {
buffer.deleteCharAt(buffer.length() - 1);
return null;
} else {
const body = buffer.substring(index + 1);
buffer.delete(index, buffer.length());
return body;
}
}
/**
* Split a StringBuffer on some dividing character. Return everything before the divider,
* and remove that prefix _and_ the divider from the StringBuffer. If there is no divider,
* return null.
* <p/>
* If the buffer begins with the divider, then the divider will be removed _and_ null returned.
* If the buffer ends with the divider, everything before the divider is returned and the buffer
* will remain empty.
*
* @param buffer the text we want to divide. Will be modified during the operation
* @param divider the character to divide the buffer on
* @return the characters before the divider, or the default if there are none
*/
function divideOn(buffer, divider) {
if (buffer.length() === 0) {
return null;
}
const i = buffer.indexOf(divider);
if (i < 0) {
return null;
} else if (i === 0) {
buffer.deleteCharAt(0);
return null;
} else {
const body = buffer.substring(0, i);
buffer.delete(0, i + 1);
return body;
}
}
function extractNumber(buf) {
const digits = new StringBuffer();
let i = 0;
for (; i < buf.length() && isDigit(buf.charAt(i)); i++) {
digits.append(buf.charAt(i));
}
if (i > 0) {
buf.delete(0, i);
}
try {
return parseInt(digits.toString(), 10);
} catch (e) {
return 0;
}
}
export function parseLink(linkText) {
const originalLinkText = linkText;
// we want to decode single quotes (represented by ') back before parsing the link test
if (linkText.indexOf(''') !== -1) {
linkText = linkText.replace(''', "'");
}
const buf = new StringBuffer(linkText);
const linkBody = extractLinkBody(buf);
const linkTitle = trimIfPossible(divideAfter(buf, '|'));
const notLinkBody = buf.toString().trim();
return {
originalLinkText,
linkBody,
linkTitle,
notLinkBody
};
}
export function parseContentLink(link) {
if (typeof link === 'string') {
link = parseLink(link);
}
const {
notLinkBody
} = link;
let shortcutName = null;
let shortcutValue = null;
let spaceKey = null;
let attachmentName = null;
let anchor = null;
let destinationTitle = '';
let contentId = 0;
// Don't treat it as a short link when it starts with "~"
if (!notLinkBody.startsWith('~')) {
const shortcutBuf = new StringBuffer(notLinkBody);
shortcutName = trimIfPossible(divideAfterLast(shortcutBuf, '@'));
if (isNotBlank(shortcutName)) {
shortcutValue = shortcutBuf.toString();
}
}
const buf = new StringBuffer(notLinkBody);
if (isBlank(shortcutName)) {
spaceKey = trimIfPossible(divideOn(buf, ':'));
if (buf.indexOf('$') === 0) {
buf.deleteCharAt(0);
contentId = extractNumber(buf);
if (contentId === 0) {
return {
...link,
shortcutName,
shortcutValue,
spaceKey,
contentId,
attachmentName,
anchor,
destinationTitle
};
}
}
attachmentName = trimIfPossible(divideAfter(buf, '^'));
anchor = trimIfPossible(divideAfter(buf, '#'));
}
if (contentId === 0) {
destinationTitle = buf.toString().trim();
}
return {
...link,
shortcutName,
shortcutValue,
spaceKey,
contentId,
attachmentName,
anchor,
destinationTitle
};
}