リンクラベル関係の変更 (#107)

* fix link label matching

* 🚀
* add syntax rules of link label
* fix #104
* remove unnecessary applyParser() call
This commit is contained in:
marihachi 2022-05-12 20:31:29 +09:00 committed by GitHub
parent fcbda2ecac
commit 49941cd9ba
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 114 additions and 28 deletions

View file

@ -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",

View file

@ -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

View file

@ -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', () => {