1use super::{Lang, SyntaxNode};
2use crate::as_yaml::{AsYaml, YamlKind};
3use crate::lex::SyntaxKind;
4use crate::yaml::ValueNode;
5use rowan::ast::AstNode;
6use rowan::GreenNodeBuilder;
7
8ast_node!(Sequence, SEQUENCE, "A YAML sequence (list)");
9
10impl Sequence {
11 pub(crate) fn items(&self) -> impl Iterator<Item = SyntaxNode> + '_ {
16 self.0.children().filter_map(|child| {
17 if child.kind() == SyntaxKind::SEQUENCE_ENTRY {
18 child.children().find(|n| {
21 matches!(
22 n.kind(),
23 SyntaxKind::SCALAR
24 | SyntaxKind::MAPPING
25 | SyntaxKind::SEQUENCE
26 | SyntaxKind::ALIAS
27 | SyntaxKind::TAGGED_NODE
28 )
29 })
30 } else {
31 None
32 }
33 })
34 }
35
36 pub fn values(&self) -> impl Iterator<Item = crate::as_yaml::YamlNode> + '_ {
40 self.items()
41 .filter_map(crate::as_yaml::YamlNode::from_syntax)
42 }
43
44 pub fn len(&self) -> usize {
46 self.items().count()
47 }
48
49 pub fn is_empty(&self) -> bool {
51 self.items().next().is_none()
52 }
53
54 pub fn get(&self, index: usize) -> Option<crate::as_yaml::YamlNode> {
58 self.items()
59 .nth(index)
60 .and_then(crate::as_yaml::YamlNode::from_syntax)
61 }
62
63 pub fn first(&self) -> Option<crate::as_yaml::YamlNode> {
65 self.get(0)
66 }
67
68 pub fn last(&self) -> Option<crate::as_yaml::YamlNode> {
70 let len = self.len();
71 if len == 0 {
72 None
73 } else {
74 self.get(len - 1)
75 }
76 }
77}
78
79impl Sequence {
80 fn detect_indentation(&self) -> String {
86 if let Some(ind) = self.0.children_with_tokens().find_map(|child| {
88 child
89 .into_token()
90 .filter(|t| t.kind() == SyntaxKind::INDENT)
91 .map(|t| t.text().to_string())
92 }) {
93 return ind;
94 }
95
96 self.0
98 .children()
99 .filter(|c| c.kind() == SyntaxKind::SEQUENCE_ENTRY)
100 .find_map(|entry| {
101 let tokens: Vec<_> = entry.children_with_tokens().collect();
102 tokens.windows(2).find_map(|pair| {
103 let ws = pair[0].as_token()?;
104 let dash = pair[1].as_token()?;
105 if ws.kind() == SyntaxKind::WHITESPACE && dash.kind() == SyntaxKind::DASH {
106 Some(ws.text().to_string())
107 } else {
108 None
109 }
110 })
111 })
112 .unwrap_or_else(|| " ".to_string())
113 }
114
115 pub fn push(&self, value: impl crate::AsYaml) {
119 let indentation = self.detect_indentation();
120
121 let mut indent_builder = GreenNodeBuilder::new();
123 indent_builder.start_node(SyntaxKind::ROOT.into());
124 indent_builder.token(SyntaxKind::INDENT.into(), &indentation);
125 indent_builder.finish_node();
126 let indent_node = SyntaxNode::new_root_mut(indent_builder.finish());
127 let indent_token = indent_node
128 .first_token()
129 .expect("builder always emits an INDENT token");
130
131 let children: Vec<_> = self.0.children_with_tokens().collect();
133
134 let mut last_entry_has_newline = true; let mut last_entry_index = None;
137
138 for (i, child) in children.iter().enumerate().rev() {
139 if let Some(node) = child.as_node() {
140 if node.kind() == SyntaxKind::SEQUENCE_ENTRY {
141 last_entry_has_newline = node
142 .last_token()
143 .map(|t| t.kind() == SyntaxKind::NEWLINE)
144 .unwrap_or(false);
145 last_entry_index = Some(i);
146 break;
147 }
148 }
149 }
150
151 let mut insert_pos = children.len();
155 if let Some(last_idx) = last_entry_index {
156 insert_pos = last_idx + 1;
158
159 while insert_pos < children.len() {
161 if let Some(token) = children[insert_pos].as_token() {
162 if token.kind() == SyntaxKind::INDENT {
163 insert_pos += 1;
164 } else {
165 break;
166 }
167 } else {
168 break;
169 }
170 }
171 }
173
174 let mut builder = GreenNodeBuilder::new();
176 builder.start_node(SyntaxKind::SEQUENCE_ENTRY.into());
177 builder.token(SyntaxKind::DASH.into(), "-");
178 builder.token(SyntaxKind::WHITESPACE.into(), " ");
179
180 let value_ends_with_newline = value.build_content(&mut builder, 0, false);
182
183 if last_entry_has_newline && !value_ends_with_newline {
186 builder.token(SyntaxKind::NEWLINE.into(), "\n");
187 }
188 builder.finish_node(); let new_entry = SyntaxNode::new_root_mut(builder.finish());
190
191 if let Some(last_idx) = last_entry_index {
193 if let Some(node) = children[last_idx].as_node() {
194 if !node
195 .last_token()
196 .map(|t| t.kind() == SyntaxKind::NEWLINE)
197 .unwrap_or(false)
198 {
199 let entry_children_count = node.children_with_tokens().count();
200 let mut nl_builder = GreenNodeBuilder::new();
201 nl_builder.start_node(SyntaxKind::ROOT.into());
202 nl_builder.token(SyntaxKind::NEWLINE.into(), "\n");
203 nl_builder.finish_node();
204 let nl_node = SyntaxNode::new_root_mut(nl_builder.finish());
205 if let Some(token) = nl_node.first_token() {
206 node.splice_children(
207 entry_children_count..entry_children_count,
208 vec![token.into()],
209 );
210 }
211 }
212 }
213 }
214
215 self.0.splice_children(
217 insert_pos..insert_pos,
218 vec![indent_token.into(), new_entry.into()],
219 );
220 }
221
222 pub fn insert(&self, index: usize, value: impl crate::AsYaml) {
229 let indentation = self.detect_indentation();
230
231 let mut newline_builder = GreenNodeBuilder::new();
233 newline_builder.start_node(SyntaxKind::ROOT.into());
234 newline_builder.token(SyntaxKind::NEWLINE.into(), "\n");
235 newline_builder.finish_node();
236 let newline_node = SyntaxNode::new_root_mut(newline_builder.finish());
237 let newline_token = newline_node
238 .first_token()
239 .expect("builder always emits a NEWLINE token");
240
241 let mut builder = GreenNodeBuilder::new();
243 builder.start_node(SyntaxKind::SEQUENCE_ENTRY.into());
244 builder.token(SyntaxKind::WHITESPACE.into(), &indentation);
245 builder.token(SyntaxKind::DASH.into(), "-");
246 builder.token(SyntaxKind::WHITESPACE.into(), " ");
247
248 value.build_content(&mut builder, 0, false);
250
251 builder.finish_node(); let new_entry = SyntaxNode::new_root_mut(builder.finish());
253
254 let children: Vec<_> = self.0.children_with_tokens().collect();
256 let mut item_count = 0;
257 let mut insert_pos = children.len();
258
259 for (i, child) in children.iter().enumerate() {
260 if let Some(node) = child.as_node() {
261 if node.kind() == SyntaxKind::SEQUENCE_ENTRY {
262 if item_count == index {
263 insert_pos = i;
264 break;
265 }
266 item_count += 1;
267 }
268 }
269 }
270
271 self.0.splice_children(
273 insert_pos..insert_pos,
274 vec![newline_token.into(), new_entry.into()],
275 );
276 }
277
278 pub fn set(&self, index: usize, value: impl crate::AsYaml) -> bool {
285 let children: Vec<_> = self.0.children_with_tokens().collect();
286 let mut item_count = 0;
287
288 for (i, child) in children.iter().enumerate() {
289 if let Some(node) = child.as_node() {
290 if node.kind() == SyntaxKind::SEQUENCE_ENTRY {
291 if item_count == index {
292 let entry_children: Vec<_> = node.children_with_tokens().collect();
294 let mut builder = GreenNodeBuilder::new();
295 builder.start_node(SyntaxKind::SEQUENCE_ENTRY.into());
296
297 let mut value_inserted = false;
298 let mut trailing_text: Option<String> = None;
299
300 for entry_child in entry_children {
301 match &entry_child {
302 rowan::NodeOrToken::Node(n)
303 if matches!(
304 n.kind(),
305 SyntaxKind::SCALAR
306 | SyntaxKind::MAPPING
307 | SyntaxKind::SEQUENCE
308 | SyntaxKind::TAGGED_NODE
309 ) =>
310 {
311 let text = n.text().to_string();
315 if let Some(last_newline_pos) = text.rfind('\n') {
316 trailing_text = Some(text[last_newline_pos..].to_string());
317 }
318
319 if !value_inserted {
321 value.build_content(&mut builder, 0, false);
322 value_inserted = true;
323 }
324 }
325 rowan::NodeOrToken::Node(n) => {
326 crate::yaml::copy_node_to_builder(&mut builder, n);
328 }
329 rowan::NodeOrToken::Token(t) => {
330 builder.token(t.kind().into(), t.text());
332 }
333 }
334 }
335
336 if let Some(trailing) = trailing_text {
338 if let Some(indent_part) = trailing.strip_prefix('\n') {
339 builder.token(SyntaxKind::NEWLINE.into(), "\n");
340 if !indent_part.is_empty() {
341 builder.token(SyntaxKind::INDENT.into(), indent_part);
342 }
343 }
344 }
345
346 builder.finish_node();
347 let new_entry = SyntaxNode::new_root_mut(builder.finish());
348
349 self.0.splice_children(i..i + 1, vec![new_entry.into()]);
351 return true;
352 }
353 item_count += 1;
354 }
355 }
356 }
357 false
358 }
359
360 pub fn remove(&self, index: usize) -> Option<crate::as_yaml::YamlNode> {
366 let removed_value = self.get(index);
368
369 let children: Vec<_> = self.0.children_with_tokens().collect();
371
372 let mut item_count = 0;
374 for (i, child) in children.iter().enumerate() {
375 if let Some(node) = child.as_node() {
376 if node.kind() == SyntaxKind::SEQUENCE_ENTRY {
377 if item_count == index {
378 let is_last = !children.iter().skip(i + 1).any(|c| {
380 c.as_node()
381 .is_some_and(|n| n.kind() == SyntaxKind::SEQUENCE_ENTRY)
382 });
383
384 self.0.splice_children(i..(i + 1), vec![]);
386
387 if !self.is_flow_style() && is_last && i > 0 {
388 if let Some(prev_entry_node) =
391 children[..i].iter().rev().find_map(|c| {
392 c.as_node()
393 .filter(|n| n.kind() == SyntaxKind::SEQUENCE_ENTRY)
394 })
395 {
396 let entry_children: Vec<_> =
398 prev_entry_node.children_with_tokens().collect();
399 let mut remove_count = 0;
400
401 for child in entry_children.iter().rev() {
403 if let Some(token) = child.as_token() {
404 if matches!(
405 token.kind(),
406 SyntaxKind::NEWLINE
407 | SyntaxKind::INDENT
408 | SyntaxKind::WHITESPACE
409 ) {
410 remove_count += 1;
411 } else {
412 break;
413 }
414 } else {
415 break;
416 }
417 }
418
419 if remove_count > 0 {
420 let total = entry_children.len();
421 prev_entry_node
422 .splice_children((total - remove_count)..total, vec![]);
423 }
424 }
425 }
426 return removed_value;
427 }
428 item_count += 1;
429 }
430 }
431 }
432 None
433 }
434
435 pub fn is_flow_style(&self) -> bool {
437 self.0.children_with_tokens().any(|child| {
438 child
439 .as_token()
440 .is_some_and(|t| t.kind() == SyntaxKind::LEFT_BRACKET)
441 })
442 }
443
444 #[allow(dead_code)] pub(crate) fn get_node(&self, index: usize) -> Option<SyntaxNode> {
450 self.items().nth(index)
451 }
452
453 pub fn pop(&self) -> Option<crate::as_yaml::YamlNode> {
459 let len = self.len();
460 if len == 0 {
461 return None;
462 }
463 let removed = self.remove(len - 1);
464
465 debug_assert_eq!(
466 self.len(),
467 len - 1,
468 "pop() invariant: remove() did not reduce length"
469 );
470
471 removed
472 }
473
474 pub fn clear(&self) {
478 let initial_len = self.len();
481 for _ in 0..initial_len {
482 let current_len = self.len();
483 if current_len == 0 {
484 break;
485 }
486 let removed = self.remove(0);
488 debug_assert!(
489 removed.is_some(),
490 "clear() invariant: remove(0) returned None"
491 );
492 debug_assert_eq!(
493 self.len(),
494 current_len - 1,
495 "clear() invariant: remove(0) did not reduce length"
496 );
497 }
498 }
499
500 pub fn byte_range(&self) -> crate::TextPosition {
504 self.0.text_range().into()
505 }
506
507 pub fn start_position(&self, source_text: &str) -> crate::LineColumn {
516 let range = self.byte_range();
517 crate::byte_offset_to_line_column(source_text, range.start as usize)
518 }
519
520 pub fn end_position(&self, source_text: &str) -> crate::LineColumn {
529 let range = self.byte_range();
530 crate::byte_offset_to_line_column(source_text, range.end as usize)
531 }
532}
533
534impl<'a> IntoIterator for &'a Sequence {
537 type Item = crate::as_yaml::YamlNode;
538 type IntoIter = Box<dyn Iterator<Item = crate::as_yaml::YamlNode> + 'a>;
539
540 fn into_iter(self) -> Self::IntoIter {
541 Box::new(self.values())
542 }
543}
544
545impl AsYaml for Sequence {
546 fn as_node(&self) -> Option<&SyntaxNode> {
547 Some(&self.0)
548 }
549
550 fn kind(&self) -> YamlKind {
551 YamlKind::Sequence
552 }
553
554 fn build_content(
555 &self,
556 builder: &mut rowan::GreenNodeBuilder,
557 indent: usize,
558 _flow_context: bool,
559 ) -> bool {
560 builder.start_node(SyntaxKind::SEQUENCE.into());
561 crate::as_yaml::copy_node_content_with_indent(builder, &self.0, indent);
562 builder.finish_node();
563 self.0
564 .last_token()
565 .map(|t| t.kind() == SyntaxKind::NEWLINE)
566 .unwrap_or(false)
567 }
568
569 fn is_inline(&self) -> bool {
570 ValueNode::is_inline(self)
571 }
572}
573#[cfg(test)]
574mod tests {
575 use crate::yaml::YamlFile;
576 use std::str::FromStr;
577
578 #[test]
579 fn test_sequence_items_tagged_node() {
580 let yaml = "- !custom foo\n- !custom bar\n- plain\n";
583 let parsed = YamlFile::from_str(yaml).unwrap();
584
585 let doc = parsed.document().unwrap();
586 let seq = doc.as_sequence().unwrap();
587 assert_eq!(
588 seq.items().count(),
589 3,
590 "Tagged scalars should be included in items()"
591 );
592 assert_eq!(
594 seq.values().count(),
595 3,
596 "Tagged scalars should be included in values()"
597 );
598 }
599
600 #[test]
601 fn test_sequence_set_tagged_node() {
602 let yaml = "- !custom foo\n- bar\n";
606 let parsed = YamlFile::from_str(yaml).unwrap();
607 let doc = parsed.document().unwrap();
608 let seq = doc.as_sequence().unwrap();
609
610 seq.set(0, "replaced");
611
612 let values: Vec<_> = seq.values().collect();
613 assert_eq!(values.len(), 2);
614 assert_eq!(
615 values[0].as_scalar().map(|s| s.as_string()),
616 Some("replaced".to_string())
617 );
618 assert_eq!(
619 values[1].as_scalar().map(|s| s.as_string()),
620 Some("bar".to_string())
621 );
622 }
623
624 #[test]
625 fn test_sequence_operations() {
626 let yaml = "- item1\n- item2";
627 let parsed = YamlFile::from_str(yaml).unwrap();
628
629 let doc = parsed.document().expect("expected a document");
630 let seq = doc.as_sequence().expect("expected a sequence");
631
632 seq.push("item3");
634 let values: Vec<_> = seq.values().collect();
635 assert_eq!(values.len(), 3);
636 assert_eq!(
637 values[2].as_scalar().map(|s| s.as_string()),
638 Some("item3".to_string())
639 );
640
641 seq.insert(0, "item0");
643 let values: Vec<_> = seq.values().collect();
644 assert_eq!(values.len(), 4);
645 assert_eq!(
646 values[0].as_scalar().map(|s| s.as_string()),
647 Some("item0".to_string())
648 );
649 }
650
651 #[test]
654 fn test_sequence_into_iterator() {
655 use crate::Document;
656 let text = "items:\n - apple\n - banana\n - cherry";
657 let doc = Document::from_str(text).unwrap();
658 let mapping = doc.as_mapping().unwrap();
659 let sequence = mapping.get_sequence("items").unwrap();
660
661 let mut items = Vec::new();
663 for value in &sequence {
664 if let Some(scalar) = value.as_scalar() {
665 items.push(scalar.to_string());
666 }
667 }
668
669 assert_eq!(items.len(), 3);
670 assert_eq!(items[0], "apple");
671 assert_eq!(items[1], "banana");
672 assert_eq!(items[2], "cherry");
673 }
674
675 #[test]
676 fn test_sequence_into_iterator_count() {
677 use crate::Document;
678 let text = "[1, 2, 3, 4, 5]";
679 let doc = Document::from_str(text).unwrap();
680 let sequence = doc.as_sequence().unwrap();
681
682 let count = (&sequence).into_iter().count();
683 assert_eq!(count, 5);
684 }
685
686 #[test]
687 fn test_sequence_iterator_map() {
688 use crate::Document;
689 let text = "numbers: [1, 2, 3]";
690 let doc = Document::from_str(text).unwrap();
691 let mapping = doc.as_mapping().unwrap();
692 let sequence = mapping.get_sequence("numbers").unwrap();
693
694 let strings: Vec<_> = (&sequence)
696 .into_iter()
697 .filter_map(|v| v.as_scalar().map(|s| s.to_string()))
698 .collect();
699
700 assert_eq!(strings, vec!["1", "2", "3"]);
701 }
702
703 #[test]
704 fn test_empty_sequence_iterator() {
705 use crate::Document;
706 let text = "items: []";
707 let doc = Document::from_str(text).unwrap();
708 let mapping = doc.as_mapping().unwrap();
709 let sequence = mapping.get_sequence("items").unwrap();
710
711 let count = (&sequence).into_iter().count();
712 assert_eq!(count, 0);
713 }
714
715 #[test]
718 fn test_sequence_push_single() {
719 use crate::Document;
720 let original = r#"team:
721 - Alice
722 - Bob"#;
723
724 let doc = Document::from_str(original).unwrap();
725 let mapping = doc.as_mapping().unwrap();
726 let team = mapping.get_sequence("team").unwrap();
727 team.push("Charlie");
728
729 let expected = r#"team:
730 - Alice
731 - Bob
732 - Charlie"#;
733 assert_eq!(doc.to_string(), expected);
734 }
735
736 #[test]
737 fn test_sequence_push_multiple() {
738 use crate::Document;
739 let original = r#"team:
740 - Alice
741 - Bob"#;
742
743 let doc = Document::from_str(original).unwrap();
744 let mapping = doc.as_mapping().unwrap();
745 let team = mapping.get_sequence("team").unwrap();
746 team.push("Charlie");
747 team.push("Diana");
748
749 let expected = r#"team:
750 - Alice
751 - Bob
752 - Charlie
753 - Diana"#;
754 assert_eq!(doc.to_string(), expected);
755 }
756
757 #[test]
758 fn test_sequence_set_item() {
759 use crate::Document;
760 let original = r#"team:
761 - Alice
762 - Bob
763 - Charlie"#;
764
765 let doc = Document::from_str(original).unwrap();
766 let mapping = doc.as_mapping().unwrap();
767 let team = mapping.get_sequence("team").unwrap();
768 team.set(1, "Robert");
769
770 let expected = r#"team:
771 - Alice
772 - Robert
773 - Charlie"#;
774 assert_eq!(doc.to_string(), expected);
775 }
776
777 #[test]
778 fn test_multiple_sequences() {
779 use crate::Document;
780 let original = r#"team:
781 - Alice
782 - Bob
783
784scores:
785 - 95
786 - 87"#;
787
788 let doc = Document::from_str(original).unwrap();
789 let mapping = doc.as_mapping().unwrap();
790 let team = mapping.get_sequence("team").unwrap();
791 team.push("Charlie");
792 let scores = mapping.get_sequence("scores").unwrap();
793 scores.push(92);
794 scores.set(0, 100);
795
796 let expected = r#"team:
797 - Alice
798 - Bob
799 - Charlie
800
801scores:
802 - 100
803 - 87
804 - 92"#;
805 assert_eq!(doc.to_string(), expected);
806 }
807
808 #[test]
809 fn test_nested_structure_with_sequences() {
810 use crate::Document;
811 let original = r#"config:
812 enabled: true
813 retries: 3
814 servers:
815 - host1
816 - host2"#;
817
818 let doc = Document::from_str(original).unwrap();
819 let mapping = doc.as_mapping().unwrap();
820 let config = mapping.get_mapping("config").unwrap();
821 config.set("enabled", false);
822 config.set("retries", 5);
823
824 let servers = config.get_sequence("servers").unwrap();
825 servers.push("host3");
826 servers.set(0, "primary-host");
827
828 let expected = r#"config:
829 enabled: false
830 retries: 5
831 servers:
832 - primary-host
833 - host2
834 - host3"#;
835 assert_eq!(doc.to_string(), expected);
836 }
837
838 #[test]
839 fn test_sequence_len_and_is_empty() {
840 use crate::Document;
841 let doc = Document::from_str("items:\n - a\n - b\n - c").unwrap();
842 let mapping = doc.as_mapping().unwrap();
843 let seq = mapping.get_sequence("items").unwrap();
844
845 assert_eq!(seq.len(), 3);
846 assert!(!seq.is_empty());
847
848 let empty_doc = Document::from_str("items: []").unwrap();
849 let empty_mapping = empty_doc.as_mapping().unwrap();
850 let empty_seq = empty_mapping.get_sequence("items").unwrap();
851
852 assert_eq!(empty_seq.len(), 0);
853 assert!(empty_seq.is_empty());
854 }
855
856 #[test]
857 fn test_sequence_get() {
858 use crate::Document;
859 let doc = Document::from_str("items:\n - first\n - second\n - third").unwrap();
860 let mapping = doc.as_mapping().unwrap();
861 let seq = mapping.get_sequence("items").unwrap();
862
863 assert_eq!(seq.get(0).unwrap().to_string(), "first");
864 assert_eq!(seq.get(1).unwrap().to_string(), "second");
865 assert_eq!(seq.get(2).unwrap().to_string(), "third");
866 assert!(seq.get(3).is_none());
867 }
868
869 #[test]
870 fn test_sequence_first_and_last() {
871 use crate::Document;
872 let doc = Document::from_str("items:\n - first\n - middle\n - last").unwrap();
873 let mapping = doc.as_mapping().unwrap();
874 let seq = mapping.get_sequence("items").unwrap();
875
876 assert_eq!(seq.first().unwrap().to_string(), "first");
877 assert_eq!(seq.last().unwrap().to_string(), "last");
878
879 let empty_doc = Document::from_str("items: []").unwrap();
880 let empty_mapping = empty_doc.as_mapping().unwrap();
881 let empty_seq = empty_mapping.get_sequence("items").unwrap();
882
883 assert!(empty_seq.first().is_none());
884 assert!(empty_seq.last().is_none());
885 }
886
887 #[test]
888 fn test_sequence_values_iterator() {
889 use crate::Document;
890 let doc = Document::from_str("items:\n - a\n - b\n - c").unwrap();
891 let mapping = doc.as_mapping().unwrap();
892 let seq = mapping.get_sequence("items").unwrap();
893
894 let values: Vec<String> = seq.values().map(|v| v.to_string()).collect();
895 assert_eq!(values, vec!["a", "b", "c"]);
896 }
897
898 #[test]
899 fn test_sequence_pop() {
900 use crate::Document;
901 let doc = Document::from_str("items:\n - a\n - b\n - c").unwrap();
902 let mapping = doc.as_mapping().unwrap();
903 let seq = mapping.get_sequence("items").unwrap();
904
905 assert_eq!(seq.len(), 3);
906 let popped = seq.pop().unwrap();
907 assert_eq!(popped.to_string(), "c");
908 assert_eq!(seq.len(), 2);
909
910 let popped = seq.pop().unwrap();
911 assert_eq!(popped.to_string(), "b");
912 assert_eq!(seq.len(), 1);
913
914 let expected = "items:\n - a";
915 assert_eq!(doc.to_string().trim_end(), expected);
916
917 let popped = seq.pop().unwrap();
918 assert_eq!(popped.to_string(), "a");
919 assert_eq!(seq.len(), 0);
920 assert!(seq.pop().is_none());
921 }
922
923 #[test]
924 fn test_sequence_clear() {
925 use crate::Document;
926 let doc = Document::from_str("items:\n - a\n - b\n - c").unwrap();
927 let mapping = doc.as_mapping().unwrap();
928 let seq = mapping.get_sequence("items").unwrap();
929
930 assert_eq!(seq.len(), 3);
931 seq.clear();
932 assert_eq!(seq.len(), 0);
933 assert!(seq.is_empty());
934 }
935
936 #[test]
937 fn test_sequence_get_with_nested_values() {
938 use crate::Document;
939 let doc = Document::from_str(
940 r#"items:
941 - simple
942 - {key: value}
943 - [nested, list]"#,
944 )
945 .unwrap();
946 let mapping = doc.as_mapping().unwrap();
947 let seq = mapping.get_sequence("items").unwrap();
948
949 assert_eq!(seq.len(), 3);
950 assert!(seq.get(0).unwrap().is_scalar());
951 assert!(seq.get(1).unwrap().is_mapping());
952 assert!(seq.get(2).unwrap().is_sequence());
953 }
954
955 #[test]
956 fn test_flow_sequence_len_and_is_empty() {
957 use crate::Document;
958 let doc = Document::from_str("items: [a, b, c]").unwrap();
959 let mapping = doc.as_mapping().unwrap();
960 let seq = mapping.get_sequence("items").unwrap();
961
962 assert_eq!(seq.len(), 3);
963 assert!(!seq.is_empty());
964
965 let empty_doc = Document::from_str("items: []").unwrap();
966 let empty_mapping = empty_doc.as_mapping().unwrap();
967 let empty_seq = empty_mapping.get_sequence("items").unwrap();
968
969 assert_eq!(empty_seq.len(), 0);
970 assert!(empty_seq.is_empty());
971 }
972
973 #[test]
974 fn test_flow_sequence_get() {
975 use crate::Document;
976 let doc = Document::from_str("items: [first, second, third]").unwrap();
977 let mapping = doc.as_mapping().unwrap();
978 let seq = mapping.get_sequence("items").unwrap();
979
980 assert_eq!(seq.get(0).unwrap().to_string(), "first");
981 assert_eq!(seq.get(1).unwrap().to_string(), "second");
982 assert_eq!(seq.get(2).unwrap().to_string(), "third");
983 assert!(seq.get(3).is_none());
984 }
985
986 #[test]
987 fn test_flow_sequence_first_and_last() {
988 use crate::Document;
989 let doc = Document::from_str("items: [first, middle, last]").unwrap();
990 let mapping = doc.as_mapping().unwrap();
991 let seq = mapping.get_sequence("items").unwrap();
992
993 assert_eq!(seq.first().unwrap().to_string(), "first");
994 assert_eq!(seq.last().unwrap().to_string(), "last");
995 }
996
997 #[test]
998 fn test_flow_sequence_values_iterator() {
999 use crate::Document;
1000 let doc = Document::from_str("items: [a, b, c]").unwrap();
1001 let mapping = doc.as_mapping().unwrap();
1002 let seq = mapping.get_sequence("items").unwrap();
1003
1004 let values: Vec<String> = seq.values().map(|v| v.to_string()).collect();
1005 assert_eq!(values, vec!["a", "b", "c"]);
1006 }
1007
1008 #[test]
1009 fn test_flow_sequence_remove_middle() {
1010 use crate::Document;
1011 let doc = Document::from_str("items: [a, b, c]").unwrap();
1012 let mapping = doc.as_mapping().unwrap();
1013 let seq = mapping.get_sequence("items").unwrap();
1014
1015 assert_eq!(seq.len(), 3);
1016 let removed = seq.remove(1);
1017 assert_eq!(removed.map(|v| v.to_string()), Some("b".to_string()));
1018 assert_eq!(seq.len(), 2);
1019
1020 let values: Vec<String> = seq.values().map(|v| v.to_string()).collect();
1021 assert_eq!(values, vec!["a", "c"]);
1022 }
1023
1024 #[test]
1025 fn test_flow_sequence_remove_first() {
1026 use crate::Document;
1027 let doc = Document::from_str("items: [a, b, c]").unwrap();
1028 let mapping = doc.as_mapping().unwrap();
1029 let seq = mapping.get_sequence("items").unwrap();
1030
1031 assert_eq!(seq.len(), 3);
1032 let removed = seq.remove(0);
1033 assert_eq!(removed.map(|v| v.to_string()), Some("a".to_string()));
1034 assert_eq!(seq.len(), 2);
1035
1036 let values: Vec<String> = seq.values().map(|v| v.to_string()).collect();
1037 assert_eq!(values, vec!["b", "c"]);
1038 }
1039
1040 #[test]
1041 fn test_flow_sequence_remove_last() {
1042 use crate::Document;
1043 let doc = Document::from_str("items: [a, b, c]").unwrap();
1044 let mapping = doc.as_mapping().unwrap();
1045 let seq = mapping.get_sequence("items").unwrap();
1046
1047 assert_eq!(seq.len(), 3);
1048 let removed = seq.remove(2);
1049 assert_eq!(removed.map(|v| v.to_string()), Some("c".to_string()));
1050 assert_eq!(seq.len(), 2);
1051
1052 let values: Vec<String> = seq.values().map(|v| v.to_string()).collect();
1053 assert_eq!(values, vec!["a", "b"]);
1054 }
1055
1056 #[test]
1057 fn test_flow_sequence_pop() {
1058 use crate::Document;
1059 let doc = Document::from_str("items: [a, b, c]").unwrap();
1060 let mapping = doc.as_mapping().unwrap();
1061 let seq = mapping.get_sequence("items").unwrap();
1062
1063 assert_eq!(seq.len(), 3);
1064 let popped = seq.pop().unwrap();
1065 assert_eq!(popped.to_string(), "c");
1066 assert_eq!(seq.len(), 2);
1067
1068 let popped = seq.pop().unwrap();
1069 assert_eq!(popped.to_string(), "b");
1070 assert_eq!(seq.len(), 1);
1071
1072 let popped = seq.pop().unwrap();
1073 assert_eq!(popped.to_string(), "a");
1074 assert_eq!(seq.len(), 0);
1075 assert!(seq.pop().is_none());
1076 }
1077
1078 #[test]
1079 fn test_flow_sequence_clear() {
1080 use crate::Document;
1081 let doc = Document::from_str("items: [a, b, c]").unwrap();
1082 let mapping = doc.as_mapping().unwrap();
1083 let seq = mapping.get_sequence("items").unwrap();
1084
1085 assert_eq!(seq.len(), 3);
1086 seq.clear();
1087 assert_eq!(seq.len(), 0);
1088 assert!(seq.is_empty());
1089 }
1090
1091 #[test]
1092 fn test_flow_sequence_with_whitespace() {
1093 use crate::Document;
1094 let doc = Document::from_str("items: [ a , b , c ]").unwrap();
1095 let mapping = doc.as_mapping().unwrap();
1096 let seq = mapping.get_sequence("items").unwrap();
1097
1098 assert_eq!(seq.len(), 3);
1099 let values: Vec<String> = seq.values().map(|v| v.to_string()).collect();
1100 assert_eq!(values, vec!["a", "b", "c"]);
1101 }
1102
1103 #[test]
1104 fn test_block_sequence_remove_middle() {
1105 use crate::Document;
1106 let doc = Document::from_str("items:\n - a\n - b\n - c").unwrap();
1107 let mapping = doc.as_mapping().unwrap();
1108 let seq = mapping.get_sequence("items").unwrap();
1109
1110 assert_eq!(seq.len(), 3);
1111 let removed = seq.remove(1);
1112 assert_eq!(removed.map(|v| v.to_string()), Some("b".to_string()));
1113 assert_eq!(seq.len(), 2);
1114
1115 let values: Vec<String> = seq.values().map(|v| v.to_string()).collect();
1116 assert_eq!(values, vec!["a", "c"]);
1117 }
1118
1119 #[test]
1120 fn test_block_sequence_remove_first() {
1121 use crate::Document;
1122 let doc = Document::from_str("items:\n - a\n - b\n - c").unwrap();
1123 let mapping = doc.as_mapping().unwrap();
1124 let seq = mapping.get_sequence("items").unwrap();
1125
1126 assert_eq!(seq.len(), 3);
1127 let removed = seq.remove(0);
1128 assert_eq!(removed.map(|v| v.to_string()), Some("a".to_string()));
1129 assert_eq!(seq.len(), 2);
1130
1131 let values: Vec<String> = seq.values().map(|v| v.to_string()).collect();
1132 assert_eq!(values, vec!["b", "c"]);
1133 }
1134
1135 #[test]
1136 fn test_block_sequence_remove_last() {
1137 use crate::Document;
1138 let doc = Document::from_str("items:\n - a\n - b\n - c").unwrap();
1139 let mapping = doc.as_mapping().unwrap();
1140 let seq = mapping.get_sequence("items").unwrap();
1141
1142 assert_eq!(seq.len(), 3);
1143 let removed = seq.remove(2);
1144 assert_eq!(removed.map(|v| v.to_string()), Some("c".to_string()));
1145 assert_eq!(seq.len(), 2);
1146
1147 let values: Vec<String> = seq.values().map(|v| v.to_string()).collect();
1148 assert_eq!(values, vec!["a", "b"]);
1149 }
1150
1151 #[test]
1152 fn test_single_item_block_sequence_remove() {
1153 use crate::Document;
1154 let doc = Document::from_str("items:\n - only").unwrap();
1155 let mapping = doc.as_mapping().unwrap();
1156 let seq = mapping.get_sequence("items").unwrap();
1157
1158 assert_eq!(seq.len(), 1);
1159 let removed = seq.remove(0);
1160 assert_eq!(removed.map(|v| v.to_string()), Some("only".to_string()));
1161 assert_eq!(seq.len(), 0);
1162 }
1163
1164 #[test]
1165 fn test_single_item_flow_sequence_remove() {
1166 use crate::Document;
1167 let doc = Document::from_str("items: [only]").unwrap();
1168 let mapping = doc.as_mapping().unwrap();
1169 let seq = mapping.get_sequence("items").unwrap();
1170
1171 assert_eq!(seq.len(), 1);
1172 let removed = seq.remove(0);
1173 assert_eq!(removed.map(|v| v.to_string()), Some("only".to_string()));
1174 assert_eq!(seq.len(), 0);
1175 }
1176
1177 #[test]
1178 fn test_flow_sequence_push() {
1179 use crate::Document;
1180 let doc = Document::from_str("items: [a, b]").unwrap();
1181 let mapping = doc.as_mapping().unwrap();
1182 let seq = mapping.get_sequence("items").unwrap();
1183
1184 assert_eq!(seq.len(), 2);
1185 seq.push("c");
1186 assert_eq!(seq.len(), 3);
1187
1188 let values: Vec<String> = seq.values().map(|v| v.to_string()).collect();
1189 assert_eq!(values, vec!["a", "b", "c"]);
1190 }
1191
1192 #[test]
1193 fn test_flow_sequence_push_multiple() {
1194 use crate::Document;
1195 let doc = Document::from_str("items: [a]").unwrap();
1196 let mapping = doc.as_mapping().unwrap();
1197 let seq = mapping.get_sequence("items").unwrap();
1198
1199 seq.push("b");
1200 seq.push("c");
1201 seq.push("d");
1202
1203 let values: Vec<String> = seq.values().map(|v| v.to_string()).collect();
1204 assert_eq!(values, vec!["a", "b", "c", "d"]);
1205 }
1206
1207 #[test]
1208 fn test_flow_sequence_set_item() {
1209 use crate::Document;
1210 let doc = Document::from_str("items: [a, b, c]").unwrap();
1211 let mapping = doc.as_mapping().unwrap();
1212 let seq = mapping.get_sequence("items").unwrap();
1213
1214 seq.set(1, "modified");
1215
1216 let values: Vec<String> = seq.values().map(|v| v.to_string()).collect();
1217 assert_eq!(values, vec!["a", "modified", "c"]);
1218 }
1219
1220 #[test]
1221 fn test_flow_sequence_insert_beginning() {
1222 use crate::Document;
1223 let doc = Document::from_str("items: [b, c]").unwrap();
1224 let mapping = doc.as_mapping().unwrap();
1225 let seq = mapping.get_sequence("items").unwrap();
1226
1227 seq.insert(0, "a");
1228
1229 let values: Vec<String> = seq.values().map(|v| v.to_string()).collect();
1230 assert_eq!(values, vec!["a", "b", "c"]);
1231 }
1232
1233 #[test]
1234 fn test_flow_sequence_insert_middle() {
1235 use crate::Document;
1236 let doc = Document::from_str("items: [a, c]").unwrap();
1237 let mapping = doc.as_mapping().unwrap();
1238 let seq = mapping.get_sequence("items").unwrap();
1239
1240 seq.insert(1, "b");
1241
1242 let values: Vec<String> = seq.values().map(|v| v.to_string()).collect();
1243 assert_eq!(values, vec!["a", "b", "c"]);
1244 }
1245
1246 #[test]
1247 fn test_flow_sequence_insert_end() {
1248 use crate::Document;
1249 let doc = Document::from_str("items: [a, b]").unwrap();
1250 let mapping = doc.as_mapping().unwrap();
1251 let seq = mapping.get_sequence("items").unwrap();
1252
1253 seq.insert(2, "c");
1254
1255 let values: Vec<String> = seq.values().map(|v| v.to_string()).collect();
1256 assert_eq!(values, vec!["a", "b", "c"]);
1257 }
1258
1259 #[test]
1260 fn test_block_sequence_push() {
1261 use crate::Document;
1262 let doc = Document::from_str("items:\n - a\n - b").unwrap();
1263 let mapping = doc.as_mapping().unwrap();
1264 let seq = mapping.get_sequence("items").unwrap();
1265
1266 assert_eq!(seq.len(), 2);
1267 seq.push("c");
1268 assert_eq!(seq.len(), 3);
1269
1270 let values: Vec<String> = seq.values().map(|v| v.to_string()).collect();
1271 assert_eq!(values, vec!["a", "b", "c"]);
1272 }
1273
1274 #[test]
1275 fn test_block_sequence_set_item() {
1276 use crate::Document;
1277 let doc = Document::from_str("items:\n - a\n - b\n - c").unwrap();
1278 let mapping = doc.as_mapping().unwrap();
1279 let seq = mapping.get_sequence("items").unwrap();
1280
1281 seq.set(1, "modified");
1282
1283 let values: Vec<String> = seq.values().map(|v| v.to_string()).collect();
1284 assert_eq!(values, vec!["a", "modified", "c"]);
1285 }
1286
1287 #[test]
1288 fn test_block_sequence_insert_beginning() {
1289 use crate::Document;
1290 let doc = Document::from_str("items:\n - b\n - c").unwrap();
1291 let mapping = doc.as_mapping().unwrap();
1292 let seq = mapping.get_sequence("items").unwrap();
1293
1294 seq.insert(0, "a");
1295
1296 let values: Vec<String> = seq.values().map(|v| v.to_string()).collect();
1297 assert_eq!(values, vec!["a", "b", "c"]);
1298 }
1299
1300 #[test]
1301 fn test_block_sequence_insert_middle() {
1302 use crate::Document;
1303 let doc = Document::from_str("items:\n - a\n - c").unwrap();
1304 let mapping = doc.as_mapping().unwrap();
1305 let seq = mapping.get_sequence("items").unwrap();
1306
1307 seq.insert(1, "b");
1308
1309 let values: Vec<String> = seq.values().map(|v| v.to_string()).collect();
1310 assert_eq!(values, vec!["a", "b", "c"]);
1311 }
1312
1313 #[test]
1314 fn test_block_sequence_insert_end() {
1315 use crate::Document;
1316 let doc = Document::from_str("items:\n - a\n - b").unwrap();
1317 let mapping = doc.as_mapping().unwrap();
1318 let seq = mapping.get_sequence("items").unwrap();
1319
1320 seq.insert(2, "c");
1321
1322 let values: Vec<String> = seq.values().map(|v| v.to_string()).collect();
1323 assert_eq!(values, vec!["a", "b", "c"]);
1324 }
1325
1326 #[test]
1327 fn test_sequence_get_node() {
1328 let doc = YamlFile::from_str("items:\n - alpha\n - beta\n - gamma")
1329 .unwrap()
1330 .document()
1331 .unwrap();
1332 let seq = doc.as_mapping().unwrap().get_sequence("items").unwrap();
1333
1334 assert_eq!(seq.len(), 3);
1335 assert!(seq.get(0).is_some());
1336 assert!(seq.get(1).is_some());
1337 assert!(seq.get(2).is_some());
1338 assert!(seq.get(3).is_none());
1339
1340 assert_eq!(
1341 seq.get(0).unwrap().as_scalar().unwrap().as_string(),
1342 "alpha"
1343 );
1344 assert_eq!(seq.get(1).unwrap().as_scalar().unwrap().as_string(), "beta");
1345 assert_eq!(
1346 seq.get(2).unwrap().as_scalar().unwrap().as_string(),
1347 "gamma"
1348 );
1349 }
1350
1351 #[test]
1352 fn test_sequence_set_with_nested_mapping() {
1353 use crate::path::YamlPath;
1354 use crate::Document;
1355
1356 let yaml_str = "items:\n - name: first\n value: 1\n - name: second\n value: 2\n";
1357 let doc = Document::from_str(yaml_str).unwrap();
1358
1359 let items_node = doc.get_path("items").unwrap();
1360 let items = items_node.as_sequence().unwrap();
1361
1362 assert_eq!(items.len(), 2);
1363 let first = items.get(0).unwrap();
1364 assert!(first.is_mapping());
1365
1366 items.set(0, "replaced");
1367 assert_eq!(
1368 doc.to_string(),
1369 "items:\n - replaced\n - name: second\n value: 2\n"
1370 );
1371 }
1372}