Newer
Older
// block
QUOTE,
SEARCH,
CODE_BLOCK,
MATH_BLOCK,
CENTER,
// inline
UNI_EMOJI,
EMOJI_CODE,
BOLD,
SMALL,
ITALIC,
STRIKE,
INLINE_CODE,
MATH_INLINE,
MENTION,
HASHTAG,
N_URL,
LINK,
FN,
TEXT
} = require('./node');
const {
mergeText,
setConsumeCount,
consumeDynamically
} = require('./util');
return parseFunc(input, startRule ? { startRule } : { });
const emojiRegex = require('twemoji-parser/dist/lib/regex').default;
const anchoredEmojiRegex = RegExp(`^(?:${emojiRegex.source})`);
/**
* check if the input matches the emoji regexp.
* if they match, set the byte length of the emoji.
*/
function matchUnicodeEmoji() {
const offset = location().start.offset;
const src = input.substr(offset);
const result = anchoredEmojiRegex.exec(src);
if (result != null) {
setConsumeCount(result[0].length); // length(utf-16 byte length) of emoji sequence.
//
// parsers
//
fullParser
= nodes:(&. n:(block / inline) { return n; })* { return mergeText(nodes); }
= nodes:(&. n:(emojiCode / unicodeEmoji / plainText) { return n; })* { return mergeText(nodes); }
= nodes:(&. n:inline { return n; })* { return mergeText(nodes); }
//
// block rules
//
return SEARCH(q, `${ q }${ sp }${ key }`);
return CODE_BLOCK(code, lang.length > 0 ? lang : null);
return MATH_BLOCK(formula.trim());
mathBlockLines
= mathBlockLine (LF mathBlockLine)*
{ return text(); }
mathBlockLine
= BEGIN "<center>" LF? content:(!(LF? "</center>" END) i:inline { return i; })+ LF? "</center>" END
return CENTER(mergeText(content));
// NOTE: if the text matches one of the emojis, it will count the length of the emoji sequence and consume it.
unicodeEmoji
= &{ return matchUnicodeEmoji(); } (&{ return consumeDynamically(); } .)+
return FN('tada', { }, mergeText(content));
return BOLD(mergeText(content));
// inline: small
small
= "<small>" content:(!"</small>" i:inline { return i; })+ "</small>"
{
return SMALL(mergeText(content));
return ITALIC(mergeText(content));
italicAlt
= "*" content:$(!"*" ([a-z0-9]i / _))+ "*" &(LF / _)
// inline: strike
strike
= "~~" content:(!("~" / LF) i:inline { return i; })+ "~~"
{
return STRIKE(mergeText(content));
// inline: inlineCode
inlineCode
= "`" content:$(!"`" c:CHAR { return c; })+ "`"
{
// inline: mathInline
mathInline
= "\\(" content:$(!"\\)" c:CHAR { return c; })+ "\\)"
{
// inline: mention
mention
= "@" name:mentionName host:("@" host:mentionHost { return host; })?
{
return MENTION(name, host, text());
}
mentionName
= !"-" mentionNamePart+ // first char is not "-".
{
return text();
}
mentionNamePart
= "-" &mentionNamePart // last char is not "-".
/ [a-z0-9_]i
mentionHost
= ![.-] mentionHostPart+ // first char is neither "." nor "-".
{
return text();
}
mentionHostPart
= [.-] &mentionHostPart // last char is neither "." nor "-".
/ [a-z0-9_]i
= "#" !("\uFE0F"? "\u20E3") content:hashtagContent
}
hashtagContent
= (hashtagBracketPair / hashtagChar)+ { return text(); }
hashtagBracketPair
= "(" hashtagContent* ")"
/ "[" hashtagContent* "]"
/ "「" hashtagContent* "」"
hashtagChar
= ![ \t.,!?'"#:\/\[\]【】()「」] CHAR
}
urlFormat
= "http" "s"? "://" urlContent
{
return text();
}
urlContent
= urlContentPart+
urlContentPart
= urlBracketPair
/ [.,] &urlContentPart // last char is neither "." nor ",".
urlBracketPair
= "(" urlContentPart* ")"
/ "[" urlContentPart* "]"
= silent:"?"? "[" label:linkLabelPart+ "](" url:linkUrl ")"
return LINK((silent != null), url, mergeText(label));
linkLabelPart
= url { return text(); /* text node */ }
/ link { return text(); /* text node */ }
// inline: fn
fn
= "[" name:$([a-z0-9_]i)+ args:fnArgs? _ content:(!"]" i:inline { return i; })+ "]"
{
args = args || {};
return FN(name, args, mergeText(content));
}
fnArgs
= "." head:fnArg tails:("," arg:fnArg { return arg; })*
{
const args = { };
for (const pair of [head, ...tails]) {
args[pair.k] = pair.v;
}
return args;
}
fnArg
{
return { k, v };
}
/ k:$([a-z0-9_]i)+
{
return { k: k, v: true };
}
= !(LF / _) . &(hashtag / mention / italicAlt) . { return text(); } // hashtag, mention, italic ignore
/ . /* text node */
// inline: text (for plainParser)
plainText
CHAR
= !LF . { return text(); }
LF
= "\r\n" / [\r\n]