1use std::cell::RefCell;
34use std::collections::VecDeque;
35use std::fmt::Display;
36use std::iter::Peekable;
37use std::rc::Rc;
38use std::rc::Weak;
39
40use super::common::Ranged;
41use crate::ParseOptions;
42use crate::ast;
43use crate::errors::ParseError;
44use crate::parse_to_ast;
45use crate::string::ParseStringErrorKind;
46
47mod input;
48
49pub use input::*;
50
51macro_rules! add_root_node_method {
52 () => {
53 pub fn root_node(&self) -> Option<CstRootNode> {
58 self
59 .ancestors()
60 .filter_map(|parent| match parent {
61 CstContainerNode::Root(node) => Some(node),
62 _ => None,
63 })
64 .next()
65 }
66 };
67}
68
69macro_rules! add_parent_info_methods {
70 () => {
71 pub fn parent(&self) -> Option<CstContainerNode> {
76 self.parent_info().map(|p| p.parent.as_container_node())
77 }
78
79 pub fn ancestors(&self) -> impl Iterator<Item = CstContainerNode> {
81 AncestorIterator::new(self.clone().into())
82 }
83
84 pub fn child_index(&self) -> usize {
87 self.parent_info().map(|p| p.child_index).unwrap_or(0)
88 }
89
90 pub fn previous_sibling(&self) -> Option<CstNode> {
92 let parent_info = self.parent_info()?;
93 if parent_info.child_index == 0 {
94 return None;
95 }
96 parent_info
97 .parent
98 .as_container_node()
99 .child_at_index(parent_info.child_index - 1)
100 }
101
102 pub fn previous_siblings(&self) -> impl Iterator<Item = CstNode> {
105 PreviousSiblingIterator::new(self.clone().into())
106 }
107
108 pub fn next_sibling(&self) -> Option<CstNode> {
110 let parent_info = self.parent_info()?;
111 parent_info
112 .parent
113 .as_container_node()
114 .child_at_index(parent_info.child_index + 1)
115 }
116
117 pub fn next_siblings(&self) -> impl Iterator<Item = CstNode> {
120 NextSiblingIterator::new(self.clone().into())
121 }
122
123 pub fn indent_text(&self) -> Option<String> {
125 indent_text(&self.clone().into())
126 }
127
128 pub fn trailing_comma(&self) -> Option<CstToken> {
130 find_trailing_comma(&self.clone().into())
131 }
132
133 pub fn uses_trailing_commas(&self) -> bool {
135 uses_trailing_commas(self.clone().into())
136 }
137 };
138}
139
140fn find_trailing_comma(node: &CstNode) -> Option<CstToken> {
141 for next_sibling in node.next_siblings() {
142 match next_sibling {
143 CstNode::Container(_) => return None,
144 CstNode::Leaf(leaf) => match leaf {
145 CstLeafNode::BooleanLit(_)
146 | CstLeafNode::NullKeyword(_)
147 | CstLeafNode::NumberLit(_)
148 | CstLeafNode::StringLit(_)
149 | CstLeafNode::WordLit(_) => return None,
150 CstLeafNode::Token(token) => {
151 if token.value() == ',' {
152 return Some(token);
153 } else {
154 return None;
155 }
156 }
157 CstLeafNode::Whitespace(_) | CstLeafNode::Newline(_) | CstLeafNode::Comment(_) => {
158 }
160 },
161 }
162 }
163
164 None
165}
166
167macro_rules! add_parent_methods {
168 () => {
169 add_parent_info_methods!();
170
171 fn parent_info(&self) -> Option<ParentInfo> {
172 self.0.borrow().parent.clone()
173 }
174
175 fn set_parent(&self, parent: Option<ParentInfo>) {
176 self.0.borrow_mut().parent = parent;
177 }
178 };
179}
180
181macro_rules! impl_from_leaf_or_container {
182 ($node_name:ident, $variant:ident, $leaf_or_container:ident, $leaf_or_container_variant:ident) => {
183 impl From<$node_name> for CstNode {
184 fn from(value: $node_name) -> Self {
185 CstNode::$leaf_or_container_variant($leaf_or_container::$variant(value))
186 }
187 }
188
189 impl From<$node_name> for $leaf_or_container {
190 fn from(value: $node_name) -> Self {
191 $leaf_or_container::$variant(value)
192 }
193 }
194 };
195}
196
197macro_rules! impl_container_methods {
198 ($node_name:ident, $variant:ident) => {
199 impl_from_leaf_or_container!($node_name, $variant, CstContainerNode, Container);
200
201 impl $node_name {
202 add_parent_methods!();
203
204 pub fn children(&self) -> Vec<CstNode> {
206 self.0.borrow().value.clone()
207 }
208
209 pub fn children_exclude_trivia_and_tokens(&self) -> Vec<CstNode> {
211 self
212 .0
213 .borrow()
214 .value
215 .iter()
216 .filter(|n| !n.is_trivia() && !n.is_token())
217 .cloned()
218 .collect()
219 }
220
221 pub fn child_at_index(&self, index: usize) -> Option<CstNode> {
223 self.0.borrow().value.get(index).cloned()
224 }
225
226 fn remove_child_set_no_parent(&self, index: usize) {
227 let mut inner = self.0.borrow_mut();
228 if index < inner.value.len() {
229 let container = self.clone().into();
230 let child = inner.value.remove(index);
231 child.set_parent(None);
232
233 for index in index..inner.value.len() {
235 inner.value[index].set_parent(Some(ParentInfo {
236 parent: WeakParent::from_container(&container),
237 child_index: index,
238 }));
239 }
240 }
241 }
242 }
243 };
244}
245
246macro_rules! impl_leaf_methods {
247 ($node_name:ident, $variant:ident) => {
248 impl_from_leaf_or_container!($node_name, $variant, CstLeafNode, Leaf);
249
250 impl $node_name {
251 add_parent_methods!();
252 add_root_node_method!();
253 }
254 };
255}
256
257#[derive(Debug, Clone)]
258enum WeakParent {
259 Root(Weak<CstRootNodeInner>),
260 Object(Weak<CstObjectInner>),
261 ObjectProp(Weak<CstObjectPropInner>),
262 Array(Weak<CstArrayInner>),
263}
264
265impl WeakParent {
266 pub fn from_container(container: &CstContainerNode) -> Self {
267 match container {
268 CstContainerNode::Root(node) => WeakParent::Root(Rc::downgrade(&node.0)),
269 CstContainerNode::Object(node) => WeakParent::Object(Rc::downgrade(&node.0)),
270 CstContainerNode::ObjectProp(node) => WeakParent::ObjectProp(Rc::downgrade(&node.0)),
271 CstContainerNode::Array(node) => WeakParent::Array(Rc::downgrade(&node.0)),
272 }
273 }
274
275 pub fn as_container_node(&self) -> CstContainerNode {
276 const PANIC_MSG: &str = "Programming error. Ensure you keep around the RootNode for the duration of using the CST.";
280 match self {
281 WeakParent::Root(weak) => CstRootNode(weak.upgrade().expect(PANIC_MSG)).into(),
282 WeakParent::Object(weak) => CstObject(weak.upgrade().expect(PANIC_MSG)).into(),
283 WeakParent::ObjectProp(weak) => CstObjectProp(weak.upgrade().expect(PANIC_MSG)).into(),
284 WeakParent::Array(weak) => CstArray(weak.upgrade().expect(PANIC_MSG)).into(),
285 }
286 }
287}
288
289#[derive(Clone, Debug)]
290struct ParentInfo {
291 pub parent: WeakParent,
292 pub child_index: usize,
293}
294
295#[derive(Debug)]
296struct CstValueInner<T> {
297 parent: Option<ParentInfo>,
298 value: T,
299}
300
301impl<T> CstValueInner<T> {
302 fn new(value: T) -> Rc<RefCell<Self>> {
303 Rc::new(RefCell::new(CstValueInner { parent: None, value }))
304 }
305}
306
307type CstChildrenInner = CstValueInner<Vec<CstNode>>;
308
309#[derive(Debug, Clone)]
311pub enum CstNode {
312 Container(CstContainerNode),
313 Leaf(CstLeafNode),
314}
315
316impl CstNode {
317 add_parent_info_methods!();
318 add_root_node_method!();
319
320 pub fn is_trivia(&self) -> bool {
322 match self {
323 CstNode::Leaf(leaf) => match leaf {
324 CstLeafNode::BooleanLit(_)
325 | CstLeafNode::NullKeyword(_)
326 | CstLeafNode::NumberLit(_)
327 | CstLeafNode::StringLit(_)
328 | CstLeafNode::Token(_)
329 | CstLeafNode::WordLit(_) => false,
330 CstLeafNode::Whitespace(_) | CstLeafNode::Newline(_) | CstLeafNode::Comment(_) => true,
331 },
332 CstNode::Container(_) => false,
333 }
334 }
335
336 pub fn leading_comments_same_line(&self) -> impl Iterator<Item = CstComment> {
338 self
339 .previous_siblings()
340 .take_while(|n| n.is_whitespace() || n.is_comment())
341 .filter_map(|n| match n {
342 CstNode::Leaf(CstLeafNode::Comment(comment)) => Some(comment.clone()),
343 _ => None,
344 })
345 }
346
347 pub fn trailing_comments_same_line(&self) -> impl Iterator<Item = CstComment> {
351 for sibling in self.next_siblings() {
353 if sibling.is_newline() {
354 break;
355 } else if !sibling.is_comment() && !sibling.is_whitespace() {
356 return Box::new(std::iter::empty()) as Box<dyn Iterator<Item = CstComment>>;
357 }
358 }
359
360 Box::new(
361 self
362 .next_siblings()
363 .take_while(|n| n.is_whitespace() || n.is_comment())
364 .filter_map(|n| match n {
365 CstNode::Leaf(CstLeafNode::Comment(comment)) => Some(comment.clone()),
366 _ => None,
367 }),
368 )
369 }
370
371 pub fn is_newline(&self) -> bool {
373 matches!(self, CstNode::Leaf(CstLeafNode::Newline(_)))
374 }
375
376 pub fn is_comma(&self) -> bool {
378 match self {
379 CstNode::Leaf(CstLeafNode::Token(t)) => t.value() == ',',
380 _ => false,
381 }
382 }
383
384 pub fn is_comment(&self) -> bool {
386 matches!(self, CstNode::Leaf(CstLeafNode::Comment(_)))
387 }
388
389 pub fn is_token(&self) -> bool {
391 matches!(self, CstNode::Leaf(CstLeafNode::Token(_)))
392 }
393
394 pub fn is_whitespace(&self) -> bool {
396 matches!(self, CstNode::Leaf(CstLeafNode::Whitespace(_)))
397 }
398
399 pub fn token_char(&self) -> Option<char> {
401 match self {
402 CstNode::Leaf(CstLeafNode::Token(token)) => Some(token.value()),
403 _ => None,
404 }
405 }
406
407 pub fn children(&self) -> Vec<CstNode> {
409 match self {
410 CstNode::Container(n) => n.children(),
411 CstNode::Leaf(_) => Vec::new(),
412 }
413 }
414
415 pub fn children_exclude_trivia_and_tokens(&self) -> Vec<CstNode> {
417 match self {
418 CstNode::Container(n) => n.children_exclude_trivia_and_tokens(),
419 CstNode::Leaf(_) => Vec::new(),
420 }
421 }
422
423 pub fn child_at_index(&self, index: usize) -> Option<CstNode> {
425 match self {
426 CstNode::Container(n) => n.child_at_index(index),
427 CstNode::Leaf(_) => None,
428 }
429 }
430
431 pub fn element_index(&self) -> Option<usize> {
435 let child_index = self.child_index();
436 let array = self.parent()?.as_array()?;
437 array.elements().iter().position(|p| p.child_index() == child_index)
438 }
439
440 pub fn as_root_node(&self) -> Option<CstRootNode> {
442 match self {
443 CstNode::Container(CstContainerNode::Root(node)) => Some(node.clone()),
444 _ => None,
445 }
446 }
447
448 pub fn as_object(&self) -> Option<CstObject> {
450 match self {
451 CstNode::Container(CstContainerNode::Object(node)) => Some(node.clone()),
453 _ => None,
454 }
455 }
456
457 pub fn as_array(&self) -> Option<CstArray> {
459 match self {
460 CstNode::Container(CstContainerNode::Array(node)) => Some(node.clone()),
461 _ => None,
462 }
463 }
464
465 pub fn as_object_prop(&self) -> Option<CstObjectProp> {
467 match self {
468 CstNode::Container(CstContainerNode::ObjectProp(node)) => Some(node.clone()),
469 _ => None,
470 }
471 }
472
473 pub fn as_boolean_lit(&self) -> Option<CstBooleanLit> {
475 match self {
476 CstNode::Leaf(CstLeafNode::BooleanLit(node)) => Some(node.clone()),
477 _ => None,
478 }
479 }
480
481 pub fn as_null_keyword(&self) -> Option<CstNullKeyword> {
483 match self {
484 CstNode::Leaf(CstLeafNode::NullKeyword(node)) => Some(node.clone()),
485 _ => None,
486 }
487 }
488
489 pub fn as_number_lit(&self) -> Option<CstNumberLit> {
491 match self {
492 CstNode::Leaf(CstLeafNode::NumberLit(node)) => Some(node.clone()),
493 _ => None,
494 }
495 }
496
497 pub fn as_string_lit(&self) -> Option<CstStringLit> {
499 match self {
500 CstNode::Leaf(CstLeafNode::StringLit(node)) => Some(node.clone()),
501 _ => None,
502 }
503 }
504
505 pub fn as_word_lit(&self) -> Option<CstWordLit> {
507 match self {
508 CstNode::Leaf(CstLeafNode::WordLit(node)) => Some(node.clone()),
509 _ => None,
510 }
511 }
512
513 pub fn as_token(&self) -> Option<CstToken> {
515 match self {
516 CstNode::Leaf(CstLeafNode::Token(node)) => Some(node.clone()),
517 _ => None,
518 }
519 }
520
521 pub fn as_newline(&self) -> Option<CstNewline> {
523 match self {
524 CstNode::Leaf(CstLeafNode::Newline(node)) => Some(node.clone()),
525 _ => None,
526 }
527 }
528
529 pub fn as_whitespace(&self) -> Option<CstWhitespace> {
531 match self {
532 CstNode::Leaf(CstLeafNode::Whitespace(node)) => Some(node.clone()),
533 _ => None,
534 }
535 }
536
537 pub fn as_comment(&self) -> Option<CstComment> {
539 match self {
540 CstNode::Leaf(CstLeafNode::Comment(node)) => Some(node.clone()),
541 _ => None,
542 }
543 }
544
545 pub fn remove(self) {
549 match self {
550 CstNode::Container(n) => n.remove(),
551 CstNode::Leaf(n) => n.remove(),
552 }
553 }
554
555 fn parent_info(&self) -> Option<ParentInfo> {
556 match self {
557 CstNode::Container(node) => node.parent_info(),
558 CstNode::Leaf(node) => node.parent_info(),
559 }
560 }
561
562 fn set_parent(&self, parent: Option<ParentInfo>) {
563 match self {
564 CstNode::Container(node) => node.set_parent(parent),
565 CstNode::Leaf(node) => node.set_parent(parent),
566 }
567 }
568
569 fn remove_raw(self) {
571 let Some(parent_info) = self.parent_info() else {
572 return; };
574 parent_info
575 .parent
576 .as_container_node()
577 .remove_child_set_no_parent(parent_info.child_index);
578 }
579
580 #[cfg(feature = "serde_json")]
602 pub fn to_serde_value(&self) -> Option<serde_json::Value> {
603 match self {
604 CstNode::Container(container) => container.to_serde_value(),
605 CstNode::Leaf(leaf) => leaf.to_serde_value(),
606 }
607 }
608}
609
610impl Display for CstNode {
611 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
612 match self {
613 CstNode::Container(node) => node.fmt(f),
614 CstNode::Leaf(node) => node.fmt(f),
615 }
616 }
617}
618
619#[derive(Default, Debug, Clone)]
620struct StyleInfo {
621 pub uses_trailing_commas: bool,
622 pub newline_kind: CstNewlineKind,
623}
624
625#[derive(Debug, Clone)]
627pub enum CstContainerNode {
628 Root(CstRootNode),
629 Array(CstArray),
630 Object(CstObject),
631 ObjectProp(CstObjectProp),
632}
633
634impl CstContainerNode {
635 add_parent_info_methods!();
636 add_root_node_method!();
637
638 pub fn is_root(&self) -> bool {
640 matches!(self, CstContainerNode::Root(_))
641 }
642
643 pub fn is_array(&self) -> bool {
645 matches!(self, CstContainerNode::Array(_))
646 }
647
648 pub fn is_object(&self) -> bool {
650 matches!(self, CstContainerNode::Object(_))
651 }
652
653 pub fn is_object_prop(&self) -> bool {
655 matches!(self, CstContainerNode::ObjectProp(_))
656 }
657
658 pub fn as_root(&self) -> Option<CstRootNode> {
660 match self {
661 CstContainerNode::Root(node) => Some(node.clone()),
662 _ => None,
663 }
664 }
665
666 pub fn as_array(&self) -> Option<CstArray> {
668 match self {
669 CstContainerNode::Array(node) => Some(node.clone()),
670 _ => None,
671 }
672 }
673
674 pub fn as_object(&self) -> Option<CstObject> {
676 match self {
677 CstContainerNode::Object(node) => Some(node.clone()),
678 _ => None,
679 }
680 }
681
682 pub fn as_object_prop(&self) -> Option<CstObjectProp> {
684 match self {
685 CstContainerNode::ObjectProp(node) => Some(node.clone()),
686 _ => None,
687 }
688 }
689
690 pub fn children(&self) -> Vec<CstNode> {
692 match self {
693 CstContainerNode::Root(n) => n.children(),
694 CstContainerNode::Object(n) => n.children(),
695 CstContainerNode::ObjectProp(n) => n.children(),
696 CstContainerNode::Array(n) => n.children(),
697 }
698 }
699
700 pub fn children_exclude_trivia_and_tokens(&self) -> Vec<CstNode> {
702 match self {
703 CstContainerNode::Root(n) => n.children_exclude_trivia_and_tokens(),
704 CstContainerNode::Object(n) => n.children_exclude_trivia_and_tokens(),
705 CstContainerNode::ObjectProp(n) => n.children_exclude_trivia_and_tokens(),
706 CstContainerNode::Array(n) => n.children_exclude_trivia_and_tokens(),
707 }
708 }
709
710 pub fn child_at_index(&self, index: usize) -> Option<CstNode> {
712 match self {
713 CstContainerNode::Root(node) => node.child_at_index(index),
714 CstContainerNode::Object(node) => node.child_at_index(index),
715 CstContainerNode::ObjectProp(node) => node.child_at_index(index),
716 CstContainerNode::Array(node) => node.child_at_index(index),
717 }
718 }
719
720 fn remove_child_set_no_parent(&self, index: usize) {
721 match self {
722 CstContainerNode::Root(n) => n.remove_child_set_no_parent(index),
723 CstContainerNode::Object(n) => n.remove_child_set_no_parent(index),
724 CstContainerNode::ObjectProp(n) => n.remove_child_set_no_parent(index),
725 CstContainerNode::Array(n) => n.remove_child_set_no_parent(index),
726 }
727 }
728
729 pub fn remove(self) {
731 match self {
732 CstContainerNode::Root(n) => n.clear_children(),
733 CstContainerNode::Object(n) => n.remove(),
734 CstContainerNode::ObjectProp(n) => n.remove(),
735 CstContainerNode::Array(n) => n.remove(),
736 }
737 }
738
739 fn parent_info(&self) -> Option<ParentInfo> {
740 match self {
741 CstContainerNode::Root(node) => node.parent_info(),
742 CstContainerNode::Object(node) => node.parent_info(),
743 CstContainerNode::ObjectProp(node) => node.parent_info(),
744 CstContainerNode::Array(node) => node.parent_info(),
745 }
746 }
747
748 fn set_parent(&self, parent: Option<ParentInfo>) {
749 match self {
750 CstContainerNode::Root(node) => node.set_parent(parent),
751 CstContainerNode::Object(node) => node.set_parent(parent),
752 CstContainerNode::ObjectProp(node) => node.set_parent(parent),
753 CstContainerNode::Array(node) => node.set_parent(parent),
754 }
755 }
756
757 #[inline(always)]
758 fn raw_append_child(&self, child: CstNode) {
759 self.raw_insert_child(None, child);
760 }
761
762 #[inline(always)]
763 fn raw_insert_child(&self, index: Option<&mut usize>, child: CstNode) {
764 self.raw_insert_children(index, vec![child]);
765 }
766
767 #[inline(always)]
768 fn raw_append_children(&self, children: Vec<CstNode>) {
769 self.raw_insert_children(None, children);
770 }
771
772 fn raw_insert_children(&self, index: Option<&mut usize>, children: Vec<CstNode>) {
773 if children.is_empty() {
774 return;
775 }
776
777 let weak_parent = WeakParent::from_container(self);
778 let mut container = match self {
779 CstContainerNode::Root(node) => node.0.borrow_mut(),
780 CstContainerNode::Object(node) => node.0.borrow_mut(),
781 CstContainerNode::ObjectProp(node) => node.0.borrow_mut(),
782 CstContainerNode::Array(node) => node.0.borrow_mut(),
783 };
784 let insert_index = index.as_ref().map(|i| **i).unwrap_or(container.value.len());
785 if let Some(i) = index {
786 *i += children.len();
787 }
788 container.value.splice(insert_index..insert_index, children);
789
790 for (i, child) in container.value.iter().enumerate().skip(insert_index) {
792 child.set_parent(Some(ParentInfo {
793 parent: weak_parent.clone(),
794 child_index: i,
795 }));
796 }
797 }
798
799 fn raw_insert_value_with_internal_indent(
800 &self,
801 insert_index: Option<&mut usize>,
802 value: InsertValue,
803 style_info: &StyleInfo,
804 indents: &Indents,
805 ) {
806 match value {
807 InsertValue::Value(value) => {
808 let is_multiline = value.force_multiline();
809 match value {
810 CstInputValue::Null => {
811 self.raw_insert_child(insert_index, CstLeafNode::NullKeyword(CstNullKeyword::new()).into());
812 }
813 CstInputValue::Bool(value) => {
814 self.raw_insert_child(insert_index, CstLeafNode::BooleanLit(CstBooleanLit::new(value)).into());
815 }
816 CstInputValue::Number(value) => {
817 self.raw_insert_child(insert_index, CstLeafNode::NumberLit(CstNumberLit::new(value)).into());
818 }
819 CstInputValue::String(value) => {
820 self.raw_insert_child(
821 insert_index,
822 CstLeafNode::StringLit(CstStringLit::new_escaped(&value)).into(),
823 );
824 }
825 CstInputValue::Array(elements) => {
826 let array_node: CstContainerNode = CstArray::new_no_tokens().into();
827 self.raw_insert_child(insert_index, array_node.clone().into());
828
829 array_node.raw_append_child(CstToken::new('[').into());
830 if !elements.is_empty() {
831 let indents = indents.indent();
832 let mut elements = elements.into_iter().peekable();
833 while let Some(value) = elements.next() {
834 if is_multiline {
835 array_node.raw_insert_children(
836 None,
837 vec![
838 CstNewline::new(style_info.newline_kind).into(),
839 CstWhitespace::new(indents.current_indent.clone()).into(),
840 ],
841 );
842 }
843
844 array_node.raw_insert_value_with_internal_indent(None, InsertValue::Value(value), style_info, &indents);
845
846 if style_info.uses_trailing_commas && is_multiline || elements.peek().is_some() {
847 if is_multiline {
848 array_node.raw_append_child(CstToken::new(',').into());
849 } else {
850 array_node.raw_insert_children(
851 None,
852 vec![CstToken::new(',').into(), CstWhitespace::new(" ".to_string()).into()],
853 );
854 }
855 }
856 }
857 }
858
859 if is_multiline {
860 array_node.raw_append_children(vec![
861 CstNewline::new(style_info.newline_kind).into(),
862 CstWhitespace::new(indents.current_indent.clone()).into(),
863 ]);
864 }
865
866 array_node.raw_append_child(CstToken::new(']').into());
867 }
868 CstInputValue::Object(properties) => {
869 let object_node: CstContainerNode = CstObject::new_no_tokens().into();
870 self.raw_insert_child(insert_index, object_node.clone().into());
871
872 object_node.raw_append_child(CstToken::new('{').into());
873
874 if !properties.is_empty() {
875 {
876 let indents = indents.indent();
877 let mut properties = properties.into_iter().peekable();
878 while let Some((prop_name, value)) = properties.next() {
879 object_node.raw_append_child(CstNewline::new(style_info.newline_kind).into());
880 object_node.raw_append_child(CstWhitespace::new(indents.current_indent.clone()).into());
881 object_node.raw_insert_value_with_internal_indent(
882 None,
883 InsertValue::Property(&prop_name, value),
884 style_info,
885 &indents,
886 );
887 if style_info.uses_trailing_commas || properties.peek().is_some() {
888 object_node.raw_append_child(CstToken::new(',').into());
889 }
890 }
891 }
892
893 object_node.raw_append_children(vec![
894 CstNewline::new(style_info.newline_kind).into(),
895 CstWhitespace::new(indents.current_indent.clone()).into(),
896 ]);
897 }
898
899 object_node.raw_append_child(CstToken::new('}').into());
900 }
901 }
902 }
903 InsertValue::Property(prop_name, value) => {
904 let prop = CstContainerNode::ObjectProp(CstObjectProp::new());
905 self.raw_insert_child(insert_index, prop.clone().into());
906 prop.raw_insert_children(
907 None,
908 vec![
909 CstStringLit::new_escaped(prop_name).into(),
910 CstToken::new(':').into(),
911 CstWhitespace::new(" ".to_string()).into(),
912 ],
913 );
914 prop.raw_insert_value_with_internal_indent(None, InsertValue::Value(value), style_info, indents);
915 }
916 }
917 }
918
919 #[cfg(feature = "serde_json")]
923 pub fn to_serde_value(&self) -> Option<serde_json::Value> {
924 match self {
925 CstContainerNode::Root(node) => node.to_serde_value(),
926 CstContainerNode::Array(node) => node.to_serde_value(),
927 CstContainerNode::Object(node) => node.to_serde_value(),
928 CstContainerNode::ObjectProp(node) => node.to_serde_value(),
929 }
930 }
931}
932
933impl From<CstContainerNode> for CstNode {
934 fn from(value: CstContainerNode) -> Self {
935 CstNode::Container(value)
936 }
937}
938
939impl Display for CstContainerNode {
940 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
941 match self {
942 CstContainerNode::Root(node) => node.fmt(f),
943 CstContainerNode::Object(node) => node.fmt(f),
944 CstContainerNode::ObjectProp(node) => node.fmt(f),
945 CstContainerNode::Array(node) => node.fmt(f),
946 }
947 }
948}
949
950#[derive(Debug, Clone)]
952pub enum CstLeafNode {
953 BooleanLit(CstBooleanLit),
954 NullKeyword(CstNullKeyword),
955 NumberLit(CstNumberLit),
956 StringLit(CstStringLit),
957 WordLit(CstWordLit),
958 Token(CstToken),
959 Whitespace(CstWhitespace),
960 Newline(CstNewline),
961 Comment(CstComment),
962}
963
964impl CstLeafNode {
965 add_parent_info_methods!();
966 add_root_node_method!();
967
968 pub fn remove(self) {
970 match self {
971 CstLeafNode::BooleanLit(n) => n.remove(),
972 CstLeafNode::NullKeyword(n) => n.remove(),
973 CstLeafNode::NumberLit(n) => n.remove(),
974 CstLeafNode::StringLit(n) => n.remove(),
975 CstLeafNode::WordLit(n) => n.remove(),
976 CstLeafNode::Token(n) => n.remove(),
977 CstLeafNode::Whitespace(n) => n.remove(),
978 CstLeafNode::Newline(n) => n.remove(),
979 CstLeafNode::Comment(n) => n.remove(),
980 }
981 }
982
983 fn parent_info(&self) -> Option<ParentInfo> {
984 match self {
985 CstLeafNode::BooleanLit(node) => node.parent_info(),
986 CstLeafNode::NullKeyword(node) => node.parent_info(),
987 CstLeafNode::NumberLit(node) => node.parent_info(),
988 CstLeafNode::StringLit(node) => node.parent_info(),
989 CstLeafNode::WordLit(node) => node.parent_info(),
990 CstLeafNode::Token(node) => node.parent_info(),
991 CstLeafNode::Whitespace(node) => node.parent_info(),
992 CstLeafNode::Newline(node) => node.parent_info(),
993 CstLeafNode::Comment(node) => node.parent_info(),
994 }
995 }
996
997 fn set_parent(&self, parent: Option<ParentInfo>) {
998 match self {
999 CstLeafNode::BooleanLit(node) => node.set_parent(parent),
1000 CstLeafNode::NullKeyword(node) => node.set_parent(parent),
1001 CstLeafNode::NumberLit(node) => node.set_parent(parent),
1002 CstLeafNode::StringLit(node) => node.set_parent(parent),
1003 CstLeafNode::WordLit(node) => node.set_parent(parent),
1004 CstLeafNode::Token(node) => node.set_parent(parent),
1005 CstLeafNode::Whitespace(node) => node.set_parent(parent),
1006 CstLeafNode::Newline(node) => node.set_parent(parent),
1007 CstLeafNode::Comment(node) => node.set_parent(parent),
1008 }
1009 }
1010
1011 #[cfg(feature = "serde_json")]
1015 pub fn to_serde_value(&self) -> Option<serde_json::Value> {
1016 match self {
1017 CstLeafNode::BooleanLit(node) => node.to_serde_value(),
1018 CstLeafNode::NullKeyword(node) => node.to_serde_value(),
1019 CstLeafNode::NumberLit(node) => node.to_serde_value(),
1020 CstLeafNode::StringLit(node) => node.to_serde_value(),
1021 CstLeafNode::WordLit(_)
1022 | CstLeafNode::Token(_)
1023 | CstLeafNode::Whitespace(_)
1024 | CstLeafNode::Newline(_)
1025 | CstLeafNode::Comment(_) => None,
1026 }
1027 }
1028}
1029
1030impl Display for CstLeafNode {
1031 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1032 match self {
1033 CstLeafNode::BooleanLit(node) => node.fmt(f),
1034 CstLeafNode::NullKeyword(node) => node.fmt(f),
1035 CstLeafNode::NumberLit(node) => node.fmt(f),
1036 CstLeafNode::StringLit(node) => node.fmt(f),
1037 CstLeafNode::WordLit(node) => node.fmt(f),
1038 CstLeafNode::Token(node) => node.fmt(f),
1039 CstLeafNode::Whitespace(node) => node.fmt(f),
1040 CstLeafNode::Newline(node) => node.fmt(f),
1041 CstLeafNode::Comment(node) => node.fmt(f),
1042 }
1043 }
1044}
1045
1046impl From<CstLeafNode> for CstNode {
1047 fn from(value: CstLeafNode) -> Self {
1048 CstNode::Leaf(value)
1049 }
1050}
1051
1052#[derive(Default, Debug, Clone, Copy)]
1054pub enum TrailingCommaMode {
1055 #[default]
1057 Never,
1058 IfMultiline,
1060}
1061
1062type CstRootNodeInner = RefCell<CstChildrenInner>;
1063
1064#[derive(Debug, Clone)]
1068pub struct CstRootNode(Rc<CstRootNodeInner>);
1069
1070impl_container_methods!(CstRootNode, Root);
1071
1072impl CstRootNode {
1073 pub fn parse(text: &str, parse_options: &ParseOptions) -> Result<Self, ParseError> {
1108 let parse_result = parse_to_ast(
1109 text,
1110 &crate::CollectOptions {
1111 comments: crate::CommentCollectionStrategy::AsTokens,
1112 tokens: true,
1113 },
1114 parse_options,
1115 )?;
1116
1117 Ok(
1118 CstBuilder {
1119 text,
1120 tokens: parse_result.tokens.unwrap().into_iter().collect(),
1121 }
1122 .build(parse_result.value),
1123 )
1124 }
1125
1126 pub fn single_indent_text(&self) -> Option<String> {
1128 let root_value = self.value()?;
1129 let first_non_trivia_child = root_value.children_exclude_trivia_and_tokens().first()?.clone();
1130 let mut last_whitespace = None;
1131 for previous_trivia in first_non_trivia_child.previous_siblings() {
1132 match previous_trivia {
1133 CstNode::Leaf(CstLeafNode::Whitespace(whitespace)) => {
1134 last_whitespace = Some(whitespace);
1135 }
1136 CstNode::Leaf(CstLeafNode::Newline(_)) => {
1137 return last_whitespace.map(|whitespace| whitespace.0.borrow().value.clone());
1138 }
1139 _ => {
1140 last_whitespace = None;
1141 }
1142 }
1143 }
1144 None
1145 }
1146
1147 pub fn newline_kind(&self) -> CstNewlineKind {
1149 let mut current_children: VecDeque<CstContainerNode> = VecDeque::from([self.clone().into()]);
1150 while let Some(child) = current_children.pop_front() {
1151 for child in child.children() {
1152 if let CstNode::Container(child) = child {
1153 current_children.push_back(child);
1154 } else if let CstNode::Leaf(CstLeafNode::Newline(node)) = child {
1155 return node.kind();
1156 }
1157 }
1158 }
1159 CstNewlineKind::LineFeed
1160 }
1161
1162 pub fn value(&self) -> Option<CstNode> {
1164 for child in &self.0.borrow().value {
1165 if !child.is_trivia() {
1166 return Some(child.clone());
1167 }
1168 }
1169 None
1170 }
1171
1172 pub fn set_value(&self, root_value: CstInputValue) {
1174 let container: CstContainerNode = self.clone().into();
1175 let style_info = StyleInfo {
1176 newline_kind: self.newline_kind(),
1177 uses_trailing_commas: uses_trailing_commas(self.clone().into()),
1178 };
1179 let indents = compute_indents(&self.clone().into());
1180 let mut insert_index = if let Some(root_value) = self.value() {
1181 let index = root_value.child_index();
1182 root_value.remove_raw();
1183 index
1184 } else {
1185 let children = self.children();
1186 let mut index = match children.last() {
1187 Some(CstNode::Leaf(CstLeafNode::Newline(_))) => children.len() - 1,
1188 _ => children.len(),
1189 };
1190 let previous_node = if index == 0 { None } else { children.get(index - 1) };
1191 if let Some(CstNode::Leaf(CstLeafNode::Comment(_))) = previous_node {
1192 container.raw_insert_child(Some(&mut index), CstNewline::new(style_info.newline_kind).into());
1194 }
1195 if self.child_at_index(index).is_none() {
1196 container.raw_insert_child(Some(&mut index), CstNewline::new(style_info.newline_kind).into());
1198 index -= 1;
1199 }
1200 index
1201 };
1202 container.raw_insert_value_with_internal_indent(
1203 Some(&mut insert_index),
1204 InsertValue::Value(root_value),
1205 &style_info,
1206 &indents,
1207 );
1208 }
1209
1210 pub fn object_value(&self) -> Option<CstObject> {
1212 self.value()?.as_object()
1213 }
1214
1215 pub fn object_value_or_create(&self) -> Option<CstObject> {
1221 match self.value() {
1222 Some(CstNode::Container(CstContainerNode::Object(node))) => Some(node),
1223 Some(_) => None,
1224 None => {
1225 self.set_value(CstInputValue::Object(Vec::new()));
1226 self.object_value()
1227 }
1228 }
1229 }
1230
1231 pub fn object_value_or_set(&self) -> CstObject {
1236 match self.value() {
1237 Some(CstNode::Container(CstContainerNode::Object(node))) => node,
1238 _ => {
1239 self.set_value(CstInputValue::Object(Vec::new()));
1240 self.object_value().unwrap()
1241 }
1242 }
1243 }
1244
1245 pub fn array_value(&self) -> Option<CstArray> {
1247 self.value()?.as_array()
1248 }
1249
1250 pub fn array_value_or_create(&self) -> Option<CstArray> {
1256 match self.value() {
1257 Some(CstNode::Container(CstContainerNode::Array(node))) => Some(node),
1258 Some(_) => None,
1259 None => {
1260 self.set_value(CstInputValue::Array(Vec::new()));
1261 self.array_value()
1262 }
1263 }
1264 }
1265
1266 pub fn array_value_or_set(&self) -> CstArray {
1271 match self.value() {
1272 Some(CstNode::Container(CstContainerNode::Array(node))) => node,
1273 _ => {
1274 self.set_value(CstInputValue::Array(Vec::new()));
1275 self.array_value().unwrap()
1276 }
1277 }
1278 }
1279
1280 pub fn set_trailing_commas(&self, mode: TrailingCommaMode) {
1286 let Some(value) = self.value() else {
1287 return;
1288 };
1289
1290 match value {
1291 CstNode::Container(container) => match container {
1292 CstContainerNode::Array(n) => n.set_trailing_commas(mode),
1293 CstContainerNode::Object(n) => n.set_trailing_commas(mode),
1294 _ => {}
1295 },
1296 CstNode::Leaf(_) => {}
1297 }
1298 }
1299
1300 pub fn clear_children(&self) {
1302 let children = std::mem::take(&mut self.0.borrow_mut().value);
1303 for child in children {
1304 child.set_parent(None);
1305 }
1306 }
1307
1308 #[cfg(feature = "serde_json")]
1312 pub fn to_serde_value(&self) -> Option<serde_json::Value> {
1313 self.value()?.to_serde_value()
1314 }
1315}
1316
1317impl Display for CstRootNode {
1318 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1319 for child in &self.0.borrow().value {
1320 write!(f, "{}", child)?;
1321 }
1322 Ok(())
1323 }
1324}
1325
1326#[derive(Debug, Clone)]
1328pub struct CstStringLit(Rc<RefCell<CstValueInner<String>>>);
1329
1330impl_leaf_methods!(CstStringLit, StringLit);
1331
1332impl CstStringLit {
1333 fn new(value: String) -> Self {
1334 Self(CstValueInner::new(value))
1335 }
1336
1337 fn new_escaped(value: &str) -> Self {
1338 let mut escaped = String::with_capacity(value.len() + 2);
1339 escaped.push('"');
1340 for ch in value.chars() {
1341 match ch {
1342 '"' => escaped.push_str("\\\""),
1343 '\\' => escaped.push_str("\\\\"),
1344 '\u{08}' => escaped.push_str("\\b"),
1345 '\u{0c}' => escaped.push_str("\\f"),
1346 '\n' => escaped.push_str("\\n"),
1347 '\r' => escaped.push_str("\\r"),
1348 '\t' => escaped.push_str("\\t"),
1349 c if c.is_control() => {
1350 escaped.push_str(&format!("\\u{:04x}", c as u32));
1351 }
1352 c => escaped.push(c),
1353 }
1354 }
1355 escaped.push('"');
1356 Self::new(escaped)
1357 }
1358
1359 pub fn set_raw_value(&self, value: String) {
1361 self.0.borrow_mut().value = value;
1362 }
1363
1364 pub fn raw_value(&self) -> String {
1366 self.0.borrow().value.clone()
1367 }
1368
1369 pub fn decoded_value(&self) -> Result<String, ParseStringErrorKind> {
1371 let inner = self.0.borrow();
1372 crate::string::parse_string(&inner.value)
1373 .map(|value| value.into_owned())
1374 .map_err(|err| err.kind)
1375 }
1376
1377 pub fn replace_with(self, replacement: CstInputValue) -> Option<CstNode> {
1379 replace_with(self.into(), InsertValue::Value(replacement))
1380 }
1381
1382 pub fn remove(self) {
1384 remove_comma_separated(self.into())
1385 }
1386
1387 #[cfg(feature = "serde_json")]
1389 pub fn to_serde_value(&self) -> Option<serde_json::Value> {
1390 self.decoded_value().ok().map(serde_json::Value::String)
1391 }
1392}
1393
1394impl Display for CstStringLit {
1395 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1396 write!(f, "{}", self.0.borrow().value)
1397 }
1398}
1399
1400#[derive(Debug, Clone)]
1402pub struct CstWordLit(Rc<RefCell<CstValueInner<String>>>);
1403
1404impl_leaf_methods!(CstWordLit, WordLit);
1405
1406impl CstWordLit {
1407 fn new(value: String) -> Self {
1408 Self(CstValueInner::new(value))
1409 }
1410
1411 pub fn set_raw_value(&self, value: String) {
1413 self.0.borrow_mut().value = value;
1414 }
1415
1416 pub fn replace_with(self, replacement: CstInputValue) -> Option<CstNode> {
1418 replace_with(self.into(), InsertValue::Value(replacement))
1419 }
1420
1421 pub fn remove(self) {
1423 remove_comma_separated(self.into())
1424 }
1425}
1426
1427impl Display for CstWordLit {
1428 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1429 write!(f, "{}", self.0.borrow().value)
1430 }
1431}
1432
1433#[derive(Debug, Clone)]
1434pub struct CstNumberLit(Rc<RefCell<CstValueInner<String>>>);
1435
1436impl_leaf_methods!(CstNumberLit, NumberLit);
1437
1438impl CstNumberLit {
1439 fn new(value: String) -> Self {
1440 Self(CstValueInner::new(value))
1441 }
1442
1443 pub fn set_raw_value(&self, value: String) {
1445 self.0.borrow_mut().value = value;
1446 }
1447
1448 pub fn replace_with(self, replacement: CstInputValue) -> Option<CstNode> {
1450 replace_with(self.into(), InsertValue::Value(replacement))
1451 }
1452
1453 pub fn remove(self) {
1455 remove_comma_separated(self.into())
1456 }
1457
1458 #[cfg(feature = "serde_json")]
1460 pub fn to_serde_value(&self) -> Option<serde_json::Value> {
1461 use std::str::FromStr;
1462 let raw = self.0.borrow().value.clone();
1463
1464 let num_str = raw.trim_start_matches(['-', '+']);
1466 if num_str.len() > 2 && (num_str.starts_with("0x") || num_str.starts_with("0X")) {
1467 let hex_part = &num_str[2..];
1469 match i64::from_str_radix(hex_part, 16) {
1470 Ok(decimal_value) => {
1471 let final_value = if raw.starts_with('-') {
1472 -decimal_value
1473 } else {
1474 decimal_value
1475 };
1476 Some(serde_json::Value::Number(serde_json::Number::from(final_value)))
1477 }
1478 Err(_) => Some(serde_json::Value::String(raw)),
1479 }
1480 } else {
1481 let num_for_parsing = raw.trim_start_matches('+');
1483 match serde_json::Number::from_str(num_for_parsing) {
1484 Ok(number) => Some(serde_json::Value::Number(number)),
1485 Err(_) => Some(serde_json::Value::String(raw)),
1487 }
1488 }
1489 }
1490}
1491
1492impl Display for CstNumberLit {
1493 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1494 write!(f, "{}", self.0.borrow().value)
1495 }
1496}
1497
1498#[derive(Debug, Clone)]
1500pub struct CstBooleanLit(Rc<RefCell<CstValueInner<bool>>>);
1501
1502impl_leaf_methods!(CstBooleanLit, BooleanLit);
1503
1504impl CstBooleanLit {
1505 fn new(value: bool) -> Self {
1506 Self(CstValueInner::new(value))
1507 }
1508
1509 pub fn value(&self) -> bool {
1511 self.0.borrow().value
1512 }
1513
1514 pub fn set_value(&self, value: bool) {
1516 self.0.borrow_mut().value = value;
1517 }
1518
1519 pub fn replace_with(self, replacement: CstInputValue) -> Option<CstNode> {
1521 replace_with(self.into(), InsertValue::Value(replacement))
1522 }
1523
1524 pub fn remove(self) {
1526 remove_comma_separated(self.into())
1527 }
1528
1529 #[cfg(feature = "serde_json")]
1531 pub fn to_serde_value(&self) -> Option<serde_json::Value> {
1532 Some(serde_json::Value::Bool(self.value()))
1533 }
1534}
1535
1536impl Display for CstBooleanLit {
1537 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1538 if self.0.borrow().value {
1539 write!(f, "true")
1540 } else {
1541 write!(f, "false")
1542 }
1543 }
1544}
1545
1546#[derive(Debug, Clone)]
1548pub struct CstNullKeyword(Rc<RefCell<CstValueInner<()>>>);
1549
1550impl CstNullKeyword {
1551 fn new() -> Self {
1552 Self(CstValueInner::new(()))
1553 }
1554
1555 pub fn replace_with(self, replacement: CstInputValue) -> Option<CstNode> {
1557 replace_with(self.into(), InsertValue::Value(replacement))
1558 }
1559
1560 pub fn remove(self) {
1562 remove_comma_separated(self.into())
1563 }
1564
1565 #[cfg(feature = "serde_json")]
1567 pub fn to_serde_value(&self) -> Option<serde_json::Value> {
1568 Some(serde_json::Value::Null)
1569 }
1570}
1571
1572impl_leaf_methods!(CstNullKeyword, NullKeyword);
1573
1574impl Display for CstNullKeyword {
1575 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1576 write!(f, "null")
1577 }
1578}
1579
1580type CstObjectInner = RefCell<CstChildrenInner>;
1581
1582#[derive(Debug, Clone)]
1584pub struct CstObject(Rc<CstObjectInner>);
1585
1586impl_container_methods!(CstObject, Object);
1587
1588impl CstObject {
1589 add_root_node_method!();
1590
1591 fn new_no_tokens() -> Self {
1592 Self(CstValueInner::new(Vec::new()))
1593 }
1594
1595 fn new_with_tokens() -> Self {
1596 let object = CstObject::new_no_tokens();
1597 let container: CstContainerNode = object.clone().into();
1598 container.raw_append_children(vec![CstToken::new('{').into(), CstToken::new('}').into()]);
1599 object
1600 }
1601
1602 pub fn array_value(&self, name: &str) -> Option<CstArray> {
1606 match self.get(name)?.value()? {
1607 CstNode::Container(CstContainerNode::Array(node)) => Some(node),
1608 _ => None,
1609 }
1610 }
1611
1612 pub fn array_value_or_create(&self, name: &str) -> Option<CstArray> {
1619 match self.get(name) {
1620 Some(prop) => match prop.value()? {
1621 CstNode::Container(CstContainerNode::Array(node)) => Some(node),
1622 _ => None,
1623 },
1624 None => {
1625 self.append(name, CstInputValue::Array(Vec::new()));
1626 self.array_value(name)
1627 }
1628 }
1629 }
1630
1631 pub fn array_value_or_set(&self, name: &str) -> CstArray {
1636 match self.get(name) {
1637 Some(prop) => match prop.value() {
1638 Some(CstNode::Container(CstContainerNode::Array(node))) => node,
1639 Some(node) => {
1640 let mut index = node.child_index();
1641 node.remove_raw();
1642 let container: CstContainerNode = prop.clone().into();
1643 let array = CstArray::new_with_tokens();
1644 container.raw_insert_child(Some(&mut index), array.clone().into());
1645 array
1646 }
1647 _ => {
1648 let mut index = prop.children().len();
1649 let container: CstContainerNode = prop.clone().into();
1650 let array = CstArray::new_with_tokens();
1651 container.raw_insert_child(Some(&mut index), array.clone().into());
1652 array
1653 }
1654 },
1655 None => {
1656 self.append(name, CstInputValue::Array(Vec::new()));
1657 self.array_value(name).unwrap()
1658 }
1659 }
1660 }
1661
1662 pub fn object_value(&self, name: &str) -> Option<CstObject> {
1666 match self.get(name)?.value()? {
1667 CstNode::Container(CstContainerNode::Object(node)) => Some(node),
1668 _ => None,
1669 }
1670 }
1671
1672 pub fn object_value_or_create(&self, name: &str) -> Option<CstObject> {
1679 match self.get(name) {
1680 Some(prop) => match prop.value()? {
1681 CstNode::Container(CstContainerNode::Object(node)) => Some(node),
1682 _ => None,
1683 },
1684 None => {
1685 self.append(name, CstInputValue::Object(Vec::new()));
1686 self.object_value(name)
1687 }
1688 }
1689 }
1690
1691 pub fn object_value_or_set(&self, name: &str) -> CstObject {
1696 match self.get(name) {
1697 Some(prop) => match prop.value() {
1698 Some(CstNode::Container(CstContainerNode::Object(node))) => node,
1699 Some(node) => {
1700 let mut index = node.child_index();
1701 node.remove_raw();
1702 let container: CstContainerNode = prop.clone().into();
1703 let object = CstObject::new_with_tokens();
1704 container.raw_insert_child(Some(&mut index), object.clone().into());
1705 object
1706 }
1707 _ => {
1708 let mut index = prop.children().len();
1709 let container: CstContainerNode = prop.clone().into();
1710 let object = CstObject::new_with_tokens();
1711 container.raw_insert_child(Some(&mut index), object.clone().into());
1712 object
1713 }
1714 },
1715 None => {
1716 self.append(name, CstInputValue::Object(Vec::new()));
1717 self.object_value(name).unwrap()
1718 }
1719 }
1720 }
1721
1722 pub fn get(&self, name: &str) -> Option<CstObjectProp> {
1726 for child in &self.0.borrow().value {
1727 if let CstNode::Container(CstContainerNode::ObjectProp(prop)) = child {
1728 let Some(prop_name) = prop.name() else {
1729 continue;
1730 };
1731 let Ok(prop_name_str) = prop_name.decoded_value() else {
1732 continue;
1733 };
1734 if prop_name_str == name {
1735 return Some(prop.clone());
1736 }
1737 }
1738 }
1739 None
1740 }
1741
1742 pub fn properties(&self) -> Vec<CstObjectProp> {
1744 self
1745 .0
1746 .borrow()
1747 .value
1748 .iter()
1749 .filter_map(|child| match child {
1750 CstNode::Container(CstContainerNode::ObjectProp(prop)) => Some(prop.clone()),
1751 _ => None,
1752 })
1753 .collect()
1754 }
1755
1756 pub fn append(&self, prop_name: &str, value: CstInputValue) -> CstObjectProp {
1760 self.insert_or_append(None, prop_name, value)
1761 }
1762
1763 pub fn insert(&self, index: usize, prop_name: &str, value: CstInputValue) -> CstObjectProp {
1767 self.insert_or_append(Some(index), prop_name, value)
1768 }
1769
1770 fn insert_or_append(&self, index: Option<usize>, prop_name: &str, value: CstInputValue) -> CstObjectProp {
1771 self.ensure_multiline();
1772 insert_or_append_to_container(
1773 &CstContainerNode::Object(self.clone()),
1774 self.properties().into_iter().map(|c| c.into()).collect(),
1775 index,
1776 InsertValue::Property(prop_name, value),
1777 )
1778 .as_object_prop()
1779 .unwrap()
1780 }
1781
1782 pub fn replace_with(self, replacement: CstInputValue) -> Option<CstNode> {
1784 replace_with(self.into(), InsertValue::Value(replacement))
1785 }
1786
1787 pub fn set_trailing_commas(&self, mode: TrailingCommaMode) {
1789 set_trailing_commas(
1790 mode,
1791 &self.clone().into(),
1792 self.properties().into_iter().map(|c| c.into()),
1793 );
1794 }
1795
1796 pub fn ensure_multiline(&self) {
1798 ensure_multiline(&self.clone().into());
1799 }
1800
1801 pub fn remove(self) {
1803 remove_comma_separated(self.into())
1804 }
1805
1806 #[cfg(feature = "serde_json")]
1808 pub fn to_serde_value(&self) -> Option<serde_json::Value> {
1809 let mut map = serde_json::map::Map::new();
1810 for prop in self.properties() {
1811 if let (Some(name), Some(value)) = (prop.name_decoded(), prop.to_serde_value()) {
1812 map.insert(name, value);
1813 }
1814 }
1815 Some(serde_json::Value::Object(map))
1816 }
1817}
1818
1819impl Display for CstObject {
1820 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1821 for child in &self.0.borrow().value {
1822 write!(f, "{}", child)?;
1823 }
1824 Ok(())
1825 }
1826}
1827
1828type CstObjectPropInner = RefCell<CstChildrenInner>;
1829
1830#[derive(Debug, Clone)]
1832pub struct CstObjectProp(Rc<CstObjectPropInner>);
1833
1834impl_container_methods!(CstObjectProp, ObjectProp);
1835
1836impl CstObjectProp {
1837 add_root_node_method!();
1838
1839 fn new() -> Self {
1840 Self(CstValueInner::new(Vec::new()))
1841 }
1842
1843 pub fn name(&self) -> Option<ObjectPropName> {
1847 for child in &self.0.borrow().value {
1848 match child {
1849 CstNode::Leaf(CstLeafNode::StringLit(node)) => return Some(ObjectPropName::String(node.clone())),
1850 CstNode::Leaf(CstLeafNode::WordLit(node)) => return Some(ObjectPropName::Word(node.clone())),
1851 _ => {
1852 }
1854 }
1855 }
1856 None
1857 }
1858
1859 pub fn property_index(&self) -> usize {
1860 let child_index = self.child_index();
1861 let Some(parent) = self.parent().and_then(|p| p.as_object()) else {
1862 return 0;
1863 };
1864 parent
1865 .properties()
1866 .iter()
1867 .position(|p| p.child_index() == child_index)
1868 .unwrap_or(0)
1869 }
1870
1871 pub fn set_value(&self, replacement: CstInputValue) {
1872 let maybe_value = self.value();
1873 let mut value_index = maybe_value
1874 .as_ref()
1875 .map(|v| v.child_index())
1876 .unwrap_or_else(|| self.children().len());
1877 let container: CstContainerNode = self.clone().into();
1878 let indents = compute_indents(&container.clone().into());
1879 let style_info = &StyleInfo {
1880 newline_kind: container.root_node().map(|v| v.newline_kind()).unwrap_or_default(),
1881 uses_trailing_commas: uses_trailing_commas(maybe_value.unwrap_or_else(|| container.clone().into())),
1882 };
1883 self.remove_child_set_no_parent(value_index);
1884 container.raw_insert_value_with_internal_indent(
1885 Some(&mut value_index),
1886 InsertValue::Value(replacement),
1887 style_info,
1888 &indents,
1889 );
1890 }
1891
1892 pub fn value(&self) -> Option<CstNode> {
1896 let name = self.name()?;
1897 let parent_info = name.parent_info()?;
1898 let children = &self.0.borrow().value;
1899 let mut children = children[parent_info.child_index + 1..].iter();
1900
1901 for child in children.by_ref() {
1903 if let CstNode::Leaf(CstLeafNode::Token(token)) = child
1904 && token.value() == ':'
1905 {
1906 break;
1907 }
1908 }
1909
1910 for child in children {
1912 match child {
1913 CstNode::Leaf(leaf) => match leaf {
1914 CstLeafNode::BooleanLit(_)
1915 | CstLeafNode::NullKeyword(_)
1916 | CstLeafNode::NumberLit(_)
1917 | CstLeafNode::StringLit(_)
1918 | CstLeafNode::WordLit(_) => return Some(child.clone()),
1919 CstLeafNode::Token(_) | CstLeafNode::Whitespace(_) | CstLeafNode::Newline(_) | CstLeafNode::Comment(_) => {
1920 }
1922 },
1923 CstNode::Container(container) => match container {
1924 CstContainerNode::Object(_) | CstContainerNode::Array(_) => return Some(child.clone()),
1925 CstContainerNode::Root(_) | CstContainerNode::ObjectProp(_) => return None,
1926 },
1927 }
1928 }
1929
1930 None
1931 }
1932
1933 pub fn object_value(&self) -> Option<CstObject> {
1935 self.value()?.as_object()
1936 }
1937
1938 pub fn object_value_or_set(&self) -> CstObject {
1940 match self.value() {
1941 Some(CstNode::Container(CstContainerNode::Object(node))) => node,
1942 _ => {
1943 self.set_value(CstInputValue::Object(Vec::new()));
1944 self.object_value().unwrap()
1945 }
1946 }
1947 }
1948
1949 pub fn array_value(&self) -> Option<CstArray> {
1951 self.value()?.as_array()
1952 }
1953
1954 pub fn array_value_or_set(&self) -> CstArray {
1956 match self.value() {
1957 Some(CstNode::Container(CstContainerNode::Array(node))) => node,
1958 _ => {
1959 self.set_value(CstInputValue::Array(Vec::new()));
1960 self.array_value().unwrap()
1961 }
1962 }
1963 }
1964
1965 pub fn previous_property(&self) -> Option<CstObjectProp> {
1967 for sibling in self.previous_siblings() {
1968 if let CstNode::Container(CstContainerNode::ObjectProp(prop)) = sibling {
1969 return Some(prop);
1970 }
1971 }
1972 None
1973 }
1974
1975 pub fn next_property(&self) -> Option<CstObjectProp> {
1977 for sibling in self.next_siblings() {
1978 if let CstNode::Container(CstContainerNode::ObjectProp(prop)) = sibling {
1979 return Some(prop);
1980 }
1981 }
1982 None
1983 }
1984
1985 pub fn replace_with(self, key: &str, replacement: CstInputValue) -> Option<CstNode> {
1987 replace_with(self.into(), InsertValue::Property(key, replacement))
1988 }
1989
1990 pub fn remove(self) {
1992 remove_comma_separated(self.into())
1993 }
1994
1995 #[cfg(feature = "serde_json")]
1999 pub fn to_serde_value(&self) -> Option<serde_json::Value> {
2000 self.value()?.to_serde_value()
2001 }
2002
2003 #[cfg(feature = "serde_json")]
2004 fn name_decoded(&self) -> Option<String> {
2005 match self.name()? {
2006 ObjectPropName::String(s) => s.decoded_value().ok(),
2007 ObjectPropName::Word(w) => Some(w.0.borrow().value.clone()),
2008 }
2009 }
2010}
2011
2012impl Display for CstObjectProp {
2013 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2014 for child in &self.0.borrow().value {
2015 write!(f, "{}", child)?;
2016 }
2017 Ok(())
2018 }
2019}
2020
2021#[derive(Debug, Clone)]
2023pub enum ObjectPropName {
2024 String(CstStringLit),
2025 Word(CstWordLit),
2026}
2027
2028impl ObjectPropName {
2029 add_root_node_method!();
2030 add_parent_info_methods!();
2031
2032 pub fn as_string_lit(&self) -> Option<CstStringLit> {
2034 match self {
2035 ObjectPropName::String(n) => Some(n.clone()),
2036 ObjectPropName::Word(_) => None,
2037 }
2038 }
2039
2040 pub fn as_word_lit(&self) -> Option<CstWordLit> {
2042 match self {
2043 ObjectPropName::String(_) => None,
2044 ObjectPropName::Word(n) => Some(n.clone()),
2045 }
2046 }
2047
2048 pub fn decoded_value(&self) -> Result<String, ParseStringErrorKind> {
2050 match self {
2051 ObjectPropName::String(n) => n.decoded_value(),
2052 ObjectPropName::Word(n) => Ok(n.0.borrow().value.clone()),
2053 }
2054 }
2055
2056 fn parent_info(&self) -> Option<ParentInfo> {
2057 match self {
2058 ObjectPropName::String(n) => n.parent_info(),
2059 ObjectPropName::Word(n) => n.parent_info(),
2060 }
2061 }
2062}
2063
2064impl From<ObjectPropName> for CstNode {
2065 fn from(value: ObjectPropName) -> Self {
2066 match value {
2067 ObjectPropName::String(n) => n.into(),
2068 ObjectPropName::Word(n) => n.into(),
2069 }
2070 }
2071}
2072
2073type CstArrayInner = RefCell<CstChildrenInner>;
2074
2075#[derive(Debug, Clone)]
2077pub struct CstArray(Rc<CstArrayInner>);
2078
2079impl_container_methods!(CstArray, Array);
2080
2081impl CstArray {
2082 add_root_node_method!();
2083
2084 fn new_no_tokens() -> Self {
2085 Self(CstValueInner::new(Vec::new()))
2086 }
2087
2088 fn new_with_tokens() -> Self {
2089 let array = CstArray::new_no_tokens();
2090 let container: CstContainerNode = array.clone().into();
2091 container.raw_append_children(vec![CstToken::new('[').into(), CstToken::new(']').into()]);
2092 array
2093 }
2094
2095 pub fn elements(&self) -> Vec<CstNode> {
2097 self
2098 .0
2099 .borrow()
2100 .value
2101 .iter()
2102 .filter(|child| match child {
2103 CstNode::Container(_) => true,
2104 CstNode::Leaf(leaf) => match leaf {
2105 CstLeafNode::BooleanLit(_)
2106 | CstLeafNode::NullKeyword(_)
2107 | CstLeafNode::NumberLit(_)
2108 | CstLeafNode::StringLit(_)
2109 | CstLeafNode::WordLit(_) => true,
2110 CstLeafNode::Token(_) | CstLeafNode::Whitespace(_) | CstLeafNode::Newline(_) | CstLeafNode::Comment(_) => {
2111 false
2112 }
2113 },
2114 })
2115 .cloned()
2116 .collect()
2117 }
2118
2119 pub fn append(&self, value: CstInputValue) -> CstNode {
2123 self.insert_or_append(None, value)
2124 }
2125
2126 pub fn insert(&self, index: usize, value: CstInputValue) -> CstNode {
2130 self.insert_or_append(Some(index), value)
2131 }
2132
2133 pub fn ensure_multiline(&self) {
2135 ensure_multiline(&self.clone().into());
2136 }
2137
2138 pub fn set_trailing_commas(&self, mode: TrailingCommaMode) {
2140 set_trailing_commas(mode, &self.clone().into(), self.elements().into_iter());
2141 }
2142
2143 fn insert_or_append(&self, index: Option<usize>, value: CstInputValue) -> CstNode {
2144 insert_or_append_to_container(
2145 &CstContainerNode::Array(self.clone()),
2146 self.elements(),
2147 index,
2148 InsertValue::Value(value),
2149 )
2150 }
2151
2152 pub fn replace_with(self, replacement: CstInputValue) -> Option<CstNode> {
2154 replace_with(self.into(), InsertValue::Value(replacement))
2155 }
2156
2157 pub fn remove(self) {
2159 remove_comma_separated(self.into())
2160 }
2161
2162 #[cfg(feature = "serde_json")]
2164 pub fn to_serde_value(&self) -> Option<serde_json::Value> {
2165 let elements: Vec<serde_json::Value> = self
2166 .elements()
2167 .into_iter()
2168 .filter_map(|element| element.to_serde_value())
2169 .collect();
2170 Some(serde_json::Value::Array(elements))
2171 }
2172}
2173
2174impl Display for CstArray {
2175 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2176 for child in &self.0.borrow().value {
2177 write!(f, "{}", child)?;
2178 }
2179 Ok(())
2180 }
2181}
2182
2183#[derive(Debug, Clone)]
2185pub struct CstToken(Rc<RefCell<CstValueInner<char>>>);
2186
2187impl_leaf_methods!(CstToken, Token);
2188
2189impl CstToken {
2190 fn new(value: char) -> Self {
2191 Self(CstValueInner::new(value))
2192 }
2193
2194 pub fn set_value(&self, value: char) {
2196 self.0.borrow_mut().value = value;
2197 }
2198
2199 pub fn value(&self) -> char {
2201 self.0.borrow().value
2202 }
2203
2204 pub fn remove(self) {
2206 Into::<CstNode>::into(self).remove_raw()
2207 }
2208}
2209
2210impl Display for CstToken {
2211 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2212 write!(f, "{}", self.0.borrow().value)
2213 }
2214}
2215
2216#[derive(Debug, Clone)]
2218pub struct CstWhitespace(Rc<RefCell<CstValueInner<String>>>);
2219
2220impl_leaf_methods!(CstWhitespace, Whitespace);
2221
2222impl CstWhitespace {
2223 fn new(value: String) -> Self {
2224 Self(CstValueInner::new(value))
2225 }
2226
2227 pub fn set_value(&self, value: String) {
2229 self.0.borrow_mut().value = value;
2230 }
2231
2232 pub fn value(&self) -> String {
2234 self.0.borrow().value.clone()
2235 }
2236
2237 pub fn remove(self) {
2239 Into::<CstNode>::into(self).remove_raw()
2240 }
2241}
2242
2243impl Display for CstWhitespace {
2244 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2245 write!(f, "{}", self.0.borrow().value)
2246 }
2247}
2248
2249#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
2251pub enum CstNewlineKind {
2252 #[default]
2253 LineFeed,
2254 CarriageReturnLineFeed,
2255}
2256
2257#[derive(Debug, Clone)]
2259pub struct CstNewline(Rc<RefCell<CstValueInner<CstNewlineKind>>>);
2260
2261impl_leaf_methods!(CstNewline, Newline);
2262
2263impl CstNewline {
2264 fn new(kind: CstNewlineKind) -> Self {
2265 Self(CstValueInner::new(kind))
2266 }
2267
2268 pub fn kind(&self) -> CstNewlineKind {
2270 self.0.borrow().value
2271 }
2272
2273 pub fn set_kind(&self, kind: CstNewlineKind) {
2275 self.0.borrow_mut().value = kind;
2276 }
2277
2278 pub fn remove(self) {
2280 Into::<CstNode>::into(self).remove_raw()
2281 }
2282}
2283
2284impl Display for CstNewline {
2285 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2286 match self.0.borrow().value {
2287 #[allow(clippy::write_with_newline)] CstNewlineKind::LineFeed => write!(f, "\n"),
2289 CstNewlineKind::CarriageReturnLineFeed => write!(f, "\r\n"),
2290 }
2291 }
2292}
2293
2294#[derive(Debug, Clone)]
2295pub struct CstComment(Rc<RefCell<CstValueInner<String>>>);
2296
2297impl_leaf_methods!(CstComment, Comment);
2298
2299impl CstComment {
2300 fn new(value: String) -> Self {
2301 Self(CstValueInner::new(value))
2302 }
2303
2304 pub fn is_line_comment(&self) -> bool {
2306 self.0.borrow().value.starts_with("//")
2307 }
2308
2309 pub fn set_raw_value(&self, value: String) {
2314 self.0.borrow_mut().value = value;
2315 }
2316
2317 pub fn raw_value(&self) -> String {
2319 self.0.borrow().value.clone()
2320 }
2321
2322 pub fn remove(self) {
2324 if self.is_line_comment() {
2325 for node in self.previous_siblings() {
2326 if node.is_whitespace() {
2327 node.remove_raw();
2328 } else {
2329 if node.is_newline() {
2330 node.remove_raw();
2331 }
2332 break;
2333 }
2334 }
2335 }
2336
2337 Into::<CstNode>::into(self).remove_raw()
2338 }
2339}
2340
2341impl Display for CstComment {
2342 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2343 write!(f, "{}", self.0.borrow().value)
2344 }
2345}
2346
2347struct CstBuilder<'a> {
2348 pub text: &'a str,
2349 pub tokens: VecDeque<crate::tokens::TokenAndRange<'a>>,
2350}
2351
2352impl<'a> CstBuilder<'a> {
2353 pub fn build(&mut self, ast_value: Option<crate::ast::Value<'a>>) -> CstRootNode {
2354 let root_node = CstContainerNode::Root(CstRootNode(Rc::new(RefCell::new(CstChildrenInner {
2355 parent: None,
2356 value: Vec::new(),
2357 }))));
2358
2359 if let Some(ast_value) = ast_value {
2360 let range = ast_value.range();
2361 self.scan_from_to(&root_node, 0, range.start);
2362 self.build_value(&root_node, ast_value);
2363 self.scan_from_to(&root_node, range.end, self.text.len());
2364 } else {
2365 self.scan_from_to(&root_node, 0, self.text.len());
2366 }
2367
2368 match root_node {
2369 CstContainerNode::Root(node) => node,
2370 _ => unreachable!(),
2371 }
2372 }
2373
2374 fn scan_from_to(&mut self, container: &CstContainerNode, from: usize, to: usize) {
2375 if from == to {
2376 return;
2377 }
2378
2379 let mut last_from = from;
2380 while let Some(token) = self.tokens.front() {
2381 if token.range.end <= from {
2382 self.tokens.pop_front();
2383 } else if token.range.start < to {
2384 if token.range.start > last_from {
2385 self.build_whitespace(container, &self.text[last_from..token.range.start]);
2386 }
2387 let token = self.tokens.pop_front().unwrap();
2388 match token.token {
2389 crate::tokens::Token::OpenBrace
2390 | crate::tokens::Token::CloseBrace
2391 | crate::tokens::Token::OpenBracket
2392 | crate::tokens::Token::CloseBracket
2393 | crate::tokens::Token::Comma
2394 | crate::tokens::Token::Colon => {
2395 self.build_token(container, token.token.as_str().chars().next().unwrap());
2396 }
2397 crate::tokens::Token::Null
2398 | crate::tokens::Token::String(_)
2399 | crate::tokens::Token::Word(_)
2400 | crate::tokens::Token::Boolean(_)
2401 | crate::tokens::Token::Number(_) => unreachable!(
2402 "programming error parsing cst {:?} scanning {} to {}",
2403 token.token, from, to
2404 ),
2405 crate::tokens::Token::CommentLine(_) | crate::tokens::Token::CommentBlock(_) => {
2406 container
2407 .raw_append_child(CstComment::new(self.text[token.range.start..token.range.end].to_string()).into());
2408 }
2409 }
2410 last_from = token.range.end;
2411 } else {
2412 break;
2413 }
2414 }
2415
2416 if last_from < to {
2417 self.build_whitespace(container, &self.text[last_from..to]);
2418 }
2419 }
2420
2421 fn build_value(&mut self, container: &CstContainerNode, ast_value: ast::Value<'_>) {
2422 match ast_value {
2423 ast::Value::StringLit(string_lit) => self.build_string_lit(container, string_lit),
2424 ast::Value::NumberLit(number_lit) => {
2425 container.raw_append_child(CstNumberLit::new(number_lit.value.to_string()).into())
2426 }
2427 ast::Value::BooleanLit(boolean_lit) => container.raw_append_child(CstBooleanLit::new(boolean_lit.value).into()),
2428 ast::Value::Object(object) => {
2429 let object = self.build_object(object);
2430 container.raw_append_child(object.into())
2431 }
2432 ast::Value::Array(array) => {
2433 let array = self.build_array(array);
2434 container.raw_append_child(array.into())
2435 }
2436 ast::Value::NullKeyword(_) => container.raw_append_child(CstNullKeyword::new().into()),
2437 }
2438 }
2439
2440 fn build_object(&mut self, object: ast::Object<'_>) -> CstContainerNode {
2441 let container = CstContainerNode::Object(CstObject::new_no_tokens());
2442 let mut last_range_end = object.range.start;
2443 for prop in object.properties {
2444 self.scan_from_to(&container, last_range_end, prop.range.start);
2445 last_range_end = prop.range.end;
2446 let object_prop = self.build_object_prop(prop);
2447 container.raw_append_child(CstNode::Container(object_prop));
2448 }
2449 self.scan_from_to(&container, last_range_end, object.range.end);
2450
2451 container
2452 }
2453
2454 fn build_object_prop(&mut self, prop: ast::ObjectProp<'_>) -> CstContainerNode {
2455 let container = CstContainerNode::ObjectProp(CstObjectProp::new());
2456 let name_range = prop.name.range();
2457 let value_range = prop.value.range();
2458
2459 match prop.name {
2460 ast::ObjectPropName::String(string_lit) => {
2461 self.build_string_lit(&container, string_lit);
2462 }
2463 ast::ObjectPropName::Word(word_lit) => {
2464 container.raw_append_child(CstWordLit::new(word_lit.value.to_string()).into());
2465 }
2466 }
2467
2468 self.scan_from_to(&container, name_range.end, value_range.start);
2469 self.build_value(&container, prop.value);
2470
2471 container
2472 }
2473
2474 fn build_token(&self, container: &CstContainerNode, value: char) {
2475 container.raw_append_child(CstToken::new(value).into());
2476 }
2477
2478 fn build_whitespace(&self, container: &CstContainerNode, value: &str) {
2479 if value.is_empty() {
2480 return;
2481 }
2482
2483 let mut last_found_index = 0;
2484 let mut chars = value.char_indices().peekable();
2485 let maybe_add_previous_text = |from: usize, to: usize| {
2486 let text = &value[from..to];
2487 if !text.is_empty() {
2488 container.raw_append_child(CstWhitespace::new(text.to_string()).into());
2489 }
2490 };
2491 while let Some((i, c)) = chars.next() {
2492 if c == '\r' && chars.peek().map(|(_, c)| *c) == Some('\n') {
2493 maybe_add_previous_text(last_found_index, i);
2494 container.raw_append_child(CstNewline::new(CstNewlineKind::CarriageReturnLineFeed).into());
2495 last_found_index = i + 2;
2496 chars.next(); } else if c == '\n' {
2498 maybe_add_previous_text(last_found_index, i);
2499 container.raw_append_child(CstNewline::new(CstNewlineKind::LineFeed).into());
2500 last_found_index = i + 1;
2501 }
2502 }
2503
2504 maybe_add_previous_text(last_found_index, value.len());
2505 }
2506
2507 fn build_string_lit(&self, container: &CstContainerNode, lit: ast::StringLit<'_>) {
2508 container.raw_append_child(CstStringLit::new(self.text[lit.range.start..lit.range.end].to_string()).into());
2509 }
2510
2511 fn build_array(&mut self, array: ast::Array<'_>) -> CstContainerNode {
2512 let container = CstContainerNode::Array(CstArray::new_no_tokens());
2513 let mut last_range_end = array.range.start;
2514 for element in array.elements {
2515 let element_range = element.range();
2516 self.scan_from_to(&container, last_range_end, element_range.start);
2517 self.build_value(&container, element);
2518 last_range_end = element_range.end;
2519 }
2520 self.scan_from_to(&container, last_range_end, array.range.end);
2521
2522 container
2523 }
2524}
2525
2526fn remove_comma_separated(node: CstNode) {
2527 fn check_next_node_same_line(trailing_comma: &CstToken) -> bool {
2528 for sibling in trailing_comma.next_siblings() {
2529 match sibling {
2530 CstNode::Container(_) => return true,
2531 CstNode::Leaf(n) => match n {
2532 CstLeafNode::BooleanLit(_)
2533 | CstLeafNode::NullKeyword(_)
2534 | CstLeafNode::NumberLit(_)
2535 | CstLeafNode::StringLit(_)
2536 | CstLeafNode::WordLit(_)
2537 | CstLeafNode::Token(_) => return true,
2538 CstLeafNode::Whitespace(_) | CstLeafNode::Comment(_) => {
2539 }
2541 CstLeafNode::Newline(_) => return false,
2542 },
2543 }
2544 }
2545
2546 true
2547 }
2548
2549 let parent = node.parent();
2550 let trailing_comma = node.trailing_comma();
2551 let is_in_array_or_obj = parent
2552 .as_ref()
2553 .map(|p| matches!(p, CstContainerNode::Array(_) | CstContainerNode::Object(_)))
2554 .unwrap_or(false);
2555 let remove_up_to_next_line = trailing_comma
2556 .as_ref()
2557 .map(|c| !check_next_node_same_line(c))
2558 .unwrap_or(true);
2559
2560 for previous in node.previous_siblings() {
2561 if previous.is_trivia() && !previous.is_newline() {
2562 previous.remove_raw();
2563 } else {
2564 break;
2565 }
2566 }
2567
2568 let mut found_newline = false;
2569
2570 if trailing_comma.is_some() {
2572 let mut next_siblings = node.next_siblings();
2573 for next in next_siblings.by_ref() {
2574 let is_comma = next.is_comma();
2575 if next.is_newline() {
2576 found_newline = true;
2577 }
2578 next.remove_raw();
2579 if is_comma {
2580 break;
2581 }
2582 }
2583 } else if is_in_array_or_obj && let Some(previous_comma) = node.previous_siblings().find(|n| n.is_comma()) {
2584 previous_comma.remove();
2585 }
2586
2587 if remove_up_to_next_line && !found_newline {
2589 let mut next_siblings = node.next_siblings().peekable();
2590 while let Some(sibling) = next_siblings.next() {
2591 if sibling.is_trivia() {
2592 if sibling.is_newline() {
2593 sibling.remove_raw();
2594 break;
2595 } else if sibling.is_whitespace()
2596 && next_siblings
2597 .peek()
2598 .map(|n| !n.is_whitespace() && !n.is_newline() && !n.is_comment())
2599 .unwrap_or(false)
2600 {
2601 break;
2602 }
2603 sibling.remove_raw();
2604 } else {
2605 break;
2606 }
2607 }
2608 }
2609
2610 node.remove_raw();
2611
2612 if let Some(parent) = parent {
2613 match parent {
2614 CstContainerNode::Root(n) => {
2615 if n.children().iter().all(|c| c.is_whitespace() || c.is_newline()) {
2616 n.clear_children();
2617 }
2618 }
2619 CstContainerNode::Object(_) | CstContainerNode::Array(_) => {
2620 let children = parent.children();
2621 if children
2622 .iter()
2623 .skip(1)
2624 .take(children.len() - 2)
2625 .all(|c| c.is_whitespace() || c.is_newline())
2626 {
2627 for c in children {
2628 if c.is_whitespace() || c.is_newline() {
2629 c.remove();
2630 }
2631 }
2632 }
2633 }
2634 CstContainerNode::ObjectProp(_) => {}
2635 }
2636 }
2637}
2638
2639fn indent_text(node: &CstNode) -> Option<String> {
2640 let mut last_whitespace: Option<String> = None;
2641 for previous_sibling in node.previous_siblings() {
2642 match previous_sibling {
2643 CstNode::Container(_) => return None,
2644 CstNode::Leaf(leaf) => match leaf {
2645 CstLeafNode::Newline(_) => {
2646 return last_whitespace;
2647 }
2648 CstLeafNode::Whitespace(whitespace) => {
2649 last_whitespace = match last_whitespace {
2650 Some(last_whitespace) => Some(format!("{}{}", whitespace.value(), last_whitespace)),
2651 None => Some(whitespace.value()),
2652 };
2653 }
2654 CstLeafNode::Comment(_) => {
2655 last_whitespace = None;
2656 }
2657 _ => return None,
2658 },
2659 }
2660 }
2661 last_whitespace
2662}
2663
2664fn uses_trailing_commas(node: CstNode) -> bool {
2665 let node = match node {
2666 CstNode::Container(node) => node,
2667 CstNode::Leaf(_) => return false,
2668 };
2669 let mut pending_nodes: VecDeque<CstContainerNode> = VecDeque::from([node.clone()]);
2670 while let Some(node) = pending_nodes.pop_front() {
2671 let children = node.children();
2672 if !node.is_root() {
2673 if let Some(object) = node.as_object() {
2674 if children.iter().any(|c| c.is_whitespace()) {
2675 let properties = object.properties();
2676 if let Some(last_property) = properties.last() {
2677 return last_property.trailing_comma().is_some();
2678 }
2679 }
2680 } else if let Some(object) = node.as_array()
2681 && children.iter().any(|c| c.is_whitespace())
2682 {
2683 let elements = object.elements();
2684 if let Some(last_property) = elements.last() {
2685 return last_property.trailing_comma().is_some();
2686 }
2687 }
2688 }
2689
2690 for child in children {
2691 if let CstNode::Container(child) = child {
2692 pending_nodes.push_back(child);
2693 }
2694 }
2695 }
2696
2697 false }
2699
2700fn replace_with(node: CstNode, replacement: InsertValue) -> Option<CstNode> {
2701 let mut child_index = node.child_index();
2702 let parent = node.parent()?;
2703 let indents = compute_indents(&parent.clone().into());
2704 let style_info = StyleInfo {
2705 newline_kind: parent.root_node().map(|r| r.newline_kind()).unwrap_or_default(),
2706 uses_trailing_commas: uses_trailing_commas(parent.clone().into()),
2707 };
2708 parent.remove_child_set_no_parent(child_index);
2709 parent.raw_insert_value_with_internal_indent(Some(&mut child_index), replacement, &style_info, &indents);
2710 parent.child_at_index(child_index - 1)
2711}
2712
2713enum InsertValue<'a> {
2714 Value(CstInputValue),
2715 Property(&'a str, CstInputValue),
2716}
2717
2718fn insert_or_append_to_container(
2719 container: &CstContainerNode,
2720 elements: Vec<CstNode>,
2721 index: Option<usize>,
2722 value: InsertValue,
2723) -> CstNode {
2724 fn has_separating_newline(siblings: impl Iterator<Item = CstNode>) -> bool {
2725 for sibling in siblings {
2726 if sibling.is_newline() {
2727 return true;
2728 } else if sibling.is_trivia() {
2729 continue;
2730 } else {
2731 break;
2732 }
2733 }
2734 false
2735 }
2736
2737 trim_inner_start_and_end_blanklines(container);
2738
2739 let children = container.children();
2740 let index = index.unwrap_or(elements.len());
2741 let index = std::cmp::min(index, elements.len());
2742 let next_node = elements.get(index);
2743 let previous_node = if index == 0 { None } else { elements.get(index - 1) };
2744 let style_info = StyleInfo {
2745 newline_kind: container.root_node().map(|r| r.newline_kind()).unwrap_or_default(),
2746 uses_trailing_commas: uses_trailing_commas(container.clone().into()),
2747 };
2748 let indents = compute_indents(&container.clone().into());
2749 let child_indents = elements
2750 .first()
2751 .map(compute_indents)
2752 .unwrap_or_else(|| indents.indent());
2753 let has_newline = children.iter().any(|child| child.is_newline());
2754 let force_multiline = has_newline
2755 || match &value {
2756 InsertValue::Value(v) => v.force_multiline(),
2757 InsertValue::Property(..) => true,
2758 };
2759 let mut insert_index: usize;
2760 let inserted_node: CstNode;
2761 if let Some(previous_node) = previous_node {
2762 if previous_node.trailing_comma().is_none() {
2763 let mut index = previous_node.child_index() + 1;
2764 container.raw_insert_child(Some(&mut index), CstToken::new(',').into());
2765 }
2766
2767 let trailing_comma: CstNode = previous_node.trailing_comma().unwrap().into();
2768 insert_index = trailing_comma
2769 .trailing_comments_same_line()
2770 .last()
2771 .map(|t| t.child_index())
2772 .unwrap_or_else(|| trailing_comma.child_index())
2773 + 1;
2774 if force_multiline {
2775 container.raw_insert_children(
2776 Some(&mut insert_index),
2777 vec![
2778 CstNewline::new(style_info.newline_kind).into(),
2779 CstStringLit::new(child_indents.current_indent.clone()).into(),
2780 ],
2781 );
2782 container.raw_insert_value_with_internal_indent(Some(&mut insert_index), value, &style_info, &child_indents);
2783 inserted_node = container.child_at_index(insert_index - 1).unwrap();
2784 } else {
2785 container.raw_insert_child(Some(&mut insert_index), CstWhitespace::new(" ".to_string()).into());
2786 container.raw_insert_value_with_internal_indent(Some(&mut insert_index), value, &style_info, &child_indents);
2787 inserted_node = container.child_at_index(insert_index - 1).unwrap();
2788 }
2789 } else {
2790 insert_index = if elements.is_empty() {
2791 children
2792 .iter()
2793 .rev()
2794 .skip(1)
2795 .take_while(|t| t.is_whitespace() || t.is_newline())
2796 .last()
2797 .unwrap_or_else(|| children.last().unwrap())
2798 .child_index()
2799 } else {
2800 children.first().unwrap().child_index() + 1
2801 };
2802 if force_multiline {
2803 container.raw_insert_children(
2804 Some(&mut insert_index),
2805 vec![
2806 CstNewline::new(style_info.newline_kind).into(),
2807 CstStringLit::new(child_indents.current_indent.clone()).into(),
2808 ],
2809 );
2810 container.raw_insert_value_with_internal_indent(Some(&mut insert_index), value, &style_info, &child_indents);
2811 inserted_node = container.child_at_index(insert_index - 1).unwrap();
2812 if next_node.is_none()
2813 && !has_separating_newline(container.child_at_index(insert_index - 1).unwrap().next_siblings())
2814 {
2815 container.raw_insert_children(
2816 Some(&mut insert_index),
2817 vec![
2818 CstNewline::new(style_info.newline_kind).into(),
2819 CstStringLit::new(indents.current_indent.clone()).into(),
2820 ],
2821 );
2822 }
2823 } else {
2824 container.raw_insert_value_with_internal_indent(Some(&mut insert_index), value, &style_info, &child_indents);
2825 inserted_node = container.child_at_index(insert_index - 1).unwrap();
2826 }
2827 }
2828
2829 if next_node.is_some() {
2830 container.raw_insert_children(Some(&mut insert_index), vec![CstToken::new(',').into()]);
2831
2832 if force_multiline {
2833 let comma_token = container.child_at_index(insert_index - 1).unwrap();
2834 if !has_separating_newline(comma_token.next_siblings()) {
2835 container.raw_insert_children(
2836 Some(&mut insert_index),
2837 vec![
2838 CstNewline::new(style_info.newline_kind).into(),
2839 CstStringLit::new(indents.current_indent.clone()).into(),
2840 ],
2841 );
2842 }
2843 } else {
2844 container.raw_insert_child(Some(&mut insert_index), CstWhitespace::new(" ".to_string()).into());
2845 }
2846 } else if style_info.uses_trailing_commas && force_multiline {
2847 container.raw_insert_children(Some(&mut insert_index), vec![CstToken::new(',').into()]);
2848 }
2849
2850 inserted_node
2851}
2852
2853fn set_trailing_commas(
2854 mode: TrailingCommaMode,
2855 parent: &CstContainerNode,
2856 elems_or_props: impl Iterator<Item = CstNode>,
2857) {
2858 let mut elems_or_props = elems_or_props.peekable();
2859 let use_trailing_commas = match mode {
2860 TrailingCommaMode::Never => false,
2861 TrailingCommaMode::IfMultiline => true,
2862 };
2863 while let Some(element) = elems_or_props.next() {
2864 if elems_or_props.peek().is_none() {
2866 if use_trailing_commas {
2867 if element.trailing_comma().is_none() && parent.children().iter().any(|c| c.is_newline()) {
2868 let mut insert_index = element.child_index() + 1;
2869 parent.raw_insert_child(Some(&mut insert_index), CstToken::new(',').into());
2870 }
2871 } else if let Some(trailing_comma) = element.trailing_comma() {
2872 trailing_comma.remove();
2873 }
2874 }
2875
2876 let maybe_prop_value = element.as_object_prop().and_then(|p| p.value());
2878 match maybe_prop_value.unwrap_or(element) {
2879 CstNode::Container(CstContainerNode::Array(array)) => {
2880 array.set_trailing_commas(mode);
2881 }
2882 CstNode::Container(CstContainerNode::Object(object)) => {
2883 object.set_trailing_commas(mode);
2884 }
2885 _ => {}
2886 }
2887 }
2888}
2889
2890fn trim_inner_start_and_end_blanklines(node: &CstContainerNode) {
2891 fn remove_blank_lines_after_first(children: &mut Peekable<impl Iterator<Item = CstNode>>) {
2892 for child in children.by_ref() {
2894 if child.is_whitespace() {
2895 } else if child.is_newline() {
2897 break; } else {
2899 return; }
2901 }
2902
2903 let mut pending = Vec::new();
2904 for child in children.by_ref() {
2905 if child.is_whitespace() {
2906 pending.push(child);
2907 } else if child.is_newline() {
2908 child.remove();
2909 for child in pending.drain(..) {
2910 child.remove();
2911 }
2912 } else {
2913 break;
2914 }
2915 }
2916 }
2917
2918 let children = node.children();
2919 let len = children.len();
2920
2921 if len < 2 {
2922 return; }
2924
2925 let mut children = children.into_iter().skip(1).take(len - 2).peekable();
2927 remove_blank_lines_after_first(&mut children);
2928 let mut children = children.rev().peekable();
2929 remove_blank_lines_after_first(&mut children);
2930}
2931
2932fn ensure_multiline(container: &CstContainerNode) {
2933 let children = container.children();
2934 if children.iter().any(|c| c.is_newline()) {
2935 return;
2936 }
2937
2938 let indents = compute_indents(&container.clone().into());
2939 let child_indents = indents.indent();
2940 let newline_kind = container
2941 .root_node()
2942 .map(|r| r.newline_kind())
2943 .unwrap_or(CstNewlineKind::LineFeed);
2944
2945 let children_len = children.len();
2947 let mut children = children.into_iter().skip(1).peekable().take(children_len - 2);
2948 let mut index = 1;
2949 while let Some(child) = children.next() {
2950 if child.is_whitespace() {
2951 child.remove();
2952 continue;
2953 } else {
2954 container.raw_insert_child(Some(&mut index), CstNewline::new(newline_kind).into());
2956 container.raw_insert_child(
2957 Some(&mut index),
2958 CstWhitespace::new(child_indents.current_indent.clone()).into(),
2959 );
2960
2961 index += 1;
2963
2964 let mut trailing_whitespace = Vec::new();
2966 for next_child in children.by_ref() {
2967 if next_child.is_whitespace() {
2968 trailing_whitespace.push(next_child);
2969 } else {
2970 index += 1 + trailing_whitespace.len();
2971 trailing_whitespace.clear();
2972 if next_child.token_char() == Some(',') {
2973 break;
2974 }
2975 }
2976 }
2977
2978 for trailing_whitespace in trailing_whitespace {
2979 trailing_whitespace.remove();
2980 }
2981 }
2982 }
2983
2984 container.raw_insert_child(Some(&mut index), CstNewline::new(newline_kind).into());
2986 if !indents.current_indent.is_empty() {
2987 container.raw_insert_child(Some(&mut index), CstWhitespace::new(indents.current_indent).into());
2988 }
2989}
2990
2991#[derive(Debug)]
2992struct Indents {
2993 current_indent: String,
2994 single_indent: String,
2995}
2996
2997impl Indents {
2998 pub fn indent(&self) -> Indents {
2999 Indents {
3000 current_indent: format!("{}{}", self.current_indent, self.single_indent),
3001 single_indent: self.single_indent.clone(),
3002 }
3003 }
3004}
3005
3006fn compute_indents(node: &CstNode) -> Indents {
3007 let mut indent_level = 0;
3008 let mut stored_last_indent = node.indent_text();
3009 let mut ancestors = node.ancestors().peekable();
3010
3011 while ancestors.peek().and_then(|p| p.as_object_prop()).is_some() {
3012 ancestors.next();
3013 }
3014
3015 while let Some(ancestor) = ancestors.next() {
3016 if ancestor.is_root() {
3017 break;
3018 }
3019
3020 if ancestors.peek().and_then(|p| p.as_object_prop()).is_some() {
3021 continue;
3022 }
3023
3024 indent_level += 1;
3025
3026 if let Some(indent_text) = ancestor.indent_text() {
3027 match stored_last_indent {
3028 Some(last_indent) => {
3029 if let Some(single_indent_text) = last_indent.strip_prefix(&indent_text) {
3030 return Indents {
3031 current_indent: format!("{}{}", last_indent, single_indent_text.repeat(indent_level - 1)),
3032 single_indent: single_indent_text.to_string(),
3033 };
3034 }
3035 stored_last_indent = None;
3036 }
3037 None => {
3038 stored_last_indent = Some(indent_text);
3039 }
3040 }
3041 } else {
3042 stored_last_indent = None;
3043 }
3044 }
3045
3046 if indent_level == 1
3047 && let Some(indent_text) = node.indent_text()
3048 {
3049 return Indents {
3050 current_indent: indent_text.clone(),
3051 single_indent: indent_text,
3052 };
3053 }
3054
3055 if let Some(root_value) = node.root_node().and_then(|r| r.value()) {
3057 for child in root_value.children() {
3058 if let Some(single_indent) = child.indent_text() {
3059 return Indents {
3060 current_indent: single_indent.repeat(indent_level),
3061 single_indent,
3062 };
3063 }
3064 }
3065 }
3066
3067 let single_indent = " ";
3069 Indents {
3070 current_indent: single_indent.repeat(indent_level),
3071 single_indent: single_indent.to_string(),
3072 }
3073}
3074
3075struct AncestorIterator {
3076 next: Option<CstContainerNode>,
3079}
3080
3081impl AncestorIterator {
3082 pub fn new(node: CstNode) -> Self {
3083 Self {
3084 next: node.parent_info().map(|i| i.parent.as_container_node()),
3085 }
3086 }
3087}
3088
3089impl Iterator for AncestorIterator {
3090 type Item = CstContainerNode;
3091
3092 fn next(&mut self) -> Option<Self::Item> {
3093 let next = self.next.take()?;
3094 self.next = next.parent_info().map(|i| i.parent.as_container_node());
3095 Some(next)
3096 }
3097}
3098
3099struct NextSiblingIterator {
3100 next: Option<CstNode>,
3103}
3104
3105impl NextSiblingIterator {
3106 pub fn new(node: CstNode) -> Self {
3107 Self {
3108 next: node.next_sibling(),
3109 }
3110 }
3111}
3112
3113impl Iterator for NextSiblingIterator {
3114 type Item = CstNode;
3115
3116 fn next(&mut self) -> Option<Self::Item> {
3117 let next_sibling = self.next.take()?;
3118 self.next = next_sibling.next_sibling();
3119 Some(next_sibling)
3120 }
3121}
3122
3123struct PreviousSiblingIterator {
3124 previous: Option<CstNode>,
3127}
3128
3129impl PreviousSiblingIterator {
3130 pub fn new(node: CstNode) -> Self {
3131 Self {
3132 previous: node.previous_sibling(),
3133 }
3134 }
3135}
3136
3137impl Iterator for PreviousSiblingIterator {
3138 type Item = CstNode;
3139
3140 fn next(&mut self) -> Option<Self::Item> {
3141 let previous_sibling = self.previous.take()?;
3142 self.previous = previous_sibling.previous_sibling();
3143 Some(previous_sibling)
3144 }
3145}
3146
3147#[cfg(test)]
3148mod test {
3149 use pretty_assertions::assert_eq;
3150
3151 use crate::cst::CstInputValue;
3152 use crate::cst::TrailingCommaMode;
3153 use crate::json;
3154
3155 use super::CstRootNode;
3156
3157 #[test]
3158 fn single_indent_text() {
3159 let cases = [
3160 (
3161 " ",
3162 r#"
3163{
3164 "prop": {
3165 "nested": 4
3166 }
3167}
3168 "#,
3169 ),
3170 (
3171 " ",
3172 r#"
3173{
3174 /* test */ "prop": {}
3175}
3176 "#,
3177 ),
3178 (
3179 " ",
3180 r#"
3181{
3182 /* test */ "prop": {}
3183}
3184 "#,
3185 ),
3186 (
3187 "\t",
3188 "
3189{
3190\t/* test */ \"prop\": {}
3191}
3192 ",
3193 ),
3194 ];
3195 for (expected, text) in cases {
3196 let root = build_cst(text);
3197 assert_eq!(root.single_indent_text(), Some(expected.to_string()), "Text: {}", text);
3198 }
3199 }
3200
3201 #[test]
3202 fn modify_values() {
3203 let cst = build_cst(
3204 r#"{
3205 "value": 5,
3206 // comment
3207 "value2": "hello",
3208 value3: true
3209}"#,
3210 );
3211
3212 let root_value = cst.value().unwrap();
3213 let root_obj = root_value.as_object().unwrap();
3214 {
3215 let prop = root_obj.get("value").unwrap();
3216 prop
3217 .value()
3218 .unwrap()
3219 .as_number_lit()
3220 .unwrap()
3221 .set_raw_value("10".to_string());
3222 assert!(prop.trailing_comma().is_some());
3223 assert!(prop.previous_property().is_none());
3224 assert_eq!(
3225 prop.next_property().unwrap().name().unwrap().decoded_value().unwrap(),
3226 "value2"
3227 );
3228 assert_eq!(prop.indent_text().unwrap(), " ");
3229 }
3230 {
3231 let prop = root_obj.get("value2").unwrap();
3232 prop
3233 .value()
3234 .unwrap()
3235 .as_string_lit()
3236 .unwrap()
3237 .set_raw_value("\"5\"".to_string());
3238 assert!(prop.trailing_comma().is_some());
3239 assert_eq!(
3240 prop
3241 .previous_property()
3242 .unwrap()
3243 .name()
3244 .unwrap()
3245 .decoded_value()
3246 .unwrap(),
3247 "value"
3248 );
3249 assert_eq!(
3250 prop.next_property().unwrap().name().unwrap().decoded_value().unwrap(),
3251 "value3"
3252 );
3253 }
3254 {
3255 let prop = root_obj.get("value3").unwrap();
3256 prop.value().unwrap().as_boolean_lit().unwrap().set_value(false);
3257 prop
3258 .name()
3259 .unwrap()
3260 .as_word_lit()
3261 .unwrap()
3262 .set_raw_value("value4".to_string());
3263 assert!(prop.trailing_comma().is_none());
3264 assert_eq!(
3265 prop
3266 .previous_property()
3267 .unwrap()
3268 .name()
3269 .unwrap()
3270 .decoded_value()
3271 .unwrap(),
3272 "value2"
3273 );
3274 assert!(prop.next_property().is_none());
3275 }
3276
3277 assert_eq!(
3278 cst.to_string(),
3279 r#"{
3280 "value": 10,
3281 // comment
3282 "value2": "5",
3283 value4: false
3284}"#
3285 );
3286 }
3287
3288 #[test]
3289 fn remove_properties() {
3290 fn run_test(prop_name: &str, json: &str, expected: &str) {
3291 let cst = build_cst(json);
3292 let root_value = cst.value().unwrap();
3293 let root_obj = root_value.as_object().unwrap();
3294 let prop = root_obj.get(prop_name).unwrap();
3295 prop.remove();
3296 assert_eq!(cst.to_string(), expected);
3297 }
3298
3299 run_test(
3300 "value2",
3301 r#"{
3302 "value": 5,
3303 // comment
3304 "value2": "hello",
3305 value3: true
3306}"#,
3307 r#"{
3308 "value": 5,
3309 // comment
3310 value3: true
3311}"#,
3312 );
3313
3314 run_test(
3315 "value2",
3316 r#"{
3317 "value": 5,
3318 // comment
3319 "value2": "hello"
3320 ,value3: true
3321}"#,
3322 r#"{
3324 "value": 5,
3325 // comment
3326value3: true
3327}"#,
3328 );
3329
3330 run_test("value", r#"{ "value": 5 }"#, r#"{}"#);
3331 run_test("value", r#"{ "value": 5, "value2": 6 }"#, r#"{ "value2": 6 }"#);
3332 run_test("value2", r#"{ "value": 5, "value2": 6 }"#, r#"{ "value": 5 }"#);
3333 }
3334
3335 #[test]
3336 fn insert_properties() {
3337 fn run_test(index: usize, prop_name: &str, value: CstInputValue, json: &str, expected: &str) {
3338 let cst = build_cst(json);
3339 let root_value = cst.value().unwrap();
3340 let root_obj = root_value.as_object().unwrap();
3341 root_obj.insert(index, prop_name, value);
3342 assert_eq!(cst.to_string(), expected, "Initial text: {}", json);
3343 }
3344
3345 run_test(
3346 0,
3347 "propName",
3348 json!([1]),
3349 r#"{}"#,
3350 r#"{
3351 "propName": [1]
3352}"#,
3353 );
3354
3355 run_test(
3357 0,
3358 "value0",
3359 json!([1]),
3360 r#"{
3361 "value1": 5
3362}"#,
3363 r#"{
3364 "value0": [1],
3365 "value1": 5
3366}"#,
3367 );
3368
3369 run_test(
3371 0,
3372 "value0",
3373 json!([1]),
3374 r#"{
3375 // some comment
3376 "value1": 5
3377}"#,
3378 r#"{
3379 "value0": [1],
3380 // some comment
3381 "value1": 5
3382}"#,
3383 );
3384
3385 run_test(
3387 1,
3388 "value1",
3389 json!({
3390 "value": 1
3391 }),
3392 r#"{
3393 "value0": 5 // comment
3394}"#,
3395 r#"{
3396 "value0": 5, // comment
3397 "value1": {
3398 "value": 1
3399 }
3400}"#,
3401 );
3402
3403 run_test(
3405 1,
3406 "propName",
3407 json!(true),
3408 r#"{
3409 "value": 4,
3410}"#,
3411 r#"{
3412 "value": 4,
3413 "propName": true,
3414}"#,
3415 );
3416
3417 run_test(
3419 1,
3420 "propName",
3421 json!(true),
3422 r#"{ "value": 4 }"#,
3423 r#"{
3424 "value": 4,
3425 "propName": true
3426}"#,
3427 );
3428
3429 run_test(
3431 1,
3432 "propName",
3433 json!(true),
3434 r#"{ "value": 4, }"#,
3435 r#"{
3436 "value": 4,
3437 "propName": true,
3438}"#,
3439 );
3440 }
3441
3442 #[test]
3443 fn remove_array_elements() {
3444 fn run_test(index: usize, json: &str, expected: &str) {
3445 let cst = build_cst(json);
3446 let root_value = cst.value().unwrap();
3447 let root_array = root_value.as_array().unwrap();
3448 let element = root_array.elements().get(index).unwrap().clone();
3449 element.remove();
3450 assert_eq!(cst.to_string(), expected);
3451 }
3452
3453 run_test(
3454 0,
3455 r#"[
3456 1,
3457]"#,
3458 r#"[]"#,
3459 );
3460 run_test(
3461 0,
3462 r#"[
3463 1,
3464 2,
3465]"#,
3466 r#"[
3467 2,
3468]"#,
3469 );
3470 run_test(
3471 0,
3472 r#"[
3473 1,
3474 2,
3475]"#,
3476 r#"[
3477 2,
3478]"#,
3479 );
3480
3481 run_test(
3482 1,
3483 r#"[
3484 1, // other comment
3485 2, // trailing comment
3486]"#,
3487 r#"[
3488 1, // other comment
3489]"#,
3490 );
3491
3492 run_test(
3493 1,
3494 r#"[
3495 1, // comment
3496 2
3497]"#,
3498 r#"[
3499 1 // comment
3500]"#,
3501 );
3502
3503 run_test(1, r#"[1, 2]"#, r#"[1]"#);
3504 run_test(1, r#"[ 1, 2 /* test */ ]"#, r#"[ 1 ]"#);
3505 run_test(1, r#"[1, /* test */ 2]"#, r#"[1]"#);
3506 run_test(
3507 1,
3508 r#"[1 /* a */, /* b */ 2 /* c */, /* d */ true]"#,
3509 r#"[1 /* a */, /* d */ true]"#,
3510 );
3511 }
3512
3513 #[test]
3514 fn insert_array_element() {
3515 #[track_caller]
3516 fn run_test(index: usize, value: CstInputValue, json: &str, expected: &str) {
3517 let cst = build_cst(json);
3518 let root_value = cst.value().unwrap();
3519 let root_array = root_value.as_array().unwrap();
3520 root_array.insert(index, value);
3521 assert_eq!(cst.to_string(), expected, "Initial text: {}", json);
3522 }
3523
3524 run_test(0, json!([1]), r#"[]"#, r#"[[1]]"#);
3525 run_test(0, json!([1, true, false, {}]), r#"[]"#, r#"[[1, true, false, {}]]"#);
3526 run_test(0, json!(10), r#"[]"#, r#"[10]"#);
3527 run_test(0, json!(10), r#"[1]"#, r#"[10, 1]"#);
3528 run_test(1, json!(10), r#"[1]"#, r#"[1, 10]"#);
3529 run_test(
3530 0,
3531 json!(10),
3532 r#"[
3533 1
3534]"#,
3535 r#"[
3536 10,
3537 1
3538]"#,
3539 );
3540 run_test(
3541 0,
3542 json!(10),
3543 r#"[
3544 /* test */ 1
3545]"#,
3546 r#"[
3547 10,
3548 /* test */ 1
3549]"#,
3550 );
3551
3552 run_test(
3553 0,
3554 json!({
3555 "value": 1,
3556 }),
3557 r#"[]"#,
3558 r#"[
3559 {
3560 "value": 1
3561 }
3562]"#,
3563 );
3564
3565 run_test(
3567 0,
3568 json!({
3569 "value": 1,
3570 }),
3571 r#"[
3572 // comment
3573]"#,
3574 r#"[
3575 // comment
3576 {
3577 "value": 1
3578 }
3579]"#,
3580 );
3581
3582 run_test(
3584 0,
3585 json!({
3586 "value": 1,
3587 }),
3588 r#"[
3589
3590]"#,
3591 r#"[
3592 {
3593 "value": 1
3594 }
3595]"#,
3596 );
3597 }
3598
3599 #[test]
3600 fn insert_array_element_trailing_commas() {
3601 let cst = build_cst(
3602 r#"{
3603 "prop": [
3604 1,
3605 2,
3606 ]
3607}"#,
3608 );
3609 cst
3610 .object_value_or_create()
3611 .unwrap()
3612 .array_value("prop")
3613 .unwrap()
3614 .append(json!(3));
3615 assert_eq!(
3616 cst.to_string(),
3617 r#"{
3618 "prop": [
3619 1,
3620 2,
3621 3,
3622 ]
3623}"#
3624 );
3625 }
3626
3627 #[test]
3628 fn remove_comment() {
3629 fn run_test(json: &str, expected: &str) {
3630 let cst = build_cst(json);
3631 let root_value = cst.value().unwrap();
3632 let root_obj = root_value.as_object().unwrap();
3633 root_obj
3634 .children()
3635 .into_iter()
3636 .filter_map(|c| c.as_comment())
3637 .next()
3638 .unwrap()
3639 .remove();
3640 assert_eq!(cst.to_string(), expected);
3641 }
3642
3643 run_test(
3644 r#"{
3645 "value": 5,
3646 // comment
3647 "value2": "hello",
3648 value3: true
3649}"#,
3650 r#"{
3651 "value": 5,
3652 "value2": "hello",
3653 value3: true
3654}"#,
3655 );
3656
3657 run_test(
3658 r#"{
3659 "value": 5, // comment
3660 "value2": "hello",
3661 value3: true
3662}"#,
3663 r#"{
3664 "value": 5,
3665 "value2": "hello",
3666 value3: true
3667}"#,
3668 );
3669 }
3670
3671 #[test]
3672 fn object_value_or_create() {
3673 {
3675 let cst = build_cst(r#"{ "value": 1 }"#);
3676 let obj = cst.object_value_or_create().unwrap();
3677 assert!(obj.get("value").is_some());
3678 }
3679 {
3681 let cst = build_cst(r#""#);
3682 cst.object_value_or_create().unwrap();
3683 assert_eq!(cst.to_string(), "{}\n");
3684 }
3685 {
3687 let cst = build_cst("// Copyright something");
3688 cst.object_value_or_create().unwrap();
3689 assert_eq!(cst.to_string(), "// Copyright something\n{}\n");
3690 }
3691 {
3693 let cst = build_cst("// Copyright something\n");
3694 cst.object_value_or_create().unwrap();
3695 assert_eq!(cst.to_string(), "// Copyright something\n{}\n");
3696 }
3697 }
3698
3699 #[test]
3700 fn array_ensure_multiline() {
3701 {
3703 let cst = build_cst(r#"[]"#);
3704 cst.value().unwrap().as_array().unwrap().ensure_multiline();
3705 assert_eq!(cst.to_string(), "[\n]");
3706 }
3707 {
3709 let cst = build_cst(r#"[ ]"#);
3710 cst.value().unwrap().as_array().unwrap().ensure_multiline();
3711 assert_eq!(cst.to_string(), "[\n]");
3712 }
3713 {
3715 let cst = build_cst(r#"[ /* test */ ]"#);
3716 cst.value().unwrap().as_array().unwrap().ensure_multiline();
3717 assert_eq!(cst.to_string(), "[\n /* test */\n]");
3718 }
3719 {
3721 let cst = build_cst(r#"[ 1, 2, /* test */ 3 ]"#);
3722 cst.value().unwrap().as_array().unwrap().ensure_multiline();
3723 assert_eq!(
3724 cst.to_string(),
3725 r#"[
3726 1,
3727 2,
3728 /* test */ 3
3729]"#
3730 );
3731 }
3732 {
3734 let cst = build_cst(
3735 r#"{
3736 "prop": {
3737 "value": [ 1, 2, /* test */ 3 ]
3738 }
3739}"#,
3740 );
3741 cst
3742 .value()
3743 .unwrap()
3744 .as_object()
3745 .unwrap()
3746 .get("prop")
3747 .unwrap()
3748 .value()
3749 .unwrap()
3750 .as_object()
3751 .unwrap()
3752 .get("value")
3753 .unwrap()
3754 .value()
3755 .unwrap()
3756 .as_array()
3757 .unwrap()
3758 .ensure_multiline();
3759 assert_eq!(
3760 cst.to_string(),
3761 r#"{
3762 "prop": {
3763 "value": [
3764 1,
3765 2,
3766 /* test */ 3
3767 ]
3768 }
3769}"#
3770 );
3771 }
3772 {
3774 let cst = build_cst("[ 1, 2, /* test */ 3 ]\r\n");
3775 cst.value().unwrap().as_array().unwrap().ensure_multiline();
3776 assert_eq!(cst.to_string(), "[\r\n 1,\r\n 2,\r\n /* test */ 3\r\n]\r\n");
3777 }
3778 }
3779
3780 #[test]
3781 fn object_ensure_multiline() {
3782 {
3784 let cst = build_cst(r#"{}"#);
3785 cst.value().unwrap().as_object().unwrap().ensure_multiline();
3786 assert_eq!(cst.to_string(), "{\n}");
3787 }
3788 {
3790 let cst = build_cst(r#"{ }"#);
3791 cst.value().unwrap().as_object().unwrap().ensure_multiline();
3792 assert_eq!(cst.to_string(), "{\n}");
3793 }
3794 {
3796 let cst = build_cst(r#"{ /* test */ }"#);
3797 cst.value().unwrap().as_object().unwrap().ensure_multiline();
3798 assert_eq!(cst.to_string(), "{\n /* test */\n}");
3799 }
3800 {
3802 let cst = build_cst(r#"{ prop: 1, prop2: 2, /* test */ prop3: 3 }"#);
3803 cst.value().unwrap().as_object().unwrap().ensure_multiline();
3804 assert_eq!(
3805 cst.to_string(),
3806 r#"{
3807 prop: 1,
3808 prop2: 2,
3809 /* test */ prop3: 3
3810}"#
3811 );
3812 }
3813 {
3815 let cst = build_cst(
3816 r#"{
3817 "prop": {
3818 "value": { prop: 1, prop2: 2, /* test */ prop3: 3 }
3819 }
3820}"#,
3821 );
3822 cst
3823 .value()
3824 .unwrap()
3825 .as_object()
3826 .unwrap()
3827 .get("prop")
3828 .unwrap()
3829 .value()
3830 .unwrap()
3831 .as_object()
3832 .unwrap()
3833 .get("value")
3834 .unwrap()
3835 .value()
3836 .unwrap()
3837 .as_object()
3838 .unwrap()
3839 .ensure_multiline();
3840 assert_eq!(
3841 cst.to_string(),
3842 r#"{
3843 "prop": {
3844 "value": {
3845 prop: 1,
3846 prop2: 2,
3847 /* test */ prop3: 3
3848 }
3849 }
3850}"#
3851 );
3852 }
3853 }
3854
3855 #[test]
3856 fn sets_trailing_commas() {
3857 fn run_test(input: &str, mode: crate::cst::TrailingCommaMode, expected: &str) {
3858 let cst = build_cst(input);
3859 let root_value = cst.value().unwrap();
3860 let root_obj = root_value.as_object().unwrap();
3861 root_obj.set_trailing_commas(mode);
3862 assert_eq!(cst.to_string(), expected);
3863 }
3864
3865 run_test(
3867 r#"{
3868}"#,
3869 TrailingCommaMode::Never,
3870 r#"{
3871}"#,
3872 );
3873 run_test(
3874 r#"{
3875 // test
3876}"#,
3877 TrailingCommaMode::IfMultiline,
3878 r#"{
3879 // test
3880}"#,
3881 );
3882
3883 run_test(r#"{"a": 1}"#, TrailingCommaMode::Never, r#"{"a": 1}"#);
3885 run_test(r#"{"a": 1}"#, TrailingCommaMode::IfMultiline, r#"{"a": 1}"#);
3886 run_test(
3888 r#"{
3889 "a": 1,
3890 "b": 2,
3891 "c": [1, 2, 3],
3892 "d": [
3893 1
3894 ]
3895}"#,
3896 TrailingCommaMode::IfMultiline,
3897 r#"{
3898 "a": 1,
3899 "b": 2,
3900 "c": [1, 2, 3],
3901 "d": [
3902 1,
3903 ],
3904}"#,
3905 );
3906 run_test(
3907 r#"{
3908"a": 1,
3909"b": 2,
3910}"#,
3911 TrailingCommaMode::Never,
3912 r#"{
3913"a": 1,
3914"b": 2
3915}"#,
3916 );
3917 }
3918
3919 #[test]
3920 fn or_create_methods() {
3921 let cst = build_cst("");
3922 let obj = cst.object_value_or_create().unwrap();
3923 assert_eq!(cst.to_string(), "{}\n");
3924 assert!(cst.array_value_or_create().is_none());
3925 assert_eq!(obj.object_value_or_create("prop").unwrap().to_string(), "{}");
3926 assert!(obj.array_value_or_create("prop").is_none());
3927 assert_eq!(obj.array_value_or_create("prop2").unwrap().to_string(), "[]");
3928 assert_eq!(
3929 cst.to_string(),
3930 r#"{
3931 "prop": {},
3932 "prop2": []
3933}
3934"#
3935 );
3936 }
3937
3938 #[test]
3939 fn or_set_methods() {
3940 let cst = build_cst("");
3941 let array = cst.array_value_or_set();
3942 assert_eq!(array.to_string(), "[]");
3943 assert_eq!(cst.to_string(), "[]\n");
3944 let object = cst.object_value_or_set();
3945 assert_eq!(object.to_string(), "{}");
3946 assert_eq!(cst.to_string(), "{}\n");
3947 let value = object.array_value_or_set("test");
3948 assert_eq!(value.to_string(), "[]");
3949 assert_eq!(cst.to_string(), "{\n \"test\": []\n}\n");
3950 let value = object.object_value_or_set("test");
3951 assert_eq!(value.to_string(), "{}");
3952 assert_eq!(cst.to_string(), "{\n \"test\": {}\n}\n");
3953 let value = object.array_value_or_set("test");
3954 assert_eq!(value.to_string(), "[]");
3955 assert_eq!(cst.to_string(), "{\n \"test\": []\n}\n");
3956 value.append(json!(1));
3957 assert_eq!(cst.to_string(), "{\n \"test\": [1]\n}\n");
3958 let value = object.object_value_or_set("test");
3959 assert_eq!(value.to_string(), "{}");
3960 assert_eq!(cst.to_string(), "{\n \"test\": {}\n}\n");
3961 let test_prop = object.get("test").unwrap();
3962 assert!(test_prop.object_value().is_some());
3963 assert!(test_prop.array_value().is_none());
3964 test_prop.array_value_or_set();
3965 assert_eq!(cst.to_string(), "{\n \"test\": []\n}\n");
3966 assert!(test_prop.object_value().is_none());
3967 assert!(test_prop.array_value().is_some());
3968 test_prop.object_value_or_set();
3969 assert_eq!(cst.to_string(), "{\n \"test\": {}\n}\n");
3970 }
3971
3972 #[test]
3973 fn expression_properties_and_values() {
3974 #[track_caller]
3975 fn run_test(value: CstInputValue, expected: &str) {
3976 let cst = build_cst("");
3977 cst.set_value(value);
3978 assert_eq!(cst.to_string(), format!("{}\n", expected));
3979 }
3980
3981 run_test(json!(1), "1");
3982 run_test(json!("test"), "\"test\"");
3983 {
3984 let text = "test";
3985 run_test(json!(text), "\"test\"");
3986 }
3987 {
3988 let num = 1;
3989 run_test(json!(num), "1");
3990 }
3991 {
3992 let vec = vec![1, 2, 3];
3993 run_test(json!(vec), "[1, 2, 3]");
3994 }
3995 {
3996 let vec = vec![1, 2, 3];
3997 run_test(
3998 json!({
3999 "value": vec,
4000 }),
4001 r#"{
4002 "value": [1, 2, 3]
4003}"#,
4004 );
4005 }
4006 run_test(
4007 json!({
4008 notQuoted: 1,
4009 "quoted": 2,
4010 }),
4011 r#"{
4012 "notQuoted": 1,
4013 "quoted": 2
4014}"#,
4015 )
4016 }
4017
4018 #[test]
4019 fn property_index() {
4020 let cst = build_cst("{ \"prop\": 1, \"prop2\": 2, \"prop3\": 3 }");
4021 let object = cst.object_value().unwrap();
4022 for (i, prop) in object.properties().into_iter().enumerate() {
4023 assert_eq!(prop.property_index(), i);
4024 }
4025 }
4026
4027 #[test]
4028 fn element_index() {
4029 let cst = build_cst("[1, 2, true ,false]");
4030 let array = cst.array_value().unwrap();
4031 for (i, prop) in array.elements().into_iter().enumerate() {
4032 assert_eq!(prop.element_index().unwrap(), i);
4033 }
4034 }
4035
4036 #[track_caller]
4037 fn build_cst(text: &str) -> CstRootNode {
4038 CstRootNode::parse(text, &crate::ParseOptions::default()).unwrap()
4039 }
4040
4041 #[cfg(feature = "serde_json")]
4042 mod serde_tests {
4043 use super::build_cst;
4044 use serde_json::Value as SerdeValue;
4045 use std::str::FromStr;
4046
4047 #[test]
4048 fn test_cst_to_serde_value_primitives() {
4049 let root = build_cst(r#"42"#);
4050 let value = root.to_serde_value().unwrap();
4051 assert_eq!(value, SerdeValue::Number(serde_json::Number::from_str("42").unwrap()));
4052
4053 let root = build_cst(r#""hello""#);
4054 let value = root.to_serde_value().unwrap();
4055 assert_eq!(value, SerdeValue::String("hello".to_string()));
4056
4057 let root = build_cst(r#"true"#);
4058 let value = root.to_serde_value().unwrap();
4059 assert_eq!(value, SerdeValue::Bool(true));
4060
4061 let root = build_cst(r#"false"#);
4062 let value = root.to_serde_value().unwrap();
4063 assert_eq!(value, SerdeValue::Bool(false));
4064
4065 let root = build_cst(r#"null"#);
4066 let value = root.to_serde_value().unwrap();
4067 assert_eq!(value, SerdeValue::Null);
4068 }
4069
4070 #[test]
4071 fn test_cst_to_serde_value_array() {
4072 let root = build_cst(r#"[1, 2, 3]"#);
4073 let value = root.to_serde_value().unwrap();
4074 let expected = SerdeValue::Array(vec![
4075 SerdeValue::Number(serde_json::Number::from_str("1").unwrap()),
4076 SerdeValue::Number(serde_json::Number::from_str("2").unwrap()),
4077 SerdeValue::Number(serde_json::Number::from_str("3").unwrap()),
4078 ]);
4079 assert_eq!(value, expected);
4080 }
4081
4082 #[test]
4083 fn test_cst_to_serde_value_array_with_comments() {
4084 let root = build_cst(
4085 r#"[
4086 // comment 1
4087 1,
4088 2, // comment 2
4089 3
4090 ]"#,
4091 );
4092 let value = root.to_serde_value().unwrap();
4093 let expected = SerdeValue::Array(vec![
4094 SerdeValue::Number(serde_json::Number::from_str("1").unwrap()),
4095 SerdeValue::Number(serde_json::Number::from_str("2").unwrap()),
4096 SerdeValue::Number(serde_json::Number::from_str("3").unwrap()),
4097 ]);
4098 assert_eq!(value, expected);
4099 }
4100
4101 #[test]
4102 fn test_cst_to_serde_value_object() {
4103 let root = build_cst(
4104 r#"{
4105 "name": "Alice",
4106 "age": 30,
4107 "active": true
4108 }"#,
4109 );
4110 let value = root.to_serde_value().unwrap();
4111
4112 let mut expected_map = serde_json::map::Map::new();
4113 expected_map.insert("name".to_string(), SerdeValue::String("Alice".to_string()));
4114 expected_map.insert(
4115 "age".to_string(),
4116 SerdeValue::Number(serde_json::Number::from_str("30").unwrap()),
4117 );
4118 expected_map.insert("active".to_string(), SerdeValue::Bool(true));
4119
4120 assert_eq!(value, SerdeValue::Object(expected_map));
4121 }
4122
4123 #[test]
4124 fn test_cst_to_serde_value_object_with_comments() {
4125 let root = build_cst(
4126 r#"{
4127 // This is a name
4128 "name": "Bob",
4129 /* age field */
4130 "age": 25
4131 }"#,
4132 );
4133 let value = root.to_serde_value().unwrap();
4134
4135 let mut expected_map = serde_json::map::Map::new();
4136 expected_map.insert("name".to_string(), SerdeValue::String("Bob".to_string()));
4137 expected_map.insert(
4138 "age".to_string(),
4139 SerdeValue::Number(serde_json::Number::from_str("25").unwrap()),
4140 );
4141
4142 assert_eq!(value, SerdeValue::Object(expected_map));
4143 }
4144
4145 #[test]
4146 fn test_cst_to_serde_value_nested() {
4147 let root = build_cst(
4148 r#"{
4149 "person": {
4150 "name": "Charlie",
4151 "hobbies": ["reading", "gaming"]
4152 },
4153 "count": 42
4154 }"#,
4155 );
4156 let value = root.to_serde_value().unwrap();
4157
4158 let mut hobbies = Vec::new();
4159 hobbies.push(SerdeValue::String("reading".to_string()));
4160 hobbies.push(SerdeValue::String("gaming".to_string()));
4161
4162 let mut person_map = serde_json::map::Map::new();
4163 person_map.insert("name".to_string(), SerdeValue::String("Charlie".to_string()));
4164 person_map.insert("hobbies".to_string(), SerdeValue::Array(hobbies));
4165
4166 let mut expected_map = serde_json::map::Map::new();
4167 expected_map.insert("person".to_string(), SerdeValue::Object(person_map));
4168 expected_map.insert(
4169 "count".to_string(),
4170 SerdeValue::Number(serde_json::Number::from_str("42").unwrap()),
4171 );
4172
4173 assert_eq!(value, SerdeValue::Object(expected_map));
4174 }
4175
4176 #[test]
4177 fn test_cst_to_serde_value_with_trailing_comma() {
4178 let root = build_cst(
4179 r#"{
4180 "a": 1,
4181 "b": 2,
4182 }"#,
4183 );
4184 let value = root.to_serde_value().unwrap();
4185
4186 let mut expected_map = serde_json::map::Map::new();
4187 expected_map.insert(
4188 "a".to_string(),
4189 SerdeValue::Number(serde_json::Number::from_str("1").unwrap()),
4190 );
4191 expected_map.insert(
4192 "b".to_string(),
4193 SerdeValue::Number(serde_json::Number::from_str("2").unwrap()),
4194 );
4195
4196 assert_eq!(value, SerdeValue::Object(expected_map));
4197 }
4198
4199 #[test]
4200 fn test_cst_to_serde_value_empty_structures() {
4201 let root = build_cst(r#"{}"#);
4202 let value = root.to_serde_value().unwrap();
4203 assert_eq!(value, SerdeValue::Object(serde_json::map::Map::new()));
4204
4205 let root = build_cst(r#"[]"#);
4206 let value = root.to_serde_value().unwrap();
4207 assert_eq!(value, SerdeValue::Array(Vec::new()));
4208 }
4209
4210 #[test]
4211 fn test_cst_to_serde_value_scientific_notation() {
4212 let root = build_cst(r#"0.3e+025"#);
4213 let value = root.to_serde_value().unwrap();
4214 assert_eq!(
4215 value,
4216 SerdeValue::Number(serde_json::Number::from_str("0.3e+025").unwrap())
4217 );
4218 }
4219
4220 #[test]
4221 fn test_cst_node_to_serde_value() {
4222 let root = build_cst(r#"{ "test": 123 }"#);
4223 let value_node = root.value().unwrap();
4224 let json_value = value_node.to_serde_value().unwrap();
4225
4226 let mut expected_map = serde_json::map::Map::new();
4227 expected_map.insert(
4228 "test".to_string(),
4229 SerdeValue::Number(serde_json::Number::from_str("123").unwrap()),
4230 );
4231
4232 assert_eq!(json_value, SerdeValue::Object(expected_map));
4233 }
4234
4235 #[test]
4236 fn test_cst_object_prop_to_serde_value() {
4237 let root = build_cst(r#"{ "key": [1, 2, 3] }"#);
4238 let obj = root.value().unwrap().as_object().unwrap();
4239 let prop = obj.get("key").unwrap();
4240 let prop_value = prop.to_serde_value().unwrap();
4241
4242 let expected = SerdeValue::Array(vec![
4243 SerdeValue::Number(serde_json::Number::from_str("1").unwrap()),
4244 SerdeValue::Number(serde_json::Number::from_str("2").unwrap()),
4245 SerdeValue::Number(serde_json::Number::from_str("3").unwrap()),
4246 ]);
4247
4248 assert_eq!(prop_value, expected);
4249 }
4250 }
4251
4252 #[test]
4253 fn new_escaped_handles_backslashes() {
4254 let cst = build_cst(r#"{"key": "old"}"#);
4255 let root_obj = cst.object_value().unwrap();
4256 let prop = root_obj.get("key").unwrap();
4257 prop.set_value(json!("/.github/workflows/lint\\.yaml$/"));
4259 assert_eq!(
4260 cst.to_string(),
4261 r#"{"key": "/.github/workflows/lint\\.yaml$/"}"#,
4262 );
4263 let decoded = root_obj
4265 .get("key")
4266 .unwrap()
4267 .value()
4268 .unwrap()
4269 .as_string_lit()
4270 .unwrap()
4271 .decoded_value()
4272 .unwrap();
4273 assert_eq!(decoded, "/.github/workflows/lint\\.yaml$/");
4274 }
4275
4276 #[test]
4277 fn new_escaped_handles_control_characters() {
4278 let cst = build_cst(r#"{}"#);
4279 let root_obj = cst.object_value_or_create().unwrap();
4280
4281 root_obj.append("tab", json!("hello\tworld"));
4282 root_obj.append("newline", json!("hello\nworld"));
4283 root_obj.append("cr", json!("hello\rworld"));
4284 root_obj.append("backspace", json!("hello\u{08}world"));
4285 root_obj.append("formfeed", json!("hello\u{0c}world"));
4286
4287 let text = cst.to_string();
4288 assert!(text.contains(r#""hello\tworld""#), "tab not escaped: {}", text);
4289 assert!(text.contains(r#""hello\nworld""#), "newline not escaped: {}", text);
4290 assert!(text.contains(r#""hello\rworld""#), "cr not escaped: {}", text);
4291 assert!(text.contains(r#""hello\bworld""#), "backspace not escaped: {}", text);
4292 assert!(text.contains(r#""hello\fworld""#), "formfeed not escaped: {}", text);
4293
4294 for (key, expected) in [
4296 ("tab", "hello\tworld"),
4297 ("newline", "hello\nworld"),
4298 ("cr", "hello\rworld"),
4299 ("backspace", "hello\u{08}world"),
4300 ("formfeed", "hello\u{0c}world"),
4301 ] {
4302 let decoded = root_obj
4303 .get(key)
4304 .unwrap()
4305 .value()
4306 .unwrap()
4307 .as_string_lit()
4308 .unwrap()
4309 .decoded_value()
4310 .unwrap();
4311 assert_eq!(decoded, expected, "roundtrip failed for key: {}", key);
4312 }
4313 }
4314
4315 #[test]
4316 fn new_escaped_handles_quotes_and_backslashes_together() {
4317 let cst = build_cst(r#"{}"#);
4318 let root_obj = cst.object_value_or_create().unwrap();
4319
4320 root_obj.append("mixed", json!("say \"hello\\world\""));
4321
4322 let text = cst.to_string();
4323 assert!(
4324 text.contains(r#""say \"hello\\world\"""#),
4325 "mixed escaping failed: {}",
4326 text
4327 );
4328
4329 let decoded = root_obj
4330 .get("mixed")
4331 .unwrap()
4332 .value()
4333 .unwrap()
4334 .as_string_lit()
4335 .unwrap()
4336 .decoded_value()
4337 .unwrap();
4338 assert_eq!(decoded, "say \"hello\\world\"");
4339 }
4340
4341 #[test]
4342 fn new_escaped_in_array_values() {
4343 let cst = build_cst(r#"{"items": []}"#);
4344 let root_obj = cst.object_value().unwrap();
4345 let arr = root_obj.array_value("items").unwrap();
4346
4347 arr.append(json!("path\\to\\file"));
4348 arr.append(json!("line1\nline2"));
4349
4350 let text = cst.to_string();
4351 assert!(text.contains(r#""path\\to\\file""#), "backslash in array element: {}", text);
4352 assert!(text.contains(r#""line1\nline2""#), "newline in array element: {}", text);
4353 }
4354
4355 #[test]
4356 fn new_escaped_property_name_with_special_chars() {
4357 let cst = build_cst(r#"{}"#);
4358 let root_obj = cst.object_value_or_create().unwrap();
4359
4360 root_obj.append("key\\with\\backslash", json!("value"));
4361
4362 let text = cst.to_string();
4363 assert!(
4364 text.contains(r#""key\\with\\backslash""#),
4365 "property name escaping failed: {}",
4366 text
4367 );
4368
4369 let decoded = root_obj
4370 .properties()
4371 .first()
4372 .unwrap()
4373 .name()
4374 .unwrap()
4375 .decoded_value()
4376 .unwrap();
4377 assert_eq!(decoded, "key\\with\\backslash");
4378 }
4379}