2017-06-08 18:02:30 -04:00
|
|
|
// since the markdown.it interface is a bit on the verbose side
|
|
|
|
// we can keep some general patterns here
|
|
|
|
|
|
|
|
|
|
|
|
export default null;
|
|
|
|
|
|
|
|
// creates a rule suitable for inline parsing and replacement
|
|
|
|
//
|
|
|
|
// example:
|
|
|
|
// const rule = inlineRegexRule(md, {
|
|
|
|
// start: '#',
|
|
|
|
// matcher: /^#([\w-:]{1,101})/i,
|
|
|
|
// emitter: emitter
|
|
|
|
// });
|
|
|
|
export function inlineRegexRule(md, options) {
|
|
|
|
|
|
|
|
const start = options.start.charCodeAt(0);
|
|
|
|
const maxLength = (options.maxLength || 500) + 1;
|
|
|
|
|
2017-06-29 12:48:04 -04:00
|
|
|
return function(state, silent) {
|
2017-06-08 18:02:30 -04:00
|
|
|
const pos = state.pos;
|
|
|
|
|
2017-06-29 12:48:04 -04:00
|
|
|
if (state.src.charCodeAt(pos) !== start || silent) {
|
2017-06-08 18:02:30 -04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// test prev
|
|
|
|
if (pos > 0) {
|
|
|
|
let prev = state.src.charCodeAt(pos-1);
|
|
|
|
if (!md.utils.isSpace(prev) && !md.utils.isPunctChar(String.fromCharCode(prev))) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// skip if in a link
|
|
|
|
if (options.skipInLink && state.tokens) {
|
2017-06-29 12:48:04 -04:00
|
|
|
let i;
|
|
|
|
for(i=state.tokens.length-1;i>=0;i--) {
|
|
|
|
let token = state.tokens[i];
|
|
|
|
let type = token.type;
|
|
|
|
if (type === 'link_open' || (type === 'html_inline' && token.content.substr(0,2) === "<a")) {
|
2017-06-08 18:02:30 -04:00
|
|
|
return false;
|
|
|
|
}
|
2017-06-29 12:48:04 -04:00
|
|
|
if (type.block || type === 'link_close' || (type === 'html_inline' && token.content.substr(0,3).toLowerCase() === "</a>")) {
|
|
|
|
break;
|
2017-06-08 18:02:30 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const substr = state.src.slice(pos, Math.min(pos + maxLength,state.posMax));
|
|
|
|
|
|
|
|
const matches = options.matcher.exec(substr);
|
|
|
|
if (!matches) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// got to test trailing boundary
|
|
|
|
const finalPos = pos+matches[0].length;
|
|
|
|
if (finalPos < state.posMax) {
|
|
|
|
const trailing = state.src.charCodeAt(finalPos);
|
|
|
|
if (!md.utils.isSpace(trailing) && !md.utils.isPunctChar(String.fromCharCode(trailing))) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (options.emitter(matches, state)) {
|
|
|
|
state.pos = Math.min(state.posMax, finalPos);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
// based off https://github.com/markdown-it/markdown-it-emoji/blob/master/dist/markdown-it-emoji.js
|
|
|
|
//
|
|
|
|
export function textReplace(state, callback) {
|
|
|
|
var i, j, l, tokens, token,
|
|
|
|
blockTokens = state.tokens,
|
|
|
|
autolinkLevel = 0;
|
|
|
|
|
|
|
|
for (j = 0, l = blockTokens.length; j < l; j++) {
|
|
|
|
if (blockTokens[j].type !== 'inline') { continue; }
|
|
|
|
tokens = blockTokens[j].children;
|
|
|
|
|
|
|
|
// We scan from the end, to keep position when new tags added.
|
|
|
|
// Use reversed logic in links start/end match
|
|
|
|
for (i = tokens.length - 1; i >= 0; i--) {
|
|
|
|
token = tokens[i];
|
|
|
|
|
|
|
|
if (token.type === 'link_open' || token.type === 'link_close') {
|
|
|
|
if (token.info === 'auto') { autolinkLevel -= token.nesting; }
|
|
|
|
}
|
|
|
|
|
|
|
|
if (token.type === 'text' && autolinkLevel === 0) {
|
|
|
|
let split;
|
|
|
|
if(split = callback(token.content, state)) {
|
|
|
|
// replace current node
|
|
|
|
blockTokens[j].children = tokens = state.md.utils.arrayReplaceAt(
|
|
|
|
tokens, i, split
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|