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 CstWhitespace::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 CstWhitespace::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 CstWhitespace::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 CstWhitespace::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 append_to_multiline_array_does_not_expose_phantom_string_lit() {
3601 let cst = build_cst(
3603 r#"{
3604 "servers": [
3605 {"name": "linear"},
3606 {"name": "supabase"}
3607 ]
3608}"#,
3609 );
3610 let arr = cst.object_value_or_create().unwrap().array_value("servers").unwrap();
3611 arr.append(CstInputValue::Object(vec![(
3612 "name".to_string(),
3613 CstInputValue::String("github".to_string()),
3614 )]));
3615
3616 let elements = arr.elements();
3617 assert_eq!(elements.len(), 3);
3618 for el in &elements {
3619 assert!(
3620 el.as_string_lit().is_none(),
3621 "element should not be a string lit: {:?}",
3622 el
3623 );
3624 assert!(el.as_object().is_some(), "element should be an object: {:?}", el);
3625 }
3626 }
3627
3628 #[test]
3629 fn insert_array_element_trailing_commas() {
3630 let cst = build_cst(
3631 r#"{
3632 "prop": [
3633 1,
3634 2,
3635 ]
3636}"#,
3637 );
3638 cst
3639 .object_value_or_create()
3640 .unwrap()
3641 .array_value("prop")
3642 .unwrap()
3643 .append(json!(3));
3644 assert_eq!(
3645 cst.to_string(),
3646 r#"{
3647 "prop": [
3648 1,
3649 2,
3650 3,
3651 ]
3652}"#
3653 );
3654 }
3655
3656 #[test]
3657 fn remove_comment() {
3658 fn run_test(json: &str, expected: &str) {
3659 let cst = build_cst(json);
3660 let root_value = cst.value().unwrap();
3661 let root_obj = root_value.as_object().unwrap();
3662 root_obj
3663 .children()
3664 .into_iter()
3665 .filter_map(|c| c.as_comment())
3666 .next()
3667 .unwrap()
3668 .remove();
3669 assert_eq!(cst.to_string(), expected);
3670 }
3671
3672 run_test(
3673 r#"{
3674 "value": 5,
3675 // comment
3676 "value2": "hello",
3677 value3: true
3678}"#,
3679 r#"{
3680 "value": 5,
3681 "value2": "hello",
3682 value3: true
3683}"#,
3684 );
3685
3686 run_test(
3687 r#"{
3688 "value": 5, // comment
3689 "value2": "hello",
3690 value3: true
3691}"#,
3692 r#"{
3693 "value": 5,
3694 "value2": "hello",
3695 value3: true
3696}"#,
3697 );
3698 }
3699
3700 #[test]
3701 fn object_value_or_create() {
3702 {
3704 let cst = build_cst(r#"{ "value": 1 }"#);
3705 let obj = cst.object_value_or_create().unwrap();
3706 assert!(obj.get("value").is_some());
3707 }
3708 {
3710 let cst = build_cst(r#""#);
3711 cst.object_value_or_create().unwrap();
3712 assert_eq!(cst.to_string(), "{}\n");
3713 }
3714 {
3716 let cst = build_cst("// Copyright something");
3717 cst.object_value_or_create().unwrap();
3718 assert_eq!(cst.to_string(), "// Copyright something\n{}\n");
3719 }
3720 {
3722 let cst = build_cst("// Copyright something\n");
3723 cst.object_value_or_create().unwrap();
3724 assert_eq!(cst.to_string(), "// Copyright something\n{}\n");
3725 }
3726 }
3727
3728 #[test]
3729 fn array_ensure_multiline() {
3730 {
3732 let cst = build_cst(r#"[]"#);
3733 cst.value().unwrap().as_array().unwrap().ensure_multiline();
3734 assert_eq!(cst.to_string(), "[\n]");
3735 }
3736 {
3738 let cst = build_cst(r#"[ ]"#);
3739 cst.value().unwrap().as_array().unwrap().ensure_multiline();
3740 assert_eq!(cst.to_string(), "[\n]");
3741 }
3742 {
3744 let cst = build_cst(r#"[ /* test */ ]"#);
3745 cst.value().unwrap().as_array().unwrap().ensure_multiline();
3746 assert_eq!(cst.to_string(), "[\n /* test */\n]");
3747 }
3748 {
3750 let cst = build_cst(r#"[ 1, 2, /* test */ 3 ]"#);
3751 cst.value().unwrap().as_array().unwrap().ensure_multiline();
3752 assert_eq!(
3753 cst.to_string(),
3754 r#"[
3755 1,
3756 2,
3757 /* test */ 3
3758]"#
3759 );
3760 }
3761 {
3763 let cst = build_cst(
3764 r#"{
3765 "prop": {
3766 "value": [ 1, 2, /* test */ 3 ]
3767 }
3768}"#,
3769 );
3770 cst
3771 .value()
3772 .unwrap()
3773 .as_object()
3774 .unwrap()
3775 .get("prop")
3776 .unwrap()
3777 .value()
3778 .unwrap()
3779 .as_object()
3780 .unwrap()
3781 .get("value")
3782 .unwrap()
3783 .value()
3784 .unwrap()
3785 .as_array()
3786 .unwrap()
3787 .ensure_multiline();
3788 assert_eq!(
3789 cst.to_string(),
3790 r#"{
3791 "prop": {
3792 "value": [
3793 1,
3794 2,
3795 /* test */ 3
3796 ]
3797 }
3798}"#
3799 );
3800 }
3801 {
3803 let cst = build_cst("[ 1, 2, /* test */ 3 ]\r\n");
3804 cst.value().unwrap().as_array().unwrap().ensure_multiline();
3805 assert_eq!(cst.to_string(), "[\r\n 1,\r\n 2,\r\n /* test */ 3\r\n]\r\n");
3806 }
3807 }
3808
3809 #[test]
3810 fn object_ensure_multiline() {
3811 {
3813 let cst = build_cst(r#"{}"#);
3814 cst.value().unwrap().as_object().unwrap().ensure_multiline();
3815 assert_eq!(cst.to_string(), "{\n}");
3816 }
3817 {
3819 let cst = build_cst(r#"{ }"#);
3820 cst.value().unwrap().as_object().unwrap().ensure_multiline();
3821 assert_eq!(cst.to_string(), "{\n}");
3822 }
3823 {
3825 let cst = build_cst(r#"{ /* test */ }"#);
3826 cst.value().unwrap().as_object().unwrap().ensure_multiline();
3827 assert_eq!(cst.to_string(), "{\n /* test */\n}");
3828 }
3829 {
3831 let cst = build_cst(r#"{ prop: 1, prop2: 2, /* test */ prop3: 3 }"#);
3832 cst.value().unwrap().as_object().unwrap().ensure_multiline();
3833 assert_eq!(
3834 cst.to_string(),
3835 r#"{
3836 prop: 1,
3837 prop2: 2,
3838 /* test */ prop3: 3
3839}"#
3840 );
3841 }
3842 {
3844 let cst = build_cst(
3845 r#"{
3846 "prop": {
3847 "value": { prop: 1, prop2: 2, /* test */ prop3: 3 }
3848 }
3849}"#,
3850 );
3851 cst
3852 .value()
3853 .unwrap()
3854 .as_object()
3855 .unwrap()
3856 .get("prop")
3857 .unwrap()
3858 .value()
3859 .unwrap()
3860 .as_object()
3861 .unwrap()
3862 .get("value")
3863 .unwrap()
3864 .value()
3865 .unwrap()
3866 .as_object()
3867 .unwrap()
3868 .ensure_multiline();
3869 assert_eq!(
3870 cst.to_string(),
3871 r#"{
3872 "prop": {
3873 "value": {
3874 prop: 1,
3875 prop2: 2,
3876 /* test */ prop3: 3
3877 }
3878 }
3879}"#
3880 );
3881 }
3882 }
3883
3884 #[test]
3885 fn sets_trailing_commas() {
3886 fn run_test(input: &str, mode: crate::cst::TrailingCommaMode, expected: &str) {
3887 let cst = build_cst(input);
3888 let root_value = cst.value().unwrap();
3889 let root_obj = root_value.as_object().unwrap();
3890 root_obj.set_trailing_commas(mode);
3891 assert_eq!(cst.to_string(), expected);
3892 }
3893
3894 run_test(
3896 r#"{
3897}"#,
3898 TrailingCommaMode::Never,
3899 r#"{
3900}"#,
3901 );
3902 run_test(
3903 r#"{
3904 // test
3905}"#,
3906 TrailingCommaMode::IfMultiline,
3907 r#"{
3908 // test
3909}"#,
3910 );
3911
3912 run_test(r#"{"a": 1}"#, TrailingCommaMode::Never, r#"{"a": 1}"#);
3914 run_test(r#"{"a": 1}"#, TrailingCommaMode::IfMultiline, r#"{"a": 1}"#);
3915 run_test(
3917 r#"{
3918 "a": 1,
3919 "b": 2,
3920 "c": [1, 2, 3],
3921 "d": [
3922 1
3923 ]
3924}"#,
3925 TrailingCommaMode::IfMultiline,
3926 r#"{
3927 "a": 1,
3928 "b": 2,
3929 "c": [1, 2, 3],
3930 "d": [
3931 1,
3932 ],
3933}"#,
3934 );
3935 run_test(
3936 r#"{
3937"a": 1,
3938"b": 2,
3939}"#,
3940 TrailingCommaMode::Never,
3941 r#"{
3942"a": 1,
3943"b": 2
3944}"#,
3945 );
3946 }
3947
3948 #[test]
3949 fn or_create_methods() {
3950 let cst = build_cst("");
3951 let obj = cst.object_value_or_create().unwrap();
3952 assert_eq!(cst.to_string(), "{}\n");
3953 assert!(cst.array_value_or_create().is_none());
3954 assert_eq!(obj.object_value_or_create("prop").unwrap().to_string(), "{}");
3955 assert!(obj.array_value_or_create("prop").is_none());
3956 assert_eq!(obj.array_value_or_create("prop2").unwrap().to_string(), "[]");
3957 assert_eq!(
3958 cst.to_string(),
3959 r#"{
3960 "prop": {},
3961 "prop2": []
3962}
3963"#
3964 );
3965 }
3966
3967 #[test]
3968 fn or_set_methods() {
3969 let cst = build_cst("");
3970 let array = cst.array_value_or_set();
3971 assert_eq!(array.to_string(), "[]");
3972 assert_eq!(cst.to_string(), "[]\n");
3973 let object = cst.object_value_or_set();
3974 assert_eq!(object.to_string(), "{}");
3975 assert_eq!(cst.to_string(), "{}\n");
3976 let value = object.array_value_or_set("test");
3977 assert_eq!(value.to_string(), "[]");
3978 assert_eq!(cst.to_string(), "{\n \"test\": []\n}\n");
3979 let value = object.object_value_or_set("test");
3980 assert_eq!(value.to_string(), "{}");
3981 assert_eq!(cst.to_string(), "{\n \"test\": {}\n}\n");
3982 let value = object.array_value_or_set("test");
3983 assert_eq!(value.to_string(), "[]");
3984 assert_eq!(cst.to_string(), "{\n \"test\": []\n}\n");
3985 value.append(json!(1));
3986 assert_eq!(cst.to_string(), "{\n \"test\": [1]\n}\n");
3987 let value = object.object_value_or_set("test");
3988 assert_eq!(value.to_string(), "{}");
3989 assert_eq!(cst.to_string(), "{\n \"test\": {}\n}\n");
3990 let test_prop = object.get("test").unwrap();
3991 assert!(test_prop.object_value().is_some());
3992 assert!(test_prop.array_value().is_none());
3993 test_prop.array_value_or_set();
3994 assert_eq!(cst.to_string(), "{\n \"test\": []\n}\n");
3995 assert!(test_prop.object_value().is_none());
3996 assert!(test_prop.array_value().is_some());
3997 test_prop.object_value_or_set();
3998 assert_eq!(cst.to_string(), "{\n \"test\": {}\n}\n");
3999 }
4000
4001 #[test]
4002 fn expression_properties_and_values() {
4003 #[track_caller]
4004 fn run_test(value: CstInputValue, expected: &str) {
4005 let cst = build_cst("");
4006 cst.set_value(value);
4007 assert_eq!(cst.to_string(), format!("{}\n", expected));
4008 }
4009
4010 run_test(json!(1), "1");
4011 run_test(json!("test"), "\"test\"");
4012 {
4013 let text = "test";
4014 run_test(json!(text), "\"test\"");
4015 }
4016 {
4017 let num = 1;
4018 run_test(json!(num), "1");
4019 }
4020 {
4021 let vec = vec![1, 2, 3];
4022 run_test(json!(vec), "[1, 2, 3]");
4023 }
4024 {
4025 let vec = vec![1, 2, 3];
4026 run_test(
4027 json!({
4028 "value": vec,
4029 }),
4030 r#"{
4031 "value": [1, 2, 3]
4032}"#,
4033 );
4034 }
4035 run_test(
4036 json!({
4037 notQuoted: 1,
4038 "quoted": 2,
4039 }),
4040 r#"{
4041 "notQuoted": 1,
4042 "quoted": 2
4043}"#,
4044 )
4045 }
4046
4047 #[test]
4048 fn property_index() {
4049 let cst = build_cst("{ \"prop\": 1, \"prop2\": 2, \"prop3\": 3 }");
4050 let object = cst.object_value().unwrap();
4051 for (i, prop) in object.properties().into_iter().enumerate() {
4052 assert_eq!(prop.property_index(), i);
4053 }
4054 }
4055
4056 #[test]
4057 fn element_index() {
4058 let cst = build_cst("[1, 2, true ,false]");
4059 let array = cst.array_value().unwrap();
4060 for (i, prop) in array.elements().into_iter().enumerate() {
4061 assert_eq!(prop.element_index().unwrap(), i);
4062 }
4063 }
4064
4065 #[track_caller]
4066 fn build_cst(text: &str) -> CstRootNode {
4067 CstRootNode::parse(text, &crate::ParseOptions::default()).unwrap()
4068 }
4069
4070 #[cfg(feature = "serde_json")]
4071 mod serde_tests {
4072 use super::build_cst;
4073 use serde_json::Value as SerdeValue;
4074 use std::str::FromStr;
4075
4076 #[test]
4077 fn test_cst_to_serde_value_primitives() {
4078 let root = build_cst(r#"42"#);
4079 let value = root.to_serde_value().unwrap();
4080 assert_eq!(value, SerdeValue::Number(serde_json::Number::from_str("42").unwrap()));
4081
4082 let root = build_cst(r#""hello""#);
4083 let value = root.to_serde_value().unwrap();
4084 assert_eq!(value, SerdeValue::String("hello".to_string()));
4085
4086 let root = build_cst(r#"true"#);
4087 let value = root.to_serde_value().unwrap();
4088 assert_eq!(value, SerdeValue::Bool(true));
4089
4090 let root = build_cst(r#"false"#);
4091 let value = root.to_serde_value().unwrap();
4092 assert_eq!(value, SerdeValue::Bool(false));
4093
4094 let root = build_cst(r#"null"#);
4095 let value = root.to_serde_value().unwrap();
4096 assert_eq!(value, SerdeValue::Null);
4097 }
4098
4099 #[test]
4100 fn test_cst_to_serde_value_array() {
4101 let root = build_cst(r#"[1, 2, 3]"#);
4102 let value = root.to_serde_value().unwrap();
4103 let expected = SerdeValue::Array(vec![
4104 SerdeValue::Number(serde_json::Number::from_str("1").unwrap()),
4105 SerdeValue::Number(serde_json::Number::from_str("2").unwrap()),
4106 SerdeValue::Number(serde_json::Number::from_str("3").unwrap()),
4107 ]);
4108 assert_eq!(value, expected);
4109 }
4110
4111 #[test]
4112 fn test_cst_to_serde_value_array_with_comments() {
4113 let root = build_cst(
4114 r#"[
4115 // comment 1
4116 1,
4117 2, // comment 2
4118 3
4119 ]"#,
4120 );
4121 let value = root.to_serde_value().unwrap();
4122 let expected = SerdeValue::Array(vec![
4123 SerdeValue::Number(serde_json::Number::from_str("1").unwrap()),
4124 SerdeValue::Number(serde_json::Number::from_str("2").unwrap()),
4125 SerdeValue::Number(serde_json::Number::from_str("3").unwrap()),
4126 ]);
4127 assert_eq!(value, expected);
4128 }
4129
4130 #[test]
4131 fn test_cst_to_serde_value_object() {
4132 let root = build_cst(
4133 r#"{
4134 "name": "Alice",
4135 "age": 30,
4136 "active": true
4137 }"#,
4138 );
4139 let value = root.to_serde_value().unwrap();
4140
4141 let mut expected_map = serde_json::map::Map::new();
4142 expected_map.insert("name".to_string(), SerdeValue::String("Alice".to_string()));
4143 expected_map.insert(
4144 "age".to_string(),
4145 SerdeValue::Number(serde_json::Number::from_str("30").unwrap()),
4146 );
4147 expected_map.insert("active".to_string(), SerdeValue::Bool(true));
4148
4149 assert_eq!(value, SerdeValue::Object(expected_map));
4150 }
4151
4152 #[test]
4153 fn test_cst_to_serde_value_object_with_comments() {
4154 let root = build_cst(
4155 r#"{
4156 // This is a name
4157 "name": "Bob",
4158 /* age field */
4159 "age": 25
4160 }"#,
4161 );
4162 let value = root.to_serde_value().unwrap();
4163
4164 let mut expected_map = serde_json::map::Map::new();
4165 expected_map.insert("name".to_string(), SerdeValue::String("Bob".to_string()));
4166 expected_map.insert(
4167 "age".to_string(),
4168 SerdeValue::Number(serde_json::Number::from_str("25").unwrap()),
4169 );
4170
4171 assert_eq!(value, SerdeValue::Object(expected_map));
4172 }
4173
4174 #[test]
4175 fn test_cst_to_serde_value_nested() {
4176 let root = build_cst(
4177 r#"{
4178 "person": {
4179 "name": "Charlie",
4180 "hobbies": ["reading", "gaming"]
4181 },
4182 "count": 42
4183 }"#,
4184 );
4185 let value = root.to_serde_value().unwrap();
4186
4187 let mut hobbies = Vec::new();
4188 hobbies.push(SerdeValue::String("reading".to_string()));
4189 hobbies.push(SerdeValue::String("gaming".to_string()));
4190
4191 let mut person_map = serde_json::map::Map::new();
4192 person_map.insert("name".to_string(), SerdeValue::String("Charlie".to_string()));
4193 person_map.insert("hobbies".to_string(), SerdeValue::Array(hobbies));
4194
4195 let mut expected_map = serde_json::map::Map::new();
4196 expected_map.insert("person".to_string(), SerdeValue::Object(person_map));
4197 expected_map.insert(
4198 "count".to_string(),
4199 SerdeValue::Number(serde_json::Number::from_str("42").unwrap()),
4200 );
4201
4202 assert_eq!(value, SerdeValue::Object(expected_map));
4203 }
4204
4205 #[test]
4206 fn test_cst_to_serde_value_with_trailing_comma() {
4207 let root = build_cst(
4208 r#"{
4209 "a": 1,
4210 "b": 2,
4211 }"#,
4212 );
4213 let value = root.to_serde_value().unwrap();
4214
4215 let mut expected_map = serde_json::map::Map::new();
4216 expected_map.insert(
4217 "a".to_string(),
4218 SerdeValue::Number(serde_json::Number::from_str("1").unwrap()),
4219 );
4220 expected_map.insert(
4221 "b".to_string(),
4222 SerdeValue::Number(serde_json::Number::from_str("2").unwrap()),
4223 );
4224
4225 assert_eq!(value, SerdeValue::Object(expected_map));
4226 }
4227
4228 #[test]
4229 fn test_cst_to_serde_value_empty_structures() {
4230 let root = build_cst(r#"{}"#);
4231 let value = root.to_serde_value().unwrap();
4232 assert_eq!(value, SerdeValue::Object(serde_json::map::Map::new()));
4233
4234 let root = build_cst(r#"[]"#);
4235 let value = root.to_serde_value().unwrap();
4236 assert_eq!(value, SerdeValue::Array(Vec::new()));
4237 }
4238
4239 #[test]
4240 fn test_cst_to_serde_value_scientific_notation() {
4241 let root = build_cst(r#"0.3e+025"#);
4242 let value = root.to_serde_value().unwrap();
4243 assert_eq!(
4244 value,
4245 SerdeValue::Number(serde_json::Number::from_str("0.3e+025").unwrap())
4246 );
4247 }
4248
4249 #[test]
4250 fn test_cst_node_to_serde_value() {
4251 let root = build_cst(r#"{ "test": 123 }"#);
4252 let value_node = root.value().unwrap();
4253 let json_value = value_node.to_serde_value().unwrap();
4254
4255 let mut expected_map = serde_json::map::Map::new();
4256 expected_map.insert(
4257 "test".to_string(),
4258 SerdeValue::Number(serde_json::Number::from_str("123").unwrap()),
4259 );
4260
4261 assert_eq!(json_value, SerdeValue::Object(expected_map));
4262 }
4263
4264 #[test]
4265 fn test_cst_object_prop_to_serde_value() {
4266 let root = build_cst(r#"{ "key": [1, 2, 3] }"#);
4267 let obj = root.value().unwrap().as_object().unwrap();
4268 let prop = obj.get("key").unwrap();
4269 let prop_value = prop.to_serde_value().unwrap();
4270
4271 let expected = SerdeValue::Array(vec![
4272 SerdeValue::Number(serde_json::Number::from_str("1").unwrap()),
4273 SerdeValue::Number(serde_json::Number::from_str("2").unwrap()),
4274 SerdeValue::Number(serde_json::Number::from_str("3").unwrap()),
4275 ]);
4276
4277 assert_eq!(prop_value, expected);
4278 }
4279 }
4280
4281 #[test]
4282 fn new_escaped_handles_backslashes() {
4283 let cst = build_cst(r#"{"key": "old"}"#);
4284 let root_obj = cst.object_value().unwrap();
4285 let prop = root_obj.get("key").unwrap();
4286 prop.set_value(json!("/.github/workflows/lint\\.yaml$/"));
4288 assert_eq!(cst.to_string(), r#"{"key": "/.github/workflows/lint\\.yaml$/"}"#,);
4289 let decoded = root_obj
4291 .get("key")
4292 .unwrap()
4293 .value()
4294 .unwrap()
4295 .as_string_lit()
4296 .unwrap()
4297 .decoded_value()
4298 .unwrap();
4299 assert_eq!(decoded, "/.github/workflows/lint\\.yaml$/");
4300 }
4301
4302 #[test]
4303 fn new_escaped_handles_control_characters() {
4304 let cst = build_cst(r#"{}"#);
4305 let root_obj = cst.object_value_or_create().unwrap();
4306
4307 root_obj.append("tab", json!("hello\tworld"));
4308 root_obj.append("newline", json!("hello\nworld"));
4309 root_obj.append("cr", json!("hello\rworld"));
4310 root_obj.append("backspace", json!("hello\u{08}world"));
4311 root_obj.append("formfeed", json!("hello\u{0c}world"));
4312
4313 let text = cst.to_string();
4314 assert!(text.contains(r#""hello\tworld""#), "tab not escaped: {}", text);
4315 assert!(text.contains(r#""hello\nworld""#), "newline not escaped: {}", text);
4316 assert!(text.contains(r#""hello\rworld""#), "cr not escaped: {}", text);
4317 assert!(text.contains(r#""hello\bworld""#), "backspace not escaped: {}", text);
4318 assert!(text.contains(r#""hello\fworld""#), "formfeed not escaped: {}", text);
4319
4320 for (key, expected) in [
4322 ("tab", "hello\tworld"),
4323 ("newline", "hello\nworld"),
4324 ("cr", "hello\rworld"),
4325 ("backspace", "hello\u{08}world"),
4326 ("formfeed", "hello\u{0c}world"),
4327 ] {
4328 let decoded = root_obj
4329 .get(key)
4330 .unwrap()
4331 .value()
4332 .unwrap()
4333 .as_string_lit()
4334 .unwrap()
4335 .decoded_value()
4336 .unwrap();
4337 assert_eq!(decoded, expected, "roundtrip failed for key: {}", key);
4338 }
4339 }
4340
4341 #[test]
4342 fn new_escaped_handles_quotes_and_backslashes_together() {
4343 let cst = build_cst(r#"{}"#);
4344 let root_obj = cst.object_value_or_create().unwrap();
4345
4346 root_obj.append("mixed", json!("say \"hello\\world\""));
4347
4348 let text = cst.to_string();
4349 assert!(
4350 text.contains(r#""say \"hello\\world\"""#),
4351 "mixed escaping failed: {}",
4352 text
4353 );
4354
4355 let decoded = root_obj
4356 .get("mixed")
4357 .unwrap()
4358 .value()
4359 .unwrap()
4360 .as_string_lit()
4361 .unwrap()
4362 .decoded_value()
4363 .unwrap();
4364 assert_eq!(decoded, "say \"hello\\world\"");
4365 }
4366
4367 #[test]
4368 fn new_escaped_in_array_values() {
4369 let cst = build_cst(r#"{"items": []}"#);
4370 let root_obj = cst.object_value().unwrap();
4371 let arr = root_obj.array_value("items").unwrap();
4372
4373 arr.append(json!("path\\to\\file"));
4374 arr.append(json!("line1\nline2"));
4375
4376 let text = cst.to_string();
4377 assert!(
4378 text.contains(r#""path\\to\\file""#),
4379 "backslash in array element: {}",
4380 text
4381 );
4382 assert!(text.contains(r#""line1\nline2""#), "newline in array element: {}", text);
4383 }
4384
4385 #[test]
4386 fn new_escaped_property_name_with_special_chars() {
4387 let cst = build_cst(r#"{}"#);
4388 let root_obj = cst.object_value_or_create().unwrap();
4389
4390 root_obj.append("key\\with\\backslash", json!("value"));
4391
4392 let text = cst.to_string();
4393 assert!(
4394 text.contains(r#""key\\with\\backslash""#),
4395 "property name escaping failed: {}",
4396 text
4397 );
4398
4399 let decoded = root_obj
4400 .properties()
4401 .first()
4402 .unwrap()
4403 .name()
4404 .unwrap()
4405 .decoded_value()
4406 .unwrap();
4407 assert_eq!(decoded, "key\\with\\backslash");
4408 }
4409}