Skip to main content

pln_parse/
validate.rs

1use crate::ast::{Item, Node, Unit};
2use crate::error::{ErrorKind, ParseError};
3
4/// Validate that col/row units are used in the correct split direction.
5pub fn validate(item: &Item) -> Result<(), ParseError> {
6    validate_node(&item.node)
7}
8
9fn validate_node(node: &Node) -> Result<(), ParseError> {
10    match node {
11        Node::Panel { .. } => Ok(()),
12        Node::HSplit { children } => {
13            for child in children {
14                check_unit(child, "horizontal (|)", Unit::Row, "row")?;
15                validate_node(&child.node)?;
16            }
17            Ok(())
18        }
19        Node::VSplit { children } => {
20            for child in children {
21                check_unit(child, "vertical (/)", Unit::Col, "col")?;
22                validate_node(&child.node)?;
23            }
24            Ok(())
25        }
26    }
27}
28
29fn check_unit(
30    item: &Item,
31    split_direction: &str,
32    invalid_unit: Unit,
33    unit_name: &str,
34) -> Result<(), ParseError> {
35    if let Some(ref size) = item.size
36        && size.unit == invalid_unit
37    {
38        return Err(ParseError {
39            message: format!(
40                "'{}' unit is not valid in a {} split",
41                unit_name, split_direction
42            ),
43            span: item.span,
44            kind: ErrorKind::InvalidUnitForSplit {
45                unit: unit_name.to_string(),
46                split: split_direction.to_string(),
47            },
48        });
49    }
50    Ok(())
51}
52
53#[cfg(test)]
54mod tests {
55    use crate::parser;
56
57    use super::*;
58
59    fn parse_and_validate(input: &str) -> Result<(), ParseError> {
60        let item = parser::parse(input).unwrap();
61        validate(&item)
62    }
63
64    #[test]
65    fn col_in_hsplit_is_valid() {
66        assert!(parse_and_validate("(sidebar=80col|main)").is_ok());
67    }
68
69    #[test]
70    fn row_in_vsplit_is_valid() {
71        assert!(parse_and_validate("(header=5row/body)").is_ok());
72    }
73
74    #[test]
75    fn col_in_vsplit_is_invalid() {
76        assert!(parse_and_validate("(header=80col/body)").is_err());
77    }
78
79    #[test]
80    fn row_in_hsplit_is_invalid() {
81        assert!(parse_and_validate("(sidebar=5row|main)").is_err());
82    }
83
84    #[test]
85    fn nested_validation() {
86        assert!(parse_and_validate("(editor|(header=80col/body))").is_err());
87    }
88
89    #[test]
90    fn fr_px_percent_always_valid() {
91        assert!(parse_and_validate("(a=2fr|b=200px|c=30%)").is_ok());
92        assert!(parse_and_validate("(a=2fr/b=200px/c=30%)").is_ok());
93    }
94}