plantuml_parser/dsl/line/
start.rs

1use crate::StartDiagramToken;
2use crate::dsl::line::LineWithComment;
3use crate::{InlineBlockCommentToken, ParseContainer, ParseResult, wr, wr2};
4use nom::character::complete::space0;
5use nom::combinator::map;
6use nom::{IResult, Parser};
7
8/// A token sequence that is a line containing a start keyword (`"@startXYZ"`) parsed by [`StartDiagramToken`]. (like `"@startuml\n"`.)
9///
10/// # Examples
11///
12/// ```
13/// use plantuml_parser::{StartLine, ParseContainer};
14///
15/// # fn main() -> anyhow::Result<()> {
16/// let input = "@startuml\n";
17/// let (rest, (raws, token)) = StartLine::parse(input.into())?;
18/// let combined_raw: ParseContainer = raws.into();
19/// assert_eq!(rest, "");
20/// assert_eq!(combined_raw, "@startuml\n");
21/// assert_eq!(token.diagram_kind(), "uml");
22/// assert_eq!(token.id(), None);
23///
24/// let input = "  @startXYZ diagram_0\n";
25/// let (rest, (raws, token)) = StartLine::parse(input.into())?;
26/// let combined_raw: ParseContainer = raws.into();
27/// assert_eq!(rest, "");
28/// assert_eq!(combined_raw, "  @startXYZ diagram_0\n");
29/// assert_eq!(token.diagram_kind(), "XYZ");
30/// assert_eq!(token.id(), Some("diagram_0"));
31///
32/// let input = "@startsalt(id=diagram_1)  \n";
33/// let (rest, (raws, token)) = StartLine::parse(input.into())?;
34/// let combined_raw: ParseContainer = raws.into();
35/// assert_eq!(rest, "");
36/// assert_eq!(combined_raw, "@startsalt(id=diagram_1)  \n");
37/// assert_eq!(token.diagram_kind(), "salt");
38/// assert_eq!(token.id(), Some("diagram_1"));
39/// # Ok(())
40/// # }
41/// ```
42#[derive(Clone, Debug)]
43pub struct StartLine {
44    token: StartDiagramToken,
45    ibc: Option<InlineBlockCommentToken>,
46}
47
48impl StartLine {
49    /// Tries to parse [`StartDiagramToken`]. (e.g. `" @startuml\n"`, `" @startuml ID\n"`, `" @startuml(id=ID)\n"`.)
50    pub fn parse(input: ParseContainer) -> ParseResult<Self> {
51        let (rest, (parsed, lwc)) = LineWithComment::parse(inner_parser, input)?;
52
53        let (token, ibc) = lwc.into();
54
55        let ret0 = ParseContainer::from(parsed);
56        let ret1 = Self { token, ibc };
57
58        Ok((rest, (ret0, ret1)))
59    }
60
61    pub fn inline_block_comment(&self) -> Option<&InlineBlockCommentToken> {
62        self.ibc.as_ref()
63    }
64}
65
66impl std::ops::Deref for StartLine {
67    type Target = StartDiagramToken;
68    fn deref(&self) -> &Self::Target {
69        &self.token
70    }
71}
72
73fn inner_parser(
74    input: ParseContainer,
75) -> IResult<ParseContainer, (Vec<ParseContainer>, StartDiagramToken)> {
76    map(
77        (wr!(space0), wr2!(StartDiagramToken::parse), wr!(space0)),
78        |(p0, (p1, sdt), p2)| {
79            let parsed = vec![p0, p1, p2];
80            (parsed, sdt)
81        },
82    )
83    .parse(input)
84}
85
86#[cfg(test)]
87mod tests {
88    use super::*;
89
90    #[test]
91    fn test_parse_start_line() -> anyhow::Result<()> {
92        let testdata = [
93            ("@startuml\n", (None, None)),
94            (" \t@startuml\n", (None, None)),
95            ("@startuml \t\n", (None, None)),
96            (" \t@startuml \t\n", (None, None)),
97            (" \t@startuml id_foo\t\n", (Some("id_foo"), None)),
98            (" \t@startuml(id=id_bar)\t\n", (Some("id_bar"), None)),
99            (
100                " /' comment '/ \t@startuml id_buz\t\n",
101                (Some("id_buz"), Some(" /' comment '/ \t")),
102            ),
103            (
104                "  @startuml id_qux\t /' comment '/   \n",
105                (Some("id_qux"), Some("/' comment '/   ")),
106            ),
107        ];
108
109        for (testdata, expected) in testdata.into_iter() {
110            let (expected_id, expected_ibc) = expected;
111
112            let (rest, (parsed, StartLine { token, ibc })) = StartLine::parse(testdata.into())?;
113
114            assert_eq!(rest, "");
115            assert_eq!(testdata, parsed);
116            assert_eq!(token.diagram_kind(), "uml");
117            assert_eq!(token.id(), expected_id);
118            assert_eq!(ibc.as_ref().map(|x| x.comment()), expected_ibc);
119        }
120
121        Ok(())
122    }
123}