1use crate::ast::{Item, Node, Unit};
2use crate::error::{ErrorKind, ParseError};
3
4pub 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}