mirror of
https://activitypub.software/TransFem-org/sfm-js
synced 2024-11-25 23:45:14 +00:00
リンクラベル関係の変更 (#107)
* fix link label matching * 🚀 * add syntax rules of link label * fix #104 * remove unnecessary applyParser() call
This commit is contained in:
parent
fcbda2ecac
commit
49941cd9ba
3 changed files with 114 additions and 28 deletions
|
@ -7,7 +7,7 @@
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "npm run tsc && npm run peg",
|
"build": "npm run tsc && npm run peg",
|
||||||
"build-debug": "npm run tsc && npm run peg-debug",
|
"build-debug": "npm run tsc && npm run peg-debug",
|
||||||
"peg": "peggy --cache -o src/internal/parser.js --allowed-start-rules fullParser,inlineParser,plainParser src/internal/parser.pegjs && npm run peg-copy",
|
"peg": "peggy --cache -o src/internal/parser.js --allowed-start-rules fullParser,plainParser src/internal/parser.pegjs && npm run peg-copy",
|
||||||
"peg-debug": "peggy --cache -o src/internal/parser.js --allowed-start-rules fullParser,inlineParser,plainParser --trace src/internal/parser.pegjs && npm run peg-copy",
|
"peg-debug": "peggy --cache -o src/internal/parser.js --allowed-start-rules fullParser,inlineParser,plainParser --trace src/internal/parser.pegjs && npm run peg-copy",
|
||||||
"peg-copy": "copyfiles -f src/internal/parser.js built/internal/",
|
"peg-copy": "copyfiles -f src/internal/parser.js built/internal/",
|
||||||
"tsc": "tsc",
|
"tsc": "tsc",
|
||||||
|
|
|
@ -41,10 +41,6 @@
|
||||||
return parseFunc(input, parseOpts);
|
return parseFunc(input, parseOpts);
|
||||||
}
|
}
|
||||||
|
|
||||||
// link
|
|
||||||
|
|
||||||
const linkLabel = options.linkLabel || false;
|
|
||||||
|
|
||||||
// emoji
|
// emoji
|
||||||
|
|
||||||
const emojiRegex = require('twemoji-parser/dist/lib/regex').default;
|
const emojiRegex = require('twemoji-parser/dist/lib/regex').default;
|
||||||
|
@ -108,9 +104,6 @@ fullParser
|
||||||
plainParser
|
plainParser
|
||||||
= nodes:(&. @plain)* { return mergeText(nodes); }
|
= nodes:(&. @plain)* { return mergeText(nodes); }
|
||||||
|
|
||||||
inlineParser
|
|
||||||
= nodes:(&. @inline)* { return mergeText(nodes); }
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// syntax list
|
// syntax list
|
||||||
//
|
//
|
||||||
|
@ -154,6 +147,19 @@ inline
|
||||||
/ link
|
/ link
|
||||||
/ inlineText
|
/ inlineText
|
||||||
|
|
||||||
|
L_inline
|
||||||
|
= emojiCode
|
||||||
|
/ unicodeEmoji
|
||||||
|
/ L_big
|
||||||
|
/ L_bold
|
||||||
|
/ L_small
|
||||||
|
/ L_italic
|
||||||
|
/ L_strike
|
||||||
|
/ inlineCode
|
||||||
|
/ mathInline
|
||||||
|
/ L_fn
|
||||||
|
/ L_inlineText
|
||||||
|
|
||||||
plain
|
plain
|
||||||
= emojiCode
|
= emojiCode
|
||||||
/ unicodeEmoji
|
/ unicodeEmoji
|
||||||
|
@ -277,6 +283,15 @@ big
|
||||||
bigContent
|
bigContent
|
||||||
= &{ return enterNest(); } @(@(!"***" @inline)+ &{ return leaveNest(); } / &{ return fallbackNest(); })
|
= &{ return enterNest(); } @(@(!"***" @inline)+ &{ return leaveNest(); } / &{ return fallbackNest(); })
|
||||||
|
|
||||||
|
L_big
|
||||||
|
= "***" content:L_bigContent "***"
|
||||||
|
{
|
||||||
|
return FN('tada', { }, mergeText(content));
|
||||||
|
}
|
||||||
|
|
||||||
|
L_bigContent
|
||||||
|
= &{ return enterNest(); } @(@(!"***" @L_inline)+ &{ return leaveNest(); } / &{ return fallbackNest(); })
|
||||||
|
|
||||||
// inline: bold
|
// inline: bold
|
||||||
|
|
||||||
bold
|
bold
|
||||||
|
@ -290,8 +305,7 @@ bold
|
||||||
}
|
}
|
||||||
/ "__" content:$(!"__" @([a-z0-9]i / _))+ "__"
|
/ "__" content:$(!"__" @([a-z0-9]i / _))+ "__"
|
||||||
{
|
{
|
||||||
const parsedContent = applyParser(content, 'inlineParser');
|
return BOLD([TEXT(content)]);
|
||||||
return BOLD(parsedContent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
boldContent
|
boldContent
|
||||||
|
@ -300,6 +314,26 @@ boldContent
|
||||||
boldTagContent
|
boldTagContent
|
||||||
= &{ return enterNest(); } @(@(!"</b>" @inline)+ &{ return leaveNest(); } / &{ return fallbackNest(); })
|
= &{ return enterNest(); } @(@(!"</b>" @inline)+ &{ return leaveNest(); } / &{ return fallbackNest(); })
|
||||||
|
|
||||||
|
L_bold
|
||||||
|
= "**" content:L_boldContent "**"
|
||||||
|
{
|
||||||
|
return BOLD(mergeText(content));
|
||||||
|
}
|
||||||
|
/ "<b>" content:L_boldTagContent "</b>"
|
||||||
|
{
|
||||||
|
return BOLD(mergeText(content));
|
||||||
|
}
|
||||||
|
/ "__" content:$(!"__" @([a-z0-9]i / _))+ "__"
|
||||||
|
{
|
||||||
|
return BOLD([TEXT(content)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
L_boldContent
|
||||||
|
= &{ return enterNest(); } @(@(!"**" @L_inline)+ &{ return leaveNest(); } / &{ return fallbackNest(); })
|
||||||
|
|
||||||
|
L_boldTagContent
|
||||||
|
= &{ return enterNest(); } @(@(!"</b>" @L_inline)+ &{ return leaveNest(); } / &{ return fallbackNest(); })
|
||||||
|
|
||||||
// inline: small
|
// inline: small
|
||||||
|
|
||||||
small
|
small
|
||||||
|
@ -311,6 +345,15 @@ small
|
||||||
smallContent
|
smallContent
|
||||||
= &{ return enterNest(); } @(@(!"</small>" @inline)+ &{ return leaveNest(); } / &{ return fallbackNest(); })
|
= &{ return enterNest(); } @(@(!"</small>" @inline)+ &{ return leaveNest(); } / &{ return fallbackNest(); })
|
||||||
|
|
||||||
|
L_small
|
||||||
|
= "<small>" content:L_smallContent "</small>"
|
||||||
|
{
|
||||||
|
return SMALL(mergeText(content));
|
||||||
|
}
|
||||||
|
|
||||||
|
L_smallContent
|
||||||
|
= &{ return enterNest(); } @(@(!"</small>" @L_inline)+ &{ return leaveNest(); } / &{ return fallbackNest(); })
|
||||||
|
|
||||||
// inline: italic
|
// inline: italic
|
||||||
|
|
||||||
italic
|
italic
|
||||||
|
@ -320,21 +363,29 @@ italic
|
||||||
}
|
}
|
||||||
/ italicAlt
|
/ italicAlt
|
||||||
|
|
||||||
italicAlt
|
L_italic
|
||||||
= "*" content:$(!"*" ([a-z0-9]i / _))+ "*" &(EOF / LF / _ / ![a-z0-9]i)
|
= "<i>" content:L_italicContent "</i>"
|
||||||
{
|
{
|
||||||
const parsedContent = applyParser(content, 'inlineParser');
|
return ITALIC(mergeText(content));
|
||||||
return ITALIC(parsedContent);
|
|
||||||
}
|
}
|
||||||
/ "_" content:$(!"_" ([a-z0-9]i / _))+ "_" &(EOF / LF / _ / ![a-z0-9]i)
|
/ italicAlt
|
||||||
|
|
||||||
|
italicAlt
|
||||||
|
= "*" content:$([a-z0-9]i / _)+ "*" &(EOF / LF / _ / ![a-z0-9]i)
|
||||||
{
|
{
|
||||||
const parsedContent = applyParser(content, 'inlineParser');
|
return ITALIC([TEXT(content)]);
|
||||||
return ITALIC(parsedContent);
|
}
|
||||||
|
/ "_" content:$([a-z0-9]i / _)+ "_" &(EOF / LF / _ / ![a-z0-9]i)
|
||||||
|
{
|
||||||
|
return ITALIC([TEXT(content)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
italicContent
|
italicContent
|
||||||
= &{ return enterNest(); } @(@(!"</i>" @inline)+ &{ return leaveNest(); } / &{ return fallbackNest(); })
|
= &{ return enterNest(); } @(@(!"</i>" @inline)+ &{ return leaveNest(); } / &{ return fallbackNest(); })
|
||||||
|
|
||||||
|
L_italicContent
|
||||||
|
= &{ return enterNest(); } @(@(!"</i>" @L_inline)+ &{ return leaveNest(); } / &{ return fallbackNest(); })
|
||||||
|
|
||||||
// inline: strike
|
// inline: strike
|
||||||
|
|
||||||
strike
|
strike
|
||||||
|
@ -353,6 +404,22 @@ strikeContent
|
||||||
strikeTagContent
|
strikeTagContent
|
||||||
= &{ return enterNest(); } @(@(!("</s>" / LF) @inline)+ &{ return leaveNest(); } / &{ return fallbackNest(); })
|
= &{ return enterNest(); } @(@(!("</s>" / LF) @inline)+ &{ return leaveNest(); } / &{ return fallbackNest(); })
|
||||||
|
|
||||||
|
L_strike
|
||||||
|
= "~~" content:L_strikeContent "~~"
|
||||||
|
{
|
||||||
|
return STRIKE(mergeText(content));
|
||||||
|
}
|
||||||
|
/ "<s>" content:L_strikeTagContent "</s>"
|
||||||
|
{
|
||||||
|
return STRIKE(mergeText(content));
|
||||||
|
}
|
||||||
|
|
||||||
|
L_strikeContent
|
||||||
|
= &{ return enterNest(); } @(@(!("~" / LF) @L_inline)+ &{ return leaveNest(); } / &{ return fallbackNest(); })
|
||||||
|
|
||||||
|
L_strikeTagContent
|
||||||
|
= &{ return enterNest(); } @(@(!("</s>" / LF) @L_inline)+ &{ return leaveNest(); } / &{ return fallbackNest(); })
|
||||||
|
|
||||||
// inline: inlineCode
|
// inline: inlineCode
|
||||||
|
|
||||||
inlineCode
|
inlineCode
|
||||||
|
@ -372,7 +439,7 @@ mathInline
|
||||||
// inline: mention
|
// inline: mention
|
||||||
|
|
||||||
mention
|
mention
|
||||||
= &{ return !linkLabel; } "@" name:mentionName host:("@" @mentionHost)?
|
= "@" name:mentionName host:("@" @mentionHost)?
|
||||||
{
|
{
|
||||||
return MENTION(name, host, text());
|
return MENTION(name, host, text());
|
||||||
}
|
}
|
||||||
|
@ -414,11 +481,11 @@ hashPairInner
|
||||||
// inline: URL
|
// inline: URL
|
||||||
|
|
||||||
url
|
url
|
||||||
= &{ return !linkLabel; } "<" url:$("http" "s"? "://" (!(">" / _) CHAR)+) ">"
|
= "<" url:$("http" "s"? "://" (!(">" / _) CHAR)+) ">"
|
||||||
{
|
{
|
||||||
return N_URL(url, true);
|
return N_URL(url, true);
|
||||||
}
|
}
|
||||||
/ &{ return !linkLabel; } "http" "s"? "://" (&([.,]+ urlContentPart) . / urlContentPart)+
|
/ "http" "s"? "://" (&([.,]+ urlContentPart) . / urlContentPart)+
|
||||||
{
|
{
|
||||||
// NOTE: last char is neither "." nor ",".
|
// NOTE: last char is neither "." nor ",".
|
||||||
return N_URL(text());
|
return N_URL(text());
|
||||||
|
@ -435,19 +502,13 @@ urlPairInner
|
||||||
// inline: link
|
// inline: link
|
||||||
|
|
||||||
link
|
link
|
||||||
= &{ return !linkLabel; } silent:"?"? "[" label:linkLabel "](" url:url ")"
|
= silent:"?"? "[" label:linkLabel "](" url:url ")"
|
||||||
{
|
{
|
||||||
return LINK((silent != null), url.props.url, mergeText(label));
|
return LINK((silent != null), url.props.url, mergeText(label));
|
||||||
}
|
}
|
||||||
|
|
||||||
linkLabel
|
linkLabel
|
||||||
= (!"](" CHAR)+
|
= (!"]" @L_inline)+
|
||||||
{
|
|
||||||
const label = applyParser(text(), 'inlineParser', {
|
|
||||||
linkLabel: true
|
|
||||||
});
|
|
||||||
return label;
|
|
||||||
}
|
|
||||||
|
|
||||||
// inline: fn
|
// inline: fn
|
||||||
|
|
||||||
|
@ -458,9 +519,19 @@ fn
|
||||||
return FN(name, args, mergeText(content));
|
return FN(name, args, mergeText(content));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
L_fn
|
||||||
|
= "$[" name:$([a-z0-9_]i)+ &{ return ensureFnName(name); } args:fnArgs? _ content:L_fnContent "]"
|
||||||
|
{
|
||||||
|
args = args || {};
|
||||||
|
return FN(name, args, mergeText(content));
|
||||||
|
}
|
||||||
|
|
||||||
fnContent
|
fnContent
|
||||||
= &{ return enterNest(); } @(@(!"]" @inline)+ &{ return leaveNest(); } / &{ return fallbackNest(); })
|
= &{ return enterNest(); } @(@(!"]" @inline)+ &{ return leaveNest(); } / &{ return fallbackNest(); })
|
||||||
|
|
||||||
|
L_fnContent
|
||||||
|
= &{ return enterNest(); } @(@(!"]" @L_inline)+ &{ return leaveNest(); } / &{ return fallbackNest(); })
|
||||||
|
|
||||||
fnArgs
|
fnArgs
|
||||||
= "." head:fnArg tails:("," @fnArg)*
|
= "." head:fnArg tails:("," @fnArg)*
|
||||||
{
|
{
|
||||||
|
@ -487,6 +558,10 @@ inlineText
|
||||||
= !(LF / _) [a-z0-9]i &(hashtag / mention / italicAlt) . { return text(); } // hashtag, mention, italic ignore
|
= !(LF / _) [a-z0-9]i &(hashtag / mention / italicAlt) . { return text(); } // hashtag, mention, italic ignore
|
||||||
/ . /* text node */
|
/ . /* text node */
|
||||||
|
|
||||||
|
L_inlineText
|
||||||
|
= !(LF / _) [a-z0-9]i &italicAlt . { return text(); } // italic ignore
|
||||||
|
/ . /* text node */
|
||||||
|
|
||||||
// inline: text (for plainParser)
|
// inline: text (for plainParser)
|
||||||
|
|
||||||
plainText
|
plainText
|
||||||
|
|
|
@ -1073,6 +1073,17 @@ hoge`;
|
||||||
];
|
];
|
||||||
assert.deepStrictEqual(mfm.parse(input), output);
|
assert.deepStrictEqual(mfm.parse(input), output);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('with brackets before', () => {
|
||||||
|
const input = '[test] foo [bar](https://example.com)';
|
||||||
|
const output = [
|
||||||
|
TEXT('[test] foo '),
|
||||||
|
LINK(false, 'https://example.com', [
|
||||||
|
TEXT('bar')
|
||||||
|
]),
|
||||||
|
];
|
||||||
|
assert.deepStrictEqual(mfm.parse(input), output);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('fn', () => {
|
describe('fn', () => {
|
||||||
|
|
Loading…
Reference in a new issue