Skip to main content

omena_parser/
layer_path.rs

1//! CST-backed cascade-layer path producer.
2
3use omena_syntax::{LayerPathV0, SyntaxKind, SyntaxNode};
4
5pub fn layer_paths_from_cst(source: &str, layer_rule: &SyntaxNode) -> Vec<LayerPathV0> {
6    if layer_rule.kind() != SyntaxKind::LayerRule
7        || layer_rule
8            .children()
9            .any(|node| node.kind() == SyntaxKind::BogusLayerName)
10    {
11        return Vec::new();
12    }
13
14    let mut paths = Vec::new();
15    let mut authored_segments = Vec::<String>::new();
16    let mut saw_layer_keyword = false;
17    let mut path_valid = true;
18    for token in layer_rule
19        .descendants_with_tokens()
20        .filter_map(|element| element.into_token())
21    {
22        let kind = token.kind();
23        if matches!(
24            kind,
25            SyntaxKind::LeftBrace | SyntaxKind::SassIndent | SyntaxKind::Semicolon
26        ) {
27            break;
28        }
29        if !saw_layer_keyword {
30            if kind == SyntaxKind::AtKeyword {
31                saw_layer_keyword = true;
32            }
33            continue;
34        }
35        match kind {
36            SyntaxKind::Ident | SyntaxKind::CustomPropertyName => {
37                if let Some(text) = source_text_for_token(source, token) {
38                    authored_segments.push(text.to_string());
39                } else {
40                    path_valid = false;
41                }
42            }
43            SyntaxKind::Dot
44            | SyntaxKind::Whitespace
45            | SyntaxKind::LineComment
46            | SyntaxKind::BlockComment => {}
47            SyntaxKind::Comma => {
48                if path_valid
49                    && let Some(path) = LayerPathV0::from_authored_segments(
50                        authored_segments.iter().map(String::as_str),
51                    )
52                {
53                    paths.push(path);
54                }
55                authored_segments.clear();
56                path_valid = true;
57            }
58            _ => path_valid = false,
59        }
60    }
61    if path_valid
62        && let Some(path) =
63            LayerPathV0::from_authored_segments(authored_segments.iter().map(String::as_str))
64    {
65        paths.push(path);
66    }
67    paths
68}
69
70fn source_text_for_token<'a>(
71    source: &'a str,
72    token: &omena_syntax::SyntaxToken,
73) -> Option<&'a str> {
74    let range = token.text_range();
75    source.get(u32::from(range.start()) as usize..u32::from(range.end()) as usize)
76}