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:(emojiCode / unicodeEmoji / text) { return n; })* { return mergeText(nodes); }
= nodes:(&. n:inline { return n; })* { return mergeText(nodes); }
//
// block rules
//
return createNode('quote', null, children);
mathBlockLines
= mathBlockLine (LF mathBlockLine)*
{ return text(); }
mathBlockLine
= BEGIN "<center>" LF? content:(!(LF? "</center>" END) i:inline { return i; })+ LF? "</center>" END
return createNode('center', null, 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 createNode('unicodeEmoji', { emoji: text() });
return createNode('bold', null, mergeText(content));
return createNode('bold', null, parsedContent);
// inline: small
small
= "<small>" content:(!"</small>" i:inline { return i; })+ "</small>"
{
return createNode('small', null, mergeText(content));
// inline: italic
italic
= "<i>" content:(!"</i>" i:inline { return i; })+ "</i>"
{
return createNode('italic', null, mergeText(content));
return createNode('italic', null, parsedContent);
return createNode('italic', null, parsedContent);
// inline: strike
strike
= "~~" content:(!("~" / LF) i:inline { return i; })+ "~~"
{
return createNode('strike', null, 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 createNode('mention', {
});
}
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
// inline: hashtag
hashtag
= "#" content:hashtagContent
{
return createNode('hashtag', { hashtag: content });
}
hashtagContent
= (hashtagBracketPair / hashtagChar)+ { return text(); }
hashtagBracketPair
= "(" hashtagContent* ")"
/ "[" hashtagContent* "]"
/ "「" hashtagContent* "」"
hashtagChar
= ![ \t.,!?'"#:\/\[\]【】()「」] CHAR
// 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 ",".
urlBracketPair
= "(" urlContentPart* ")"
/ "[" urlContentPart* "]"
= silent:"?"? "[" label:linkLabelPart+ "](" url:linkUrl ")"
{
return createNode('link', {
silent: (silent != null),
url: url
}, mergeText(label));
}
linkLabelPart
= url { return text(); /* text node */ }
/ link { return text(); /* text node */ }
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
// inline: fn
fn
= "[" name:$([a-z0-9_]i)+ args:fnArgs? _ content:(!"]" i:inline { return i; })+ "]"
{
args = args || {};
return createNode('fn', {
name: name,
args: 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
= k:$([a-z0-9_]i)+ "=" v:$([a-z0-9_]i)+
{
return { k, v };
}
/ k:$([a-z0-9_]i)+
{
return { k: k, v: true };
}
CHAR
= !LF . { return text(); }
LF
= "\r\n" / [\r\n]