[parsing] Further improve mention parser logic, add more tests

This commit is contained in:
Laura Hausmann 2024-05-17 23:27:05 +02:00
parent fd5a524a8c
commit 3dc14f5bfe
No known key found for this signature in database
GPG key ID: D044E84C5BE01605
2 changed files with 45 additions and 19 deletions

View file

@ -134,24 +134,20 @@ module private MfmParser =
let aggregateTextInline nodes =
nodes |> aggregateText |> List.map (fun x -> x :?> MfmInlineNode)
let domainFirstComponent =
many1Chars (satisfy isAsciiLetter <|> satisfy isDigit <|> anyOf "_-")
let domainComponent =
many1Chars (satisfy isAsciiLetter <|> satisfy isDigit <|> anyOf "._-")
many1Chars (
satisfy isAsciiLetterOrNumber
<|> pchar '_'
<|> attempt (
pchar '-'
.>> (previousCharSatisfies isAsciiLetterOrNumber
<|> nextCharSatisfies isAsciiLetterOrNumber)
)
)
let domainStart = (satisfy isAsciiLetter <|> satisfy isDigit)
let domainFull =
domainStart .>>. domainFirstComponent .>>. pchar '.' .>>. many1 domainComponent
let domainAggregate1 (a: char, b: string) = string a + b
let domainAggregate2 (a: char * string, b: char) = (domainAggregate1 a) + string b
let domainAggregate (x: (char * string) * char, y: string list) =
domainAggregate2 x + (String.concat "" y)
let domain = domainFull |>> domainAggregate
let domain =
domainComponent .>>. (many <| attempt (skipChar '.' >>. domainComponent))
|>> fun (a, b) -> String.concat "." <| Seq.append [ a ] b
let acct (user: string, host: string option) =
match host with
@ -230,7 +226,10 @@ module private MfmParser =
let mentionNode =
previousCharSatisfiesNot isNotWhitespace
>>. skipString "@"
>>. many1Chars (satisfy isAsciiLetter <|> satisfy isDigit <|> anyOf "._-")
>>. many1Chars (
satisfy isAsciiLetterOrNumber
<|> attempt (anyOf "._-" .>> nextCharSatisfies isAsciiLetterOrNumber)
)
.>>. opt (skipChar '@' >>. domain)
.>> (lookAhead
<| choice

View file

@ -66,10 +66,13 @@ public class MfmTests
[TestMethod]
public void TestMention()
{
const string input = "test @test test";
const string input = "test @test test @test@instance.tld";
List<MfmNode> expected =
[
new MfmTextNode("test "), new MfmMentionNode("test", "test", null), new MfmTextNode(" test")
new MfmTextNode("test "),
new MfmMentionNode("test", "test", null),
new MfmTextNode(" test "),
new MfmMentionNode("test@instance.tld", "test", "instance.tld")
];
var res = Mfm.parse(input);
@ -90,6 +93,30 @@ public class MfmTests
MfmSerializer.Serialize(res).Should().BeEquivalentTo(input);
}
[TestMethod]
public void TestMentionTrailingDot()
{
const string input = "@test@asdf.com.";
List<MfmNode> expected = [new MfmMentionNode("test@asdf.com", "test", "asdf.com"), new MfmTextNode(".")];
var res = Mfm.parse(input);
AssertionOptions.FormattingOptions.MaxDepth = 100;
res.ToList().Should().Equal(expected, MfmNodeEqual);
MfmSerializer.Serialize(res).Should().BeEquivalentTo(input);
}
[TestMethod]
public void TestMentionTrailingDotLocal()
{
const string input = "@test.";
List<MfmNode> expected = [new MfmMentionNode("test", "test", null), new MfmTextNode(".")];
var res = Mfm.parse(input);
AssertionOptions.FormattingOptions.MaxDepth = 100;
res.ToList().Should().Equal(expected, MfmNodeEqual);
MfmSerializer.Serialize(res).Should().BeEquivalentTo(input);
}
[TestMethod]
public void TestCodeBlock()
{