panache_parser/parser/yaml/
parser.rs1use crate::syntax::{SyntaxKind, SyntaxNode};
2use rowan::GreenNodeBuilder;
3
4use super::model::{
5 ShadowYamlOptions, ShadowYamlOutcome, ShadowYamlReport, YamlInputKind, YamlParseReport,
6};
7
8pub fn parse_shadow(input: &str, options: ShadowYamlOptions) -> ShadowYamlReport {
13 let line_count = input.lines().count().max(1);
14
15 if !options.enabled {
16 return ShadowYamlReport {
17 outcome: ShadowYamlOutcome::SkippedDisabled,
18 shadow_reason: "shadow-disabled",
19 input_kind: options.input_kind,
20 input_len_bytes: input.len(),
21 line_count,
22 normalized_input: None,
23 };
24 }
25
26 let normalized = match options.input_kind {
27 YamlInputKind::Plain => input.to_owned(),
28 YamlInputKind::Hashpipe => normalize_hashpipe_input(input),
29 };
30
31 let parsed = parse_yaml_tree(&normalized).is_some();
32
33 ShadowYamlReport {
34 outcome: if parsed {
35 ShadowYamlOutcome::PrototypeParsed
36 } else {
37 ShadowYamlOutcome::PrototypeRejected
38 },
39 shadow_reason: if parsed {
40 "prototype-basic-mapping-parsed"
41 } else {
42 "prototype-basic-mapping-rejected"
43 },
44 input_kind: options.input_kind,
45 input_len_bytes: input.len(),
46 line_count,
47 normalized_input: Some(normalized),
48 }
49}
50
51fn normalize_hashpipe_input(input: &str) -> String {
52 input
53 .lines()
54 .map(strip_hashpipe_prefix)
55 .collect::<Vec<_>>()
56 .join("\n")
57}
58
59fn strip_hashpipe_prefix(line: &str) -> &str {
60 if let Some(rest) = line.strip_prefix("#|") {
61 return rest.strip_prefix(' ').unwrap_or(rest);
62 }
63 line
64}
65
66pub fn parse_yaml_tree(input: &str) -> Option<SyntaxNode> {
68 parse_yaml_report(input).tree
69}
70
71pub fn parse_yaml_report(input: &str) -> YamlParseReport {
82 if let Some(err) = super::validator::validate_yaml(input) {
83 return YamlParseReport {
84 tree: None,
85 diagnostics: vec![err],
86 };
87 }
88
89 let v2_stream = super::parser_v2::parse_v2(input);
90 let mut builder = GreenNodeBuilder::new();
91 builder.start_node(SyntaxKind::DOCUMENT.into());
92 builder.start_node(SyntaxKind::YAML_METADATA_CONTENT.into());
93 let stream_green = v2_stream.green().into_owned();
94 builder.start_node(SyntaxKind::YAML_STREAM.into());
95 for child in stream_green.children() {
96 match child {
97 rowan::NodeOrToken::Node(n) => {
98 push_green_node(&mut builder, n);
99 }
100 rowan::NodeOrToken::Token(t) => {
101 builder.token(t.kind(), t.text());
102 }
103 }
104 }
105 builder.finish_node(); builder.finish_node(); builder.finish_node(); YamlParseReport {
109 tree: Some(SyntaxNode::new_root(builder.finish())),
110 diagnostics: Vec::new(),
111 }
112}
113
114fn push_green_node(builder: &mut GreenNodeBuilder<'_>, node: &rowan::GreenNodeData) {
115 builder.start_node(node.kind());
116 for child in node.children() {
117 match child {
118 rowan::NodeOrToken::Node(n) => push_green_node(builder, n),
119 rowan::NodeOrToken::Token(t) => builder.token(t.kind(), t.text()),
120 }
121 }
122 builder.finish_node();
123}