nparse/
indent_document.rs

1use nom::{
2    branch::alt,
3    bytes::complete::{tag, take_till, take_till1},
4    character::complete::{char, line_ending},
5    combinator::{complete, eof, map, opt},
6    multi::{count, many0, many1},
7    sequence::{delimited, pair, separated_pair, terminated},
8    IResult,
9};
10use serde_json::{json, Value};
11
12pub(crate) fn parse_indent_string(i: &str) -> IResult<&str, Value> {
13    terminated(
14        map(opt(parse_value_array(0)), |v| v.unwrap_or_default()),
15        eof,
16    )(i)
17}
18
19fn parse_value_array(indent_level: usize) -> impl Fn(&str) -> IResult<&str, Value> {
20    move |i| {
21        map(
22            many1(complete(terminated(
23                alt((
24                    parse_colon_pair(indent_level),
25                    parse_value_pair_array(indent_level),
26                    map(parse_string(indent_level), |s| (s, Value::Null)),
27                )),
28                many0(line_ending),
29            ))),
30            |mut s| {
31                if s.iter().any(|m| m.1.is_null()) {
32                    json!(s
33                        .drain(..)
34                        .map(|(k, v)| if v.is_null() { json!(k) } else { json!({k: v}) })
35                        .collect::<Vec<_>>())
36                } else {
37                    json!(s
38                        .drain(..)
39                        .map(|(k, v)| (k.into(), v))
40                        .collect::<serde_json::Map<_, _>>())
41                }
42            },
43        )(i)
44    }
45}
46
47fn parse_colon_pair(indent_level: usize) -> impl Fn(&str) -> IResult<&str, (&str, Value)> {
48    move |i| {
49        map(
50            delimited(
51                count(parse_indent, indent_level),
52                separated_pair(
53                    take_till(|ch| ch == '\n' || ch == ':'),
54                    pair(tag(":"), many1(char(' '))),
55                    take_till1(|ch| ch == '\n' || ch == ':'),
56                ),
57                line_ending,
58            ),
59            |(k, v)| (k, json!(v)),
60        )(i)
61    }
62}
63
64fn parse_value_pair_array(indent_level: usize) -> impl Fn(&str) -> IResult<&str, (&str, Value)> {
65    move |i| {
66        pair(
67            parse_string(indent_level),
68            parse_value_array(indent_level + 1),
69        )(i)
70    }
71}
72
73fn parse_string(indent_level: usize) -> impl Fn(&str) -> IResult<&str, &str> {
74    move |i| {
75        delimited(
76            count(parse_indent, indent_level),
77            terminated(take_till(|ch| ch == '\n' || ch == ':'), opt(char(':'))),
78            line_ending,
79        )(i)
80    }
81}
82
83fn parse_indent(i: &str) -> IResult<&str, &str> {
84    alt((tag("    "), tag("\t")))(i)
85}