Newer
Older
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:(emoji / text) { return n; })* { return mergeText(nodes); }
= nodes:(&. n:inline { return n; })* { return mergeText(nodes); }
//
// block rules
//
const lines = [head, ...tails];
const children = applyParser(lines.join('\n'), 'fullParser');
return createNode('quote', { }, children);
codeBlock
= BEGIN "```" lang:$(CHAR*) LF code:codeBlockLines LF "```" END
codeBlockLines
= head:codeBlockLine tails:(LF line:codeBlockLine { return line; })*
{ return text(); }
codeBlockLine
= BEGIN (!(BEGIN "```" END) CHAR)* END { return text(); }
mathBlockLines
= mathBlockLine (LF mathBlockLine)*
{ return text(); }
mathBlockLine
= (!("\\]" END) CHAR)+
const children = applyParser(content, 'inlineParser');
return createNode('center', { }, children);
centerLines
= centerLine (LF centerLine)*
{ return text(); }
centerLine
= (!("</center>" END) CHAR)+
//
// inline rules
//
inline
// inline: emoji
emoji
= customEmoji / unicodeEmoji
customEmoji
= ":" name:emojiName ":"
{
return createNode('emoji', { name: name });
}
emojiName
= [a-z0-9_+-]i+ { return text(); }
// 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(); } .)+
// inline: small
small
= "<small>" content:(!"</small>" i:inline { return i; })+ "</small>"
{
// inline: italic
italic
= "<i>" content:(!"</i>" i:inline { return i; })+ "</i>"
{
return createNode('italic', { }, mergeText(content));
}
/ "*" content:$(!"*" [a-z0-9 \t]i)+ "*"
{
const parsedContent = applyParser(content, 'inlineParser');
return createNode('italic', { }, parsedContent);
}
/ "_" content:$(!"_" [a-z0-9 \t]i)+ "_"
{
const parsedContent = applyParser(content, 'inlineParser');
return createNode('italic', { }, parsedContent);
}
// inline: strike
strike
= "~~" content:(!("~" / LF) i:inline { return i; })+ "~~"
{
return createNode('strike', { }, mergeText(content));
}
// inline: inlineCode
inlineCode
= "`" content:$(!"`" c:CHAR { return c; })+ "`"
{
// inline: mathInline
mathInline
= "\\(" content:$(!"\\)" c:CHAR { return c; })+ "\\)"
{
// inline: hashtag
hashtag
= "#" content:hashtagContent
{
return createNode('hashtag', { hashtag: content });
}
hashtagContent
= (hashtagBracketPair / hashtagChar)+ { return text(); }
hashtagBracketPair
= "(" hashtagContent* ")"
/ "[" hashtagContent* "]"
/ "「" hashtagContent* "」"
hashtagChar
= ![ \t.,!?'"#:\/\[\]【】()「」] CHAR
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
// inline: URL
url
= "<" url:urlFormat ">"
{
return createNode('url', { url: url });
}
/ url:urlFormat
{
return createNode('url', { url: url });
}
urlFormat
= "http" "s"? "://" urlContent
{
return text();
}
urlContent
= urlContentPart+
urlContentPart
= urlBracketPair
/ [.,] &urlContentPart // last char is neither "." nor ",".
/ [a-z0-9/:%#@$&?!~=+-]i
urlBracketPair
= "(" urlContentPart* ")"
/ "[" urlContentPart* "]"
CHAR
= !LF . { return text(); }
LF
= "\r\n" / [\r\n]