plantuml_parser/dsl/line/
include.rs

1use crate::IncludeToken;
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 [`IncludeToken`]. (like `"\t!include foo.puml  \n"` or `"\r!include bar.iuml!buz  \n"`.)
9///
10/// # Examples
11///
12/// ```
13/// use plantuml_parser::{IncludeLine, ParseContainer};
14///
15/// # fn main() -> anyhow::Result<()> {
16/// let input = "!include foo.puml \n";
17/// let (rest, (raws, token)) = IncludeLine::parse(input.into())?;
18/// let combined_raw: ParseContainer = raws.into();
19/// assert_eq!(rest, "");
20/// assert_eq!(combined_raw, "!include foo.puml \n");
21/// assert_eq!(token.filepath(), "foo.puml");
22/// assert_eq!(token.index(), None);
23/// assert_eq!(token.id(), None);
24///
25/// let input = "!include_many bar.iuml!1  \n";
26/// let (rest, (raws, token)) = IncludeLine::parse(input.into())?;
27/// let combined_raw: ParseContainer = raws.into();
28/// assert_eq!(rest, "");
29/// assert_eq!(combined_raw, "!include_many bar.iuml!1  \n");
30/// assert_eq!(token.filepath(), "bar.iuml");
31/// assert_eq!(token.index(), Some(1));
32/// assert_eq!(token.id(), Some("1"));
33///
34/// let input = "  !include_once baz.txt!qux\n";
35/// let (rest, (raws, token)) = IncludeLine::parse(input.into())?;
36/// let combined_raw: ParseContainer = raws.into();
37/// assert_eq!(rest, "");
38/// assert_eq!(combined_raw, "  !include_once baz.txt!qux\n");
39/// assert_eq!(token.filepath(), "baz.txt");
40/// assert_eq!(token.index(), None);
41/// assert_eq!(token.id(), Some("qux"));
42/// # Ok(())
43/// # }
44/// ```
45#[derive(Clone, Debug)]
46pub struct IncludeLine {
47    token: IncludeToken,
48    ibc: Option<InlineBlockCommentToken>,
49}
50
51impl IncludeLine {
52    /// Tries to parse [`IncludeLine`]. (e.g. `" !include foo.puml\n"`, `"!include  bar.iuml!buz \n"`.)
53    pub fn parse(input: ParseContainer) -> ParseResult<Self> {
54        let (rest, (parsed, lwc)) = LineWithComment::parse(inner_parser, input)?;
55
56        let (token, ibc) = lwc.into();
57
58        let ret0 = ParseContainer::from(parsed);
59        let ret1 = Self { token, ibc };
60
61        Ok((rest, (ret0, ret1)))
62    }
63
64    /// Returns the [`IncludeToken`] included.
65    pub fn token(&self) -> &IncludeToken {
66        &self.token
67    }
68
69    pub fn inline_block_comment(&self) -> Option<&InlineBlockCommentToken> {
70        self.ibc.as_ref()
71    }
72}
73
74impl std::ops::Deref for IncludeLine {
75    type Target = IncludeToken;
76    fn deref(&self) -> &Self::Target {
77        &self.token
78    }
79}
80
81fn inner_parser(
82    input: ParseContainer,
83) -> IResult<ParseContainer, (Vec<ParseContainer>, IncludeToken)> {
84    map(
85        (wr!(space0), wr2!(IncludeToken::parse), wr!(space0)),
86        |(p0, (p1, token), p2)| (vec![p0, p1, p2], token),
87    )
88    .parse(input)
89}
90
91#[cfg(test)]
92mod tests {
93    use super::*;
94
95    #[test]
96    fn test_parse_start_line() -> anyhow::Result<()> {
97        let testdata = [
98            (" !include i1.puml\n", ("i1.puml", None, None, None)),
99            (
100                " !include i2.puml!1\n",
101                ("i2.puml", Some(1), Some("1"), None),
102            ),
103            (
104                "\t !include i3.puml!id3\n",
105                ("i3.puml", None, Some("id3"), None),
106            ),
107            (
108                " /' comment '/ !include i4.puml!4  \n",
109                ("i4.puml", Some(4), Some("4"), Some(" /' comment '/ ")),
110            ),
111            (
112                " !include i5.puml!5 /' comment '/ \n",
113                ("i5.puml", Some(5), Some("5"), Some("/' comment '/ ")),
114            ),
115        ];
116
117        for (testdata, expected) in testdata.into_iter() {
118            let (expected_file, expected_index, expected_id, expected_ibc) = expected;
119            let (rest, (parsed, IncludeLine { token, ibc })) = IncludeLine::parse(testdata.into())?;
120
121            assert_eq!(rest, "");
122            assert_eq!(testdata, parsed);
123            assert_eq!(token.filepath(), expected_file);
124            assert_eq!(token.index(), expected_index);
125            assert_eq!(token.id(), expected_id);
126            assert_eq!(ibc.as_ref().map(|x| x.comment()), expected_ibc);
127        }
128
129        Ok(())
130    }
131}