1use std::cell::RefCell;
37use std::cmp::Ordering;
38use std::collections::VecDeque;
39use std::fmt::Display;
40use std::iter::Peekable;
41use std::ops::Range;
42use std::rc::Rc;
43use std::rc::Weak;
44
45use super::common::Ranged;
46use crate::ParseOptions;
47use crate::ast;
48use crate::errors::ParseError;
49use crate::parse_to_ast;
50use crate::string::ParseStringErrorKind;
51
52mod input;
53
54pub use input::*;
55
56macro_rules! add_root_node_method {
57 () => {
58 pub fn root_node(&self) -> Option<CstRootNode> {
63 self
64 .ancestors()
65 .filter_map(|parent| match parent {
66 CstContainerNode::Root(node) => Some(node),
67 _ => None,
68 })
69 .next()
70 }
71 };
72}
73
74macro_rules! add_parent_info_methods {
75 () => {
76 pub fn parent(&self) -> Option<CstContainerNode> {
81 self.parent_info().map(|p| p.parent.as_container_node())
82 }
83
84 pub fn ancestors(&self) -> impl Iterator<Item = CstContainerNode> {
86 AncestorIterator::new(self.clone().into())
87 }
88
89 pub fn child_index(&self) -> usize {
92 self.parent_info().map(|p| p.child_index).unwrap_or(0)
93 }
94
95 pub fn previous_sibling(&self) -> Option<CstNode> {
97 let parent_info = self.parent_info()?;
98 if parent_info.child_index == 0 {
99 return None;
100 }
101 parent_info
102 .parent
103 .as_container_node()
104 .child_at_index(parent_info.child_index - 1)
105 }
106
107 pub fn previous_siblings(&self) -> impl Iterator<Item = CstNode> {
110 PreviousSiblingIterator::new(self.clone().into())
111 }
112
113 pub fn next_sibling(&self) -> Option<CstNode> {
115 let parent_info = self.parent_info()?;
116 parent_info
117 .parent
118 .as_container_node()
119 .child_at_index(parent_info.child_index + 1)
120 }
121
122 pub fn next_siblings(&self) -> impl Iterator<Item = CstNode> {
125 NextSiblingIterator::new(self.clone().into())
126 }
127
128 pub fn indent_text(&self) -> Option<String> {
130 indent_text(&self.clone().into())
131 }
132
133 pub fn has_blank_line_before(&self) -> bool {
136 has_blank_line_before(&self.clone().into())
137 }
138
139 pub fn trailing_comma(&self) -> Option<CstToken> {
141 find_trailing_comma(&self.clone().into())
142 }
143
144 pub fn uses_trailing_commas(&self) -> bool {
146 uses_trailing_commas(self.clone().into())
147 }
148 };
149}
150
151fn has_blank_line_before(node: &CstNode) -> bool {
154 has_blank_line(node.previous_siblings().take_while(|n| n.is_trivia()))
155}
156
157fn find_trailing_comma(node: &CstNode) -> Option<CstToken> {
158 for next_sibling in node.next_siblings() {
159 match next_sibling {
160 CstNode::Container(_) => return None,
161 CstNode::Leaf(leaf) => match leaf {
162 CstLeafNode::BooleanLit(_)
163 | CstLeafNode::NullKeyword(_)
164 | CstLeafNode::NumberLit(_)
165 | CstLeafNode::StringLit(_)
166 | CstLeafNode::WordLit(_) => return None,
167 CstLeafNode::Token(token) => {
168 if token.value() == ',' {
169 return Some(token);
170 } else {
171 return None;
172 }
173 }
174 CstLeafNode::Whitespace(_) | CstLeafNode::Newline(_) | CstLeafNode::Comment(_) => {
175 }
177 },
178 }
179 }
180
181 None
182}
183
184macro_rules! add_parent_methods {
185 () => {
186 add_parent_info_methods!();
187
188 fn parent_info(&self) -> Option<ParentInfo> {
189 self.0.borrow().parent.clone()
190 }
191
192 fn set_parent(&self, parent: Option<ParentInfo>) {
193 self.0.borrow_mut().parent = parent;
194 }
195 };
196}
197
198macro_rules! impl_from_leaf_or_container {
199 ($node_name:ident, $variant:ident, $leaf_or_container:ident, $leaf_or_container_variant:ident) => {
200 impl From<$node_name> for CstNode {
201 fn from(value: $node_name) -> Self {
202 CstNode::$leaf_or_container_variant($leaf_or_container::$variant(value))
203 }
204 }
205
206 impl From<$node_name> for $leaf_or_container {
207 fn from(value: $node_name) -> Self {
208 $leaf_or_container::$variant(value)
209 }
210 }
211 };
212}
213
214macro_rules! impl_container_methods {
215 ($node_name:ident, $variant:ident) => {
216 impl_from_leaf_or_container!($node_name, $variant, CstContainerNode, Container);
217
218 impl $node_name {
219 add_parent_methods!();
220
221 pub fn children(&self) -> Vec<CstNode> {
223 self.0.borrow().value.clone()
224 }
225
226 pub fn children_exclude_trivia_and_tokens(&self) -> Vec<CstNode> {
228 self
229 .0
230 .borrow()
231 .value
232 .iter()
233 .filter(|n| !n.is_trivia() && !n.is_token())
234 .cloned()
235 .collect()
236 }
237
238 pub fn child_at_index(&self, index: usize) -> Option<CstNode> {
240 self.0.borrow().value.get(index).cloned()
241 }
242
243 fn remove_child_set_no_parent(&self, index: usize) {
244 let mut inner = self.0.borrow_mut();
245 if index < inner.value.len() {
246 let container = self.clone().into();
247 let child = inner.value.remove(index);
248 child.set_parent(None);
249
250 for index in index..inner.value.len() {
252 inner.value[index].set_parent(Some(ParentInfo {
253 parent: WeakParent::from_container(&container),
254 child_index: index,
255 }));
256 }
257 }
258 }
259 }
260 };
261}
262
263macro_rules! impl_leaf_methods {
264 ($node_name:ident, $variant:ident) => {
265 impl_from_leaf_or_container!($node_name, $variant, CstLeafNode, Leaf);
266
267 impl $node_name {
268 add_parent_methods!();
269 add_root_node_method!();
270 }
271 };
272}
273
274#[derive(Debug, Clone)]
275enum WeakParent {
276 Root(Weak<CstRootNodeInner>),
277 Object(Weak<CstObjectInner>),
278 ObjectProp(Weak<CstObjectPropInner>),
279 Array(Weak<CstArrayInner>),
280}
281
282impl WeakParent {
283 pub fn from_container(container: &CstContainerNode) -> Self {
284 match container {
285 CstContainerNode::Root(node) => WeakParent::Root(Rc::downgrade(&node.0)),
286 CstContainerNode::Object(node) => WeakParent::Object(Rc::downgrade(&node.0)),
287 CstContainerNode::ObjectProp(node) => WeakParent::ObjectProp(Rc::downgrade(&node.0)),
288 CstContainerNode::Array(node) => WeakParent::Array(Rc::downgrade(&node.0)),
289 }
290 }
291
292 pub fn as_container_node(&self) -> CstContainerNode {
293 const PANIC_MSG: &str = "Programming error. Ensure you keep around the RootNode for the duration of using the CST.";
297 match self {
298 WeakParent::Root(weak) => CstRootNode(weak.upgrade().expect(PANIC_MSG)).into(),
299 WeakParent::Object(weak) => CstObject(weak.upgrade().expect(PANIC_MSG)).into(),
300 WeakParent::ObjectProp(weak) => CstObjectProp(weak.upgrade().expect(PANIC_MSG)).into(),
301 WeakParent::Array(weak) => CstArray(weak.upgrade().expect(PANIC_MSG)).into(),
302 }
303 }
304}
305
306#[derive(Clone, Debug)]
307struct ParentInfo {
308 pub parent: WeakParent,
309 pub child_index: usize,
310}
311
312#[derive(Debug)]
313struct CstValueInner<T> {
314 parent: Option<ParentInfo>,
315 value: T,
316}
317
318impl<T> CstValueInner<T> {
319 fn new(value: T) -> Rc<RefCell<Self>> {
320 Rc::new(RefCell::new(CstValueInner { parent: None, value }))
321 }
322}
323
324type CstChildrenInner = CstValueInner<Vec<CstNode>>;
325
326#[derive(Debug, Clone)]
328pub enum CstNode {
329 Container(CstContainerNode),
330 Leaf(CstLeafNode),
331}
332
333impl CstNode {
334 add_parent_info_methods!();
335 add_root_node_method!();
336
337 pub fn is_trivia(&self) -> bool {
339 match self {
340 CstNode::Leaf(leaf) => match leaf {
341 CstLeafNode::BooleanLit(_)
342 | CstLeafNode::NullKeyword(_)
343 | CstLeafNode::NumberLit(_)
344 | CstLeafNode::StringLit(_)
345 | CstLeafNode::Token(_)
346 | CstLeafNode::WordLit(_) => false,
347 CstLeafNode::Whitespace(_) | CstLeafNode::Newline(_) | CstLeafNode::Comment(_) => true,
348 },
349 CstNode::Container(_) => false,
350 }
351 }
352
353 pub fn leading_comments_same_line(&self) -> impl Iterator<Item = CstComment> {
355 self
356 .previous_siblings()
357 .take_while(|n| n.is_whitespace() || n.is_comment())
358 .filter_map(|n| match n {
359 CstNode::Leaf(CstLeafNode::Comment(comment)) => Some(comment.clone()),
360 _ => None,
361 })
362 }
363
364 pub fn trailing_comments_same_line(&self) -> impl Iterator<Item = CstComment> {
368 for sibling in self.next_siblings() {
370 if sibling.is_newline() {
371 break;
372 } else if !sibling.is_comment() && !sibling.is_whitespace() {
373 return Box::new(std::iter::empty()) as Box<dyn Iterator<Item = CstComment>>;
374 }
375 }
376
377 Box::new(
378 self
379 .next_siblings()
380 .take_while(|n| n.is_whitespace() || n.is_comment())
381 .filter_map(|n| match n {
382 CstNode::Leaf(CstLeafNode::Comment(comment)) => Some(comment.clone()),
383 _ => None,
384 }),
385 )
386 }
387
388 pub fn is_newline(&self) -> bool {
390 matches!(self, CstNode::Leaf(CstLeafNode::Newline(_)))
391 }
392
393 pub fn is_comma(&self) -> bool {
395 match self {
396 CstNode::Leaf(CstLeafNode::Token(t)) => t.value() == ',',
397 _ => false,
398 }
399 }
400
401 pub fn is_comment(&self) -> bool {
403 matches!(self, CstNode::Leaf(CstLeafNode::Comment(_)))
404 }
405
406 pub fn is_token(&self) -> bool {
408 matches!(self, CstNode::Leaf(CstLeafNode::Token(_)))
409 }
410
411 pub fn is_whitespace(&self) -> bool {
413 matches!(self, CstNode::Leaf(CstLeafNode::Whitespace(_)))
414 }
415
416 pub fn token_char(&self) -> Option<char> {
418 match self {
419 CstNode::Leaf(CstLeafNode::Token(token)) => Some(token.value()),
420 _ => None,
421 }
422 }
423
424 pub fn children(&self) -> Vec<CstNode> {
426 match self {
427 CstNode::Container(n) => n.children(),
428 CstNode::Leaf(_) => Vec::new(),
429 }
430 }
431
432 pub fn children_exclude_trivia_and_tokens(&self) -> Vec<CstNode> {
434 match self {
435 CstNode::Container(n) => n.children_exclude_trivia_and_tokens(),
436 CstNode::Leaf(_) => Vec::new(),
437 }
438 }
439
440 pub fn child_at_index(&self, index: usize) -> Option<CstNode> {
442 match self {
443 CstNode::Container(n) => n.child_at_index(index),
444 CstNode::Leaf(_) => None,
445 }
446 }
447
448 pub fn element_index(&self) -> Option<usize> {
452 let child_index = self.child_index();
453 let array = self.parent()?.as_array()?;
454 array.elements().iter().position(|p| p.child_index() == child_index)
455 }
456
457 pub fn as_root_node(&self) -> Option<CstRootNode> {
459 match self {
460 CstNode::Container(CstContainerNode::Root(node)) => Some(node.clone()),
461 _ => None,
462 }
463 }
464
465 pub fn as_object(&self) -> Option<CstObject> {
467 match self {
468 CstNode::Container(CstContainerNode::Object(node)) => Some(node.clone()),
470 _ => None,
471 }
472 }
473
474 pub fn as_array(&self) -> Option<CstArray> {
476 match self {
477 CstNode::Container(CstContainerNode::Array(node)) => Some(node.clone()),
478 _ => None,
479 }
480 }
481
482 pub fn as_object_prop(&self) -> Option<CstObjectProp> {
484 match self {
485 CstNode::Container(CstContainerNode::ObjectProp(node)) => Some(node.clone()),
486 _ => None,
487 }
488 }
489
490 pub fn as_boolean_lit(&self) -> Option<CstBooleanLit> {
492 match self {
493 CstNode::Leaf(CstLeafNode::BooleanLit(node)) => Some(node.clone()),
494 _ => None,
495 }
496 }
497
498 pub fn as_null_keyword(&self) -> Option<CstNullKeyword> {
500 match self {
501 CstNode::Leaf(CstLeafNode::NullKeyword(node)) => Some(node.clone()),
502 _ => None,
503 }
504 }
505
506 pub fn as_number_lit(&self) -> Option<CstNumberLit> {
508 match self {
509 CstNode::Leaf(CstLeafNode::NumberLit(node)) => Some(node.clone()),
510 _ => None,
511 }
512 }
513
514 pub fn as_string_lit(&self) -> Option<CstStringLit> {
516 match self {
517 CstNode::Leaf(CstLeafNode::StringLit(node)) => Some(node.clone()),
518 _ => None,
519 }
520 }
521
522 pub fn as_word_lit(&self) -> Option<CstWordLit> {
524 match self {
525 CstNode::Leaf(CstLeafNode::WordLit(node)) => Some(node.clone()),
526 _ => None,
527 }
528 }
529
530 pub fn as_token(&self) -> Option<CstToken> {
532 match self {
533 CstNode::Leaf(CstLeafNode::Token(node)) => Some(node.clone()),
534 _ => None,
535 }
536 }
537
538 pub fn as_newline(&self) -> Option<CstNewline> {
540 match self {
541 CstNode::Leaf(CstLeafNode::Newline(node)) => Some(node.clone()),
542 _ => None,
543 }
544 }
545
546 pub fn as_whitespace(&self) -> Option<CstWhitespace> {
548 match self {
549 CstNode::Leaf(CstLeafNode::Whitespace(node)) => Some(node.clone()),
550 _ => None,
551 }
552 }
553
554 pub fn as_comment(&self) -> Option<CstComment> {
556 match self {
557 CstNode::Leaf(CstLeafNode::Comment(node)) => Some(node.clone()),
558 _ => None,
559 }
560 }
561
562 pub fn remove(self) {
566 match self {
567 CstNode::Container(n) => n.remove(),
568 CstNode::Leaf(n) => n.remove(),
569 }
570 }
571
572 fn parent_info(&self) -> Option<ParentInfo> {
573 match self {
574 CstNode::Container(node) => node.parent_info(),
575 CstNode::Leaf(node) => node.parent_info(),
576 }
577 }
578
579 fn set_parent(&self, parent: Option<ParentInfo>) {
580 match self {
581 CstNode::Container(node) => node.set_parent(parent),
582 CstNode::Leaf(node) => node.set_parent(parent),
583 }
584 }
585
586 fn remove_raw(self) {
588 let Some(parent_info) = self.parent_info() else {
589 return; };
591 parent_info
592 .parent
593 .as_container_node()
594 .remove_child_set_no_parent(parent_info.child_index);
595 }
596
597 #[cfg(feature = "serde_json")]
619 pub fn to_serde_value(&self) -> Option<serde_json::Value> {
620 match self {
621 CstNode::Container(container) => container.to_serde_value(),
622 CstNode::Leaf(leaf) => leaf.to_serde_value(),
623 }
624 }
625}
626
627impl Display for CstNode {
628 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
629 match self {
630 CstNode::Container(node) => node.fmt(f),
631 CstNode::Leaf(node) => node.fmt(f),
632 }
633 }
634}
635
636#[derive(Default, Debug, Clone)]
637struct StyleInfo {
638 pub uses_trailing_commas: bool,
639 pub newline_kind: CstNewlineKind,
640}
641
642#[derive(Debug, Clone)]
644pub enum CstContainerNode {
645 Root(CstRootNode),
646 Array(CstArray),
647 Object(CstObject),
648 ObjectProp(CstObjectProp),
649}
650
651impl CstContainerNode {
652 add_parent_info_methods!();
653 add_root_node_method!();
654
655 pub fn is_root(&self) -> bool {
657 matches!(self, CstContainerNode::Root(_))
658 }
659
660 pub fn is_array(&self) -> bool {
662 matches!(self, CstContainerNode::Array(_))
663 }
664
665 pub fn is_object(&self) -> bool {
667 matches!(self, CstContainerNode::Object(_))
668 }
669
670 pub fn is_object_prop(&self) -> bool {
672 matches!(self, CstContainerNode::ObjectProp(_))
673 }
674
675 pub fn as_root(&self) -> Option<CstRootNode> {
677 match self {
678 CstContainerNode::Root(node) => Some(node.clone()),
679 _ => None,
680 }
681 }
682
683 pub fn as_array(&self) -> Option<CstArray> {
685 match self {
686 CstContainerNode::Array(node) => Some(node.clone()),
687 _ => None,
688 }
689 }
690
691 pub fn as_object(&self) -> Option<CstObject> {
693 match self {
694 CstContainerNode::Object(node) => Some(node.clone()),
695 _ => None,
696 }
697 }
698
699 pub fn as_object_prop(&self) -> Option<CstObjectProp> {
701 match self {
702 CstContainerNode::ObjectProp(node) => Some(node.clone()),
703 _ => None,
704 }
705 }
706
707 pub fn children(&self) -> Vec<CstNode> {
709 match self {
710 CstContainerNode::Root(n) => n.children(),
711 CstContainerNode::Object(n) => n.children(),
712 CstContainerNode::ObjectProp(n) => n.children(),
713 CstContainerNode::Array(n) => n.children(),
714 }
715 }
716
717 pub fn children_exclude_trivia_and_tokens(&self) -> Vec<CstNode> {
719 match self {
720 CstContainerNode::Root(n) => n.children_exclude_trivia_and_tokens(),
721 CstContainerNode::Object(n) => n.children_exclude_trivia_and_tokens(),
722 CstContainerNode::ObjectProp(n) => n.children_exclude_trivia_and_tokens(),
723 CstContainerNode::Array(n) => n.children_exclude_trivia_and_tokens(),
724 }
725 }
726
727 pub fn child_at_index(&self, index: usize) -> Option<CstNode> {
729 match self {
730 CstContainerNode::Root(node) => node.child_at_index(index),
731 CstContainerNode::Object(node) => node.child_at_index(index),
732 CstContainerNode::ObjectProp(node) => node.child_at_index(index),
733 CstContainerNode::Array(node) => node.child_at_index(index),
734 }
735 }
736
737 fn remove_child_set_no_parent(&self, index: usize) {
738 match self {
739 CstContainerNode::Root(n) => n.remove_child_set_no_parent(index),
740 CstContainerNode::Object(n) => n.remove_child_set_no_parent(index),
741 CstContainerNode::ObjectProp(n) => n.remove_child_set_no_parent(index),
742 CstContainerNode::Array(n) => n.remove_child_set_no_parent(index),
743 }
744 }
745
746 pub fn remove(self) {
748 match self {
749 CstContainerNode::Root(n) => n.clear_children(),
750 CstContainerNode::Object(n) => n.remove(),
751 CstContainerNode::ObjectProp(n) => n.remove(),
752 CstContainerNode::Array(n) => n.remove(),
753 }
754 }
755
756 fn parent_info(&self) -> Option<ParentInfo> {
757 match self {
758 CstContainerNode::Root(node) => node.parent_info(),
759 CstContainerNode::Object(node) => node.parent_info(),
760 CstContainerNode::ObjectProp(node) => node.parent_info(),
761 CstContainerNode::Array(node) => node.parent_info(),
762 }
763 }
764
765 fn set_parent(&self, parent: Option<ParentInfo>) {
766 match self {
767 CstContainerNode::Root(node) => node.set_parent(parent),
768 CstContainerNode::Object(node) => node.set_parent(parent),
769 CstContainerNode::ObjectProp(node) => node.set_parent(parent),
770 CstContainerNode::Array(node) => node.set_parent(parent),
771 }
772 }
773
774 #[inline(always)]
775 fn raw_append_child(&self, child: CstNode) {
776 self.raw_insert_child(None, child);
777 }
778
779 #[inline(always)]
780 fn raw_insert_child(&self, index: Option<&mut usize>, child: CstNode) {
781 self.raw_insert_children(index, vec![child]);
782 }
783
784 #[inline(always)]
785 fn raw_append_children(&self, children: Vec<CstNode>) {
786 self.raw_insert_children(None, children);
787 }
788
789 fn raw_set_children(&self, children: Vec<CstNode>) {
791 let weak_parent = WeakParent::from_container(self);
792 let mut container = match self {
793 CstContainerNode::Root(node) => node.0.borrow_mut(),
794 CstContainerNode::Object(node) => node.0.borrow_mut(),
795 CstContainerNode::ObjectProp(node) => node.0.borrow_mut(),
796 CstContainerNode::Array(node) => node.0.borrow_mut(),
797 };
798 for child in &container.value {
800 child.set_parent(None);
801 }
802 container.value = children;
803 for (i, child) in container.value.iter().enumerate() {
804 child.set_parent(Some(ParentInfo {
805 parent: weak_parent.clone(),
806 child_index: i,
807 }));
808 }
809 }
810
811 fn raw_insert_children(&self, index: Option<&mut usize>, children: Vec<CstNode>) {
812 if children.is_empty() {
813 return;
814 }
815
816 let weak_parent = WeakParent::from_container(self);
817 let mut container = match self {
818 CstContainerNode::Root(node) => node.0.borrow_mut(),
819 CstContainerNode::Object(node) => node.0.borrow_mut(),
820 CstContainerNode::ObjectProp(node) => node.0.borrow_mut(),
821 CstContainerNode::Array(node) => node.0.borrow_mut(),
822 };
823 let insert_index = index.as_ref().map(|i| **i).unwrap_or(container.value.len());
824 if let Some(i) = index {
825 *i += children.len();
826 }
827 container.value.splice(insert_index..insert_index, children);
828
829 for (i, child) in container.value.iter().enumerate().skip(insert_index) {
831 child.set_parent(Some(ParentInfo {
832 parent: weak_parent.clone(),
833 child_index: i,
834 }));
835 }
836 }
837
838 fn raw_insert_value_with_internal_indent(
839 &self,
840 insert_index: Option<&mut usize>,
841 value: InsertValue,
842 style_info: &StyleInfo,
843 indents: &Indents,
844 ) {
845 match value {
846 InsertValue::Value(value) => {
847 let is_multiline = value.force_multiline();
848 match value {
849 CstInputValue::Null => {
850 self.raw_insert_child(insert_index, CstLeafNode::NullKeyword(CstNullKeyword::new()).into());
851 }
852 CstInputValue::Bool(value) => {
853 self.raw_insert_child(insert_index, CstLeafNode::BooleanLit(CstBooleanLit::new(value)).into());
854 }
855 CstInputValue::Number(value) => {
856 self.raw_insert_child(insert_index, CstLeafNode::NumberLit(CstNumberLit::new(value)).into());
857 }
858 CstInputValue::String(value) => {
859 self.raw_insert_child(
860 insert_index,
861 CstLeafNode::StringLit(CstStringLit::new_escaped(&value)).into(),
862 );
863 }
864 CstInputValue::Array(elements) => {
865 let array_node: CstContainerNode = CstArray::new_no_tokens().into();
866 self.raw_insert_child(insert_index, array_node.clone().into());
867
868 array_node.raw_append_child(CstToken::new('[').into());
869 if !elements.is_empty() {
870 let indents = indents.indent();
871 let mut elements = elements.into_iter().peekable();
872 while let Some(value) = elements.next() {
873 if is_multiline {
874 array_node.raw_insert_children(
875 None,
876 vec![
877 CstNewline::new(style_info.newline_kind).into(),
878 CstWhitespace::new(indents.current_indent.clone()).into(),
879 ],
880 );
881 }
882
883 array_node.raw_insert_value_with_internal_indent(None, InsertValue::Value(value), style_info, &indents);
884
885 if style_info.uses_trailing_commas && is_multiline || elements.peek().is_some() {
886 if is_multiline {
887 array_node.raw_append_child(CstToken::new(',').into());
888 } else {
889 array_node.raw_insert_children(
890 None,
891 vec![CstToken::new(',').into(), CstWhitespace::new(" ".to_string()).into()],
892 );
893 }
894 }
895 }
896 }
897
898 if is_multiline {
899 array_node.raw_append_children(vec![
900 CstNewline::new(style_info.newline_kind).into(),
901 CstWhitespace::new(indents.current_indent.clone()).into(),
902 ]);
903 }
904
905 array_node.raw_append_child(CstToken::new(']').into());
906 }
907 CstInputValue::Object(properties) => {
908 let object_node: CstContainerNode = CstObject::new_no_tokens().into();
909 self.raw_insert_child(insert_index, object_node.clone().into());
910
911 object_node.raw_append_child(CstToken::new('{').into());
912
913 if !properties.is_empty() {
914 {
915 let indents = indents.indent();
916 let mut properties = properties.into_iter().peekable();
917 while let Some((prop_name, value)) = properties.next() {
918 object_node.raw_append_child(CstNewline::new(style_info.newline_kind).into());
919 object_node.raw_append_child(CstWhitespace::new(indents.current_indent.clone()).into());
920 object_node.raw_insert_value_with_internal_indent(
921 None,
922 InsertValue::Property(&prop_name, value),
923 style_info,
924 &indents,
925 );
926 if style_info.uses_trailing_commas || properties.peek().is_some() {
927 object_node.raw_append_child(CstToken::new(',').into());
928 }
929 }
930 }
931
932 object_node.raw_append_children(vec![
933 CstNewline::new(style_info.newline_kind).into(),
934 CstWhitespace::new(indents.current_indent.clone()).into(),
935 ]);
936 }
937
938 object_node.raw_append_child(CstToken::new('}').into());
939 }
940 }
941 }
942 InsertValue::Property(prop_name, value) => {
943 let prop = CstContainerNode::ObjectProp(CstObjectProp::new());
944 self.raw_insert_child(insert_index, prop.clone().into());
945 prop.raw_insert_children(
946 None,
947 vec![
948 CstStringLit::new_escaped(prop_name).into(),
949 CstToken::new(':').into(),
950 CstWhitespace::new(" ".to_string()).into(),
951 ],
952 );
953 prop.raw_insert_value_with_internal_indent(None, InsertValue::Value(value), style_info, indents);
954 }
955 }
956 }
957
958 #[cfg(feature = "serde_json")]
962 pub fn to_serde_value(&self) -> Option<serde_json::Value> {
963 match self {
964 CstContainerNode::Root(node) => node.to_serde_value(),
965 CstContainerNode::Array(node) => node.to_serde_value(),
966 CstContainerNode::Object(node) => node.to_serde_value(),
967 CstContainerNode::ObjectProp(node) => node.to_serde_value(),
968 }
969 }
970}
971
972impl From<CstContainerNode> for CstNode {
973 fn from(value: CstContainerNode) -> Self {
974 CstNode::Container(value)
975 }
976}
977
978impl Display for CstContainerNode {
979 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
980 match self {
981 CstContainerNode::Root(node) => node.fmt(f),
982 CstContainerNode::Object(node) => node.fmt(f),
983 CstContainerNode::ObjectProp(node) => node.fmt(f),
984 CstContainerNode::Array(node) => node.fmt(f),
985 }
986 }
987}
988
989#[derive(Debug, Clone)]
991pub enum CstLeafNode {
992 BooleanLit(CstBooleanLit),
993 NullKeyword(CstNullKeyword),
994 NumberLit(CstNumberLit),
995 StringLit(CstStringLit),
996 WordLit(CstWordLit),
997 Token(CstToken),
998 Whitespace(CstWhitespace),
999 Newline(CstNewline),
1000 Comment(CstComment),
1001}
1002
1003impl CstLeafNode {
1004 add_parent_info_methods!();
1005 add_root_node_method!();
1006
1007 pub fn remove(self) {
1009 match self {
1010 CstLeafNode::BooleanLit(n) => n.remove(),
1011 CstLeafNode::NullKeyword(n) => n.remove(),
1012 CstLeafNode::NumberLit(n) => n.remove(),
1013 CstLeafNode::StringLit(n) => n.remove(),
1014 CstLeafNode::WordLit(n) => n.remove(),
1015 CstLeafNode::Token(n) => n.remove(),
1016 CstLeafNode::Whitespace(n) => n.remove(),
1017 CstLeafNode::Newline(n) => n.remove(),
1018 CstLeafNode::Comment(n) => n.remove(),
1019 }
1020 }
1021
1022 fn parent_info(&self) -> Option<ParentInfo> {
1023 match self {
1024 CstLeafNode::BooleanLit(node) => node.parent_info(),
1025 CstLeafNode::NullKeyword(node) => node.parent_info(),
1026 CstLeafNode::NumberLit(node) => node.parent_info(),
1027 CstLeafNode::StringLit(node) => node.parent_info(),
1028 CstLeafNode::WordLit(node) => node.parent_info(),
1029 CstLeafNode::Token(node) => node.parent_info(),
1030 CstLeafNode::Whitespace(node) => node.parent_info(),
1031 CstLeafNode::Newline(node) => node.parent_info(),
1032 CstLeafNode::Comment(node) => node.parent_info(),
1033 }
1034 }
1035
1036 fn set_parent(&self, parent: Option<ParentInfo>) {
1037 match self {
1038 CstLeafNode::BooleanLit(node) => node.set_parent(parent),
1039 CstLeafNode::NullKeyword(node) => node.set_parent(parent),
1040 CstLeafNode::NumberLit(node) => node.set_parent(parent),
1041 CstLeafNode::StringLit(node) => node.set_parent(parent),
1042 CstLeafNode::WordLit(node) => node.set_parent(parent),
1043 CstLeafNode::Token(node) => node.set_parent(parent),
1044 CstLeafNode::Whitespace(node) => node.set_parent(parent),
1045 CstLeafNode::Newline(node) => node.set_parent(parent),
1046 CstLeafNode::Comment(node) => node.set_parent(parent),
1047 }
1048 }
1049
1050 #[cfg(feature = "serde_json")]
1054 pub fn to_serde_value(&self) -> Option<serde_json::Value> {
1055 match self {
1056 CstLeafNode::BooleanLit(node) => node.to_serde_value(),
1057 CstLeafNode::NullKeyword(node) => node.to_serde_value(),
1058 CstLeafNode::NumberLit(node) => node.to_serde_value(),
1059 CstLeafNode::StringLit(node) => node.to_serde_value(),
1060 CstLeafNode::WordLit(_)
1061 | CstLeafNode::Token(_)
1062 | CstLeafNode::Whitespace(_)
1063 | CstLeafNode::Newline(_)
1064 | CstLeafNode::Comment(_) => None,
1065 }
1066 }
1067}
1068
1069impl Display for CstLeafNode {
1070 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1071 match self {
1072 CstLeafNode::BooleanLit(node) => node.fmt(f),
1073 CstLeafNode::NullKeyword(node) => node.fmt(f),
1074 CstLeafNode::NumberLit(node) => node.fmt(f),
1075 CstLeafNode::StringLit(node) => node.fmt(f),
1076 CstLeafNode::WordLit(node) => node.fmt(f),
1077 CstLeafNode::Token(node) => node.fmt(f),
1078 CstLeafNode::Whitespace(node) => node.fmt(f),
1079 CstLeafNode::Newline(node) => node.fmt(f),
1080 CstLeafNode::Comment(node) => node.fmt(f),
1081 }
1082 }
1083}
1084
1085impl From<CstLeafNode> for CstNode {
1086 fn from(value: CstLeafNode) -> Self {
1087 CstNode::Leaf(value)
1088 }
1089}
1090
1091#[derive(Default, Debug, Clone, Copy)]
1093pub enum TrailingCommaMode {
1094 #[default]
1096 Never,
1097 IfMultiline,
1099}
1100
1101type CstRootNodeInner = RefCell<CstChildrenInner>;
1102
1103#[derive(Debug, Clone)]
1107pub struct CstRootNode(Rc<CstRootNodeInner>);
1108
1109impl_container_methods!(CstRootNode, Root);
1110
1111impl CstRootNode {
1112 pub fn parse(text: &str, parse_options: &ParseOptions) -> Result<Self, ParseError> {
1147 let parse_result = parse_to_ast(
1148 text,
1149 &crate::CollectOptions {
1150 comments: crate::CommentCollectionStrategy::AsTokens,
1151 tokens: true,
1152 },
1153 parse_options,
1154 )?;
1155
1156 Ok(
1157 CstBuilder {
1158 text,
1159 tokens: parse_result.tokens.unwrap().into_iter().collect(),
1160 }
1161 .build(parse_result.value),
1162 )
1163 }
1164
1165 pub fn single_indent_text(&self) -> Option<String> {
1167 let root_value = self.value()?;
1168 let first_non_trivia_child = root_value.children_exclude_trivia_and_tokens().first()?.clone();
1169 let mut last_whitespace = None;
1170 for previous_trivia in first_non_trivia_child.previous_siblings() {
1171 match previous_trivia {
1172 CstNode::Leaf(CstLeafNode::Whitespace(whitespace)) => {
1173 last_whitespace = Some(whitespace);
1174 }
1175 CstNode::Leaf(CstLeafNode::Newline(_)) => {
1176 return last_whitespace.map(|whitespace| whitespace.0.borrow().value.clone());
1177 }
1178 _ => {
1179 last_whitespace = None;
1180 }
1181 }
1182 }
1183 None
1184 }
1185
1186 pub fn newline_kind(&self) -> CstNewlineKind {
1188 let mut current_children: VecDeque<CstContainerNode> = VecDeque::from([self.clone().into()]);
1189 while let Some(child) = current_children.pop_front() {
1190 for child in child.children() {
1191 if let CstNode::Container(child) = child {
1192 current_children.push_back(child);
1193 } else if let CstNode::Leaf(CstLeafNode::Newline(node)) = child {
1194 return node.kind();
1195 }
1196 }
1197 }
1198 CstNewlineKind::LineFeed
1199 }
1200
1201 pub fn value(&self) -> Option<CstNode> {
1203 for child in &self.0.borrow().value {
1204 if !child.is_trivia() {
1205 return Some(child.clone());
1206 }
1207 }
1208 None
1209 }
1210
1211 pub fn set_value(&self, root_value: CstInputValue) {
1213 let container: CstContainerNode = self.clone().into();
1214 let style_info = StyleInfo {
1215 newline_kind: self.newline_kind(),
1216 uses_trailing_commas: uses_trailing_commas(self.clone().into()),
1217 };
1218 let indents = compute_indents(&self.clone().into());
1219 let mut insert_index = if let Some(root_value) = self.value() {
1220 let index = root_value.child_index();
1221 root_value.remove_raw();
1222 index
1223 } else {
1224 let children = self.children();
1225 let mut index = match children.last() {
1226 Some(CstNode::Leaf(CstLeafNode::Newline(_))) => children.len() - 1,
1227 _ => children.len(),
1228 };
1229 let previous_node = if index == 0 { None } else { children.get(index - 1) };
1230 if let Some(CstNode::Leaf(CstLeafNode::Comment(_))) = previous_node {
1231 container.raw_insert_child(Some(&mut index), CstNewline::new(style_info.newline_kind).into());
1233 }
1234 if self.child_at_index(index).is_none() {
1235 container.raw_insert_child(Some(&mut index), CstNewline::new(style_info.newline_kind).into());
1237 index -= 1;
1238 }
1239 index
1240 };
1241 container.raw_insert_value_with_internal_indent(
1242 Some(&mut insert_index),
1243 InsertValue::Value(root_value),
1244 &style_info,
1245 &indents,
1246 );
1247 }
1248
1249 pub fn object_value(&self) -> Option<CstObject> {
1251 self.value()?.as_object()
1252 }
1253
1254 pub fn object_value_or_create(&self) -> Option<CstObject> {
1260 match self.value() {
1261 Some(CstNode::Container(CstContainerNode::Object(node))) => Some(node),
1262 Some(_) => None,
1263 None => {
1264 self.set_value(CstInputValue::Object(Vec::new()));
1265 self.object_value()
1266 }
1267 }
1268 }
1269
1270 pub fn object_value_or_set(&self) -> CstObject {
1275 match self.value() {
1276 Some(CstNode::Container(CstContainerNode::Object(node))) => node,
1277 _ => {
1278 self.set_value(CstInputValue::Object(Vec::new()));
1279 self.object_value().unwrap()
1280 }
1281 }
1282 }
1283
1284 pub fn array_value(&self) -> Option<CstArray> {
1286 self.value()?.as_array()
1287 }
1288
1289 pub fn array_value_or_create(&self) -> Option<CstArray> {
1295 match self.value() {
1296 Some(CstNode::Container(CstContainerNode::Array(node))) => Some(node),
1297 Some(_) => None,
1298 None => {
1299 self.set_value(CstInputValue::Array(Vec::new()));
1300 self.array_value()
1301 }
1302 }
1303 }
1304
1305 pub fn array_value_or_set(&self) -> CstArray {
1310 match self.value() {
1311 Some(CstNode::Container(CstContainerNode::Array(node))) => node,
1312 _ => {
1313 self.set_value(CstInputValue::Array(Vec::new()));
1314 self.array_value().unwrap()
1315 }
1316 }
1317 }
1318
1319 pub fn set_trailing_commas(&self, mode: TrailingCommaMode) {
1325 let Some(value) = self.value() else {
1326 return;
1327 };
1328
1329 match value {
1330 CstNode::Container(container) => match container {
1331 CstContainerNode::Array(n) => n.set_trailing_commas(mode),
1332 CstContainerNode::Object(n) => n.set_trailing_commas(mode),
1333 _ => {}
1334 },
1335 CstNode::Leaf(_) => {}
1336 }
1337 }
1338
1339 pub fn clear_children(&self) {
1341 let children = std::mem::take(&mut self.0.borrow_mut().value);
1342 for child in children {
1343 child.set_parent(None);
1344 }
1345 }
1346
1347 #[cfg(feature = "serde_json")]
1351 pub fn to_serde_value(&self) -> Option<serde_json::Value> {
1352 self.value()?.to_serde_value()
1353 }
1354}
1355
1356impl Display for CstRootNode {
1357 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1358 for child in &self.0.borrow().value {
1359 write!(f, "{}", child)?;
1360 }
1361 Ok(())
1362 }
1363}
1364
1365#[derive(Debug, Clone)]
1367pub struct CstStringLit(Rc<RefCell<CstValueInner<String>>>);
1368
1369impl_leaf_methods!(CstStringLit, StringLit);
1370
1371impl CstStringLit {
1372 fn new(value: String) -> Self {
1373 Self(CstValueInner::new(value))
1374 }
1375
1376 fn new_escaped(value: &str) -> Self {
1377 let mut escaped = String::with_capacity(value.len() + 2);
1378 escaped.push('"');
1379 for ch in value.chars() {
1380 match ch {
1381 '"' => escaped.push_str("\\\""),
1382 '\\' => escaped.push_str("\\\\"),
1383 '\u{08}' => escaped.push_str("\\b"),
1384 '\u{0c}' => escaped.push_str("\\f"),
1385 '\n' => escaped.push_str("\\n"),
1386 '\r' => escaped.push_str("\\r"),
1387 '\t' => escaped.push_str("\\t"),
1388 c if c.is_control() => {
1389 escaped.push_str(&format!("\\u{:04x}", c as u32));
1390 }
1391 c => escaped.push(c),
1392 }
1393 }
1394 escaped.push('"');
1395 Self::new(escaped)
1396 }
1397
1398 pub fn set_raw_value(&self, value: String) {
1400 self.0.borrow_mut().value = value;
1401 }
1402
1403 pub fn raw_value(&self) -> String {
1405 self.0.borrow().value.clone()
1406 }
1407
1408 pub fn decoded_value(&self) -> Result<String, ParseStringErrorKind> {
1410 let inner = self.0.borrow();
1411 crate::string::parse_string(&inner.value)
1412 .map(|value| value.into_owned())
1413 .map_err(|err| err.kind)
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 #[cfg(feature = "serde_json")]
1428 pub fn to_serde_value(&self) -> Option<serde_json::Value> {
1429 self.decoded_value().ok().map(serde_json::Value::String)
1430 }
1431}
1432
1433impl Display for CstStringLit {
1434 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1435 write!(f, "{}", self.0.borrow().value)
1436 }
1437}
1438
1439#[derive(Debug, Clone)]
1441pub struct CstWordLit(Rc<RefCell<CstValueInner<String>>>);
1442
1443impl_leaf_methods!(CstWordLit, WordLit);
1444
1445impl CstWordLit {
1446 fn new(value: String) -> Self {
1447 Self(CstValueInner::new(value))
1448 }
1449
1450 pub fn set_raw_value(&self, value: String) {
1452 self.0.borrow_mut().value = value;
1453 }
1454
1455 pub fn replace_with(self, replacement: CstInputValue) -> Option<CstNode> {
1457 replace_with(self.into(), InsertValue::Value(replacement))
1458 }
1459
1460 pub fn remove(self) {
1462 remove_comma_separated(self.into())
1463 }
1464}
1465
1466impl Display for CstWordLit {
1467 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1468 write!(f, "{}", self.0.borrow().value)
1469 }
1470}
1471
1472#[derive(Debug, Clone)]
1473pub struct CstNumberLit(Rc<RefCell<CstValueInner<String>>>);
1474
1475impl_leaf_methods!(CstNumberLit, NumberLit);
1476
1477impl CstNumberLit {
1478 fn new(value: String) -> Self {
1479 Self(CstValueInner::new(value))
1480 }
1481
1482 pub fn set_raw_value(&self, value: String) {
1484 self.0.borrow_mut().value = value;
1485 }
1486
1487 pub fn replace_with(self, replacement: CstInputValue) -> Option<CstNode> {
1489 replace_with(self.into(), InsertValue::Value(replacement))
1490 }
1491
1492 pub fn remove(self) {
1494 remove_comma_separated(self.into())
1495 }
1496
1497 #[cfg(feature = "serde_json")]
1499 pub fn to_serde_value(&self) -> Option<serde_json::Value> {
1500 use std::str::FromStr;
1501 let raw = self.0.borrow().value.clone();
1502
1503 let num_str = raw.trim_start_matches(['-', '+']);
1505 if num_str.len() > 2 && (num_str.starts_with("0x") || num_str.starts_with("0X")) {
1506 let hex_part = &num_str[2..];
1508 match i64::from_str_radix(hex_part, 16) {
1509 Ok(decimal_value) => {
1510 let final_value = if raw.starts_with('-') {
1511 -decimal_value
1512 } else {
1513 decimal_value
1514 };
1515 Some(serde_json::Value::Number(serde_json::Number::from(final_value)))
1516 }
1517 Err(_) => Some(serde_json::Value::String(raw)),
1518 }
1519 } else {
1520 let num_for_parsing = raw.trim_start_matches('+');
1522 match serde_json::Number::from_str(num_for_parsing) {
1523 Ok(number) => Some(serde_json::Value::Number(number)),
1524 Err(_) => Some(serde_json::Value::String(raw)),
1526 }
1527 }
1528 }
1529}
1530
1531impl Display for CstNumberLit {
1532 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1533 write!(f, "{}", self.0.borrow().value)
1534 }
1535}
1536
1537#[derive(Debug, Clone)]
1539pub struct CstBooleanLit(Rc<RefCell<CstValueInner<bool>>>);
1540
1541impl_leaf_methods!(CstBooleanLit, BooleanLit);
1542
1543impl CstBooleanLit {
1544 fn new(value: bool) -> Self {
1545 Self(CstValueInner::new(value))
1546 }
1547
1548 pub fn value(&self) -> bool {
1550 self.0.borrow().value
1551 }
1552
1553 pub fn set_value(&self, value: bool) {
1555 self.0.borrow_mut().value = value;
1556 }
1557
1558 pub fn replace_with(self, replacement: CstInputValue) -> Option<CstNode> {
1560 replace_with(self.into(), InsertValue::Value(replacement))
1561 }
1562
1563 pub fn remove(self) {
1565 remove_comma_separated(self.into())
1566 }
1567
1568 #[cfg(feature = "serde_json")]
1570 pub fn to_serde_value(&self) -> Option<serde_json::Value> {
1571 Some(serde_json::Value::Bool(self.value()))
1572 }
1573}
1574
1575impl Display for CstBooleanLit {
1576 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1577 if self.0.borrow().value {
1578 write!(f, "true")
1579 } else {
1580 write!(f, "false")
1581 }
1582 }
1583}
1584
1585#[derive(Debug, Clone)]
1587pub struct CstNullKeyword(Rc<RefCell<CstValueInner<()>>>);
1588
1589impl CstNullKeyword {
1590 fn new() -> Self {
1591 Self(CstValueInner::new(()))
1592 }
1593
1594 pub fn replace_with(self, replacement: CstInputValue) -> Option<CstNode> {
1596 replace_with(self.into(), InsertValue::Value(replacement))
1597 }
1598
1599 pub fn remove(self) {
1601 remove_comma_separated(self.into())
1602 }
1603
1604 #[cfg(feature = "serde_json")]
1606 pub fn to_serde_value(&self) -> Option<serde_json::Value> {
1607 Some(serde_json::Value::Null)
1608 }
1609}
1610
1611impl_leaf_methods!(CstNullKeyword, NullKeyword);
1612
1613impl Display for CstNullKeyword {
1614 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1615 write!(f, "null")
1616 }
1617}
1618
1619type CstObjectInner = RefCell<CstChildrenInner>;
1620
1621#[derive(Debug, Clone)]
1623pub struct CstObject(Rc<CstObjectInner>);
1624
1625impl_container_methods!(CstObject, Object);
1626
1627impl CstObject {
1628 add_root_node_method!();
1629
1630 fn new_no_tokens() -> Self {
1631 Self(CstValueInner::new(Vec::new()))
1632 }
1633
1634 fn new_with_tokens() -> Self {
1635 let object = CstObject::new_no_tokens();
1636 let container: CstContainerNode = object.clone().into();
1637 container.raw_append_children(vec![CstToken::new('{').into(), CstToken::new('}').into()]);
1638 object
1639 }
1640
1641 pub fn array_value(&self, name: &str) -> Option<CstArray> {
1645 match self.get(name)?.value()? {
1646 CstNode::Container(CstContainerNode::Array(node)) => Some(node),
1647 _ => None,
1648 }
1649 }
1650
1651 pub fn array_value_or_create(&self, name: &str) -> Option<CstArray> {
1658 match self.get(name) {
1659 Some(prop) => match prop.value()? {
1660 CstNode::Container(CstContainerNode::Array(node)) => Some(node),
1661 _ => None,
1662 },
1663 None => {
1664 self.append(name, CstInputValue::Array(Vec::new()));
1665 self.array_value(name)
1666 }
1667 }
1668 }
1669
1670 pub fn array_value_or_set(&self, name: &str) -> CstArray {
1675 match self.get(name) {
1676 Some(prop) => match prop.value() {
1677 Some(CstNode::Container(CstContainerNode::Array(node))) => node,
1678 Some(node) => {
1679 let mut index = node.child_index();
1680 node.remove_raw();
1681 let container: CstContainerNode = prop.clone().into();
1682 let array = CstArray::new_with_tokens();
1683 container.raw_insert_child(Some(&mut index), array.clone().into());
1684 array
1685 }
1686 _ => {
1687 let mut index = prop.children().len();
1688 let container: CstContainerNode = prop.clone().into();
1689 let array = CstArray::new_with_tokens();
1690 container.raw_insert_child(Some(&mut index), array.clone().into());
1691 array
1692 }
1693 },
1694 None => {
1695 self.append(name, CstInputValue::Array(Vec::new()));
1696 self.array_value(name).unwrap()
1697 }
1698 }
1699 }
1700
1701 pub fn object_value(&self, name: &str) -> Option<CstObject> {
1705 match self.get(name)?.value()? {
1706 CstNode::Container(CstContainerNode::Object(node)) => Some(node),
1707 _ => None,
1708 }
1709 }
1710
1711 pub fn object_value_or_create(&self, name: &str) -> Option<CstObject> {
1718 match self.get(name) {
1719 Some(prop) => match prop.value()? {
1720 CstNode::Container(CstContainerNode::Object(node)) => Some(node),
1721 _ => None,
1722 },
1723 None => {
1724 self.append(name, CstInputValue::Object(Vec::new()));
1725 self.object_value(name)
1726 }
1727 }
1728 }
1729
1730 pub fn object_value_or_set(&self, name: &str) -> CstObject {
1735 match self.get(name) {
1736 Some(prop) => match prop.value() {
1737 Some(CstNode::Container(CstContainerNode::Object(node))) => node,
1738 Some(node) => {
1739 let mut index = node.child_index();
1740 node.remove_raw();
1741 let container: CstContainerNode = prop.clone().into();
1742 let object = CstObject::new_with_tokens();
1743 container.raw_insert_child(Some(&mut index), object.clone().into());
1744 object
1745 }
1746 _ => {
1747 let mut index = prop.children().len();
1748 let container: CstContainerNode = prop.clone().into();
1749 let object = CstObject::new_with_tokens();
1750 container.raw_insert_child(Some(&mut index), object.clone().into());
1751 object
1752 }
1753 },
1754 None => {
1755 self.append(name, CstInputValue::Object(Vec::new()));
1756 self.object_value(name).unwrap()
1757 }
1758 }
1759 }
1760
1761 pub fn get(&self, name: &str) -> Option<CstObjectProp> {
1765 for child in &self.0.borrow().value {
1766 if let CstNode::Container(CstContainerNode::ObjectProp(prop)) = child {
1767 let Some(prop_name) = prop.name() else {
1768 continue;
1769 };
1770 let Ok(prop_name_str) = prop_name.decoded_value() else {
1771 continue;
1772 };
1773 if prop_name_str == name {
1774 return Some(prop.clone());
1775 }
1776 }
1777 }
1778 None
1779 }
1780
1781 pub fn properties(&self) -> Vec<CstObjectProp> {
1783 self
1784 .0
1785 .borrow()
1786 .value
1787 .iter()
1788 .filter_map(|child| match child {
1789 CstNode::Container(CstContainerNode::ObjectProp(prop)) => Some(prop.clone()),
1790 _ => None,
1791 })
1792 .collect()
1793 }
1794
1795 pub fn append(&self, prop_name: &str, value: CstInputValue) -> CstObjectProp {
1799 self.insert_or_append(None, prop_name, value)
1800 }
1801
1802 pub fn insert(&self, index: usize, prop_name: &str, value: CstInputValue) -> CstObjectProp {
1806 self.insert_or_append(Some(index), prop_name, value)
1807 }
1808
1809 fn insert_or_append(&self, index: Option<usize>, prop_name: &str, value: CstInputValue) -> CstObjectProp {
1810 self.ensure_multiline();
1811 insert_or_append_to_container(
1812 &CstContainerNode::Object(self.clone()),
1813 self.properties().into_iter().map(|c| c.into()).collect(),
1814 index,
1815 InsertValue::Property(prop_name, value),
1816 )
1817 .as_object_prop()
1818 .unwrap()
1819 }
1820
1821 pub fn sort_properties(&self) -> PropertySort<'_> {
1859 PropertySort {
1860 object: self,
1861 options: SortOptions::default(),
1862 }
1863 }
1864
1865 pub fn replace_with(self, replacement: CstInputValue) -> Option<CstNode> {
1867 replace_with(self.into(), InsertValue::Value(replacement))
1868 }
1869
1870 pub fn set_trailing_commas(&self, mode: TrailingCommaMode) {
1872 set_trailing_commas(
1873 mode,
1874 &self.clone().into(),
1875 self.properties().into_iter().map(|c| c.into()),
1876 );
1877 }
1878
1879 pub fn ensure_multiline(&self) {
1881 ensure_multiline(&self.clone().into());
1882 }
1883
1884 pub fn remove(self) {
1886 remove_comma_separated(self.into())
1887 }
1888
1889 #[cfg(feature = "serde_json")]
1891 pub fn to_serde_value(&self) -> Option<serde_json::Value> {
1892 let mut map = serde_json::map::Map::new();
1893 for prop in self.properties() {
1894 if let (Some(name), Some(value)) = (prop.decoded_name(), prop.to_serde_value()) {
1895 map.insert(name, value);
1896 }
1897 }
1898 Some(serde_json::Value::Object(map))
1899 }
1900}
1901
1902impl Display for CstObject {
1903 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1904 for child in &self.0.borrow().value {
1905 write!(f, "{}", child)?;
1906 }
1907 Ok(())
1908 }
1909}
1910
1911type CstObjectPropInner = RefCell<CstChildrenInner>;
1912
1913#[derive(Debug, Clone)]
1915pub struct CstObjectProp(Rc<CstObjectPropInner>);
1916
1917impl_container_methods!(CstObjectProp, ObjectProp);
1918
1919impl CstObjectProp {
1920 add_root_node_method!();
1921
1922 fn new() -> Self {
1923 Self(CstValueInner::new(Vec::new()))
1924 }
1925
1926 pub fn name(&self) -> Option<ObjectPropName> {
1930 for child in &self.0.borrow().value {
1931 match child {
1932 CstNode::Leaf(CstLeafNode::StringLit(node)) => return Some(ObjectPropName::String(node.clone())),
1933 CstNode::Leaf(CstLeafNode::WordLit(node)) => return Some(ObjectPropName::Word(node.clone())),
1934 _ => {
1935 }
1937 }
1938 }
1939 None
1940 }
1941
1942 pub fn decoded_name(&self) -> Option<String> {
1946 match self.name()? {
1947 ObjectPropName::String(s) => s.decoded_value().ok(),
1948 ObjectPropName::Word(w) => Some(w.0.borrow().value.clone()),
1949 }
1950 }
1951
1952 pub fn property_index(&self) -> usize {
1953 let child_index = self.child_index();
1954 let Some(parent) = self.parent().and_then(|p| p.as_object()) else {
1955 return 0;
1956 };
1957 parent
1958 .properties()
1959 .iter()
1960 .position(|p| p.child_index() == child_index)
1961 .unwrap_or(0)
1962 }
1963
1964 pub fn set_value(&self, replacement: CstInputValue) {
1965 let maybe_value = self.value();
1966 let mut value_index = maybe_value
1967 .as_ref()
1968 .map(|v| v.child_index())
1969 .unwrap_or_else(|| self.children().len());
1970 let container: CstContainerNode = self.clone().into();
1971 let indents = compute_indents(&container.clone().into());
1972 let style_info = &StyleInfo {
1973 newline_kind: container.root_node().map(|v| v.newline_kind()).unwrap_or_default(),
1974 uses_trailing_commas: uses_trailing_commas(maybe_value.unwrap_or_else(|| container.clone().into())),
1975 };
1976 self.remove_child_set_no_parent(value_index);
1977 container.raw_insert_value_with_internal_indent(
1978 Some(&mut value_index),
1979 InsertValue::Value(replacement),
1980 style_info,
1981 &indents,
1982 );
1983 }
1984
1985 pub fn value(&self) -> Option<CstNode> {
1989 let name = self.name()?;
1990 let parent_info = name.parent_info()?;
1991 let children = &self.0.borrow().value;
1992 let mut children = children[parent_info.child_index + 1..].iter();
1993
1994 for child in children.by_ref() {
1996 if let CstNode::Leaf(CstLeafNode::Token(token)) = child
1997 && token.value() == ':'
1998 {
1999 break;
2000 }
2001 }
2002
2003 for child in children {
2005 match child {
2006 CstNode::Leaf(leaf) => match leaf {
2007 CstLeafNode::BooleanLit(_)
2008 | CstLeafNode::NullKeyword(_)
2009 | CstLeafNode::NumberLit(_)
2010 | CstLeafNode::StringLit(_)
2011 | CstLeafNode::WordLit(_) => return Some(child.clone()),
2012 CstLeafNode::Token(_) | CstLeafNode::Whitespace(_) | CstLeafNode::Newline(_) | CstLeafNode::Comment(_) => {
2013 }
2015 },
2016 CstNode::Container(container) => match container {
2017 CstContainerNode::Object(_) | CstContainerNode::Array(_) => return Some(child.clone()),
2018 CstContainerNode::Root(_) | CstContainerNode::ObjectProp(_) => return None,
2019 },
2020 }
2021 }
2022
2023 None
2024 }
2025
2026 pub fn object_value(&self) -> Option<CstObject> {
2028 self.value()?.as_object()
2029 }
2030
2031 pub fn object_value_or_set(&self) -> CstObject {
2033 match self.value() {
2034 Some(CstNode::Container(CstContainerNode::Object(node))) => node,
2035 _ => {
2036 self.set_value(CstInputValue::Object(Vec::new()));
2037 self.object_value().unwrap()
2038 }
2039 }
2040 }
2041
2042 pub fn array_value(&self) -> Option<CstArray> {
2044 self.value()?.as_array()
2045 }
2046
2047 pub fn array_value_or_set(&self) -> CstArray {
2049 match self.value() {
2050 Some(CstNode::Container(CstContainerNode::Array(node))) => node,
2051 _ => {
2052 self.set_value(CstInputValue::Array(Vec::new()));
2053 self.array_value().unwrap()
2054 }
2055 }
2056 }
2057
2058 pub fn previous_property(&self) -> Option<CstObjectProp> {
2060 for sibling in self.previous_siblings() {
2061 if let CstNode::Container(CstContainerNode::ObjectProp(prop)) = sibling {
2062 return Some(prop);
2063 }
2064 }
2065 None
2066 }
2067
2068 pub fn next_property(&self) -> Option<CstObjectProp> {
2070 for sibling in self.next_siblings() {
2071 if let CstNode::Container(CstContainerNode::ObjectProp(prop)) = sibling {
2072 return Some(prop);
2073 }
2074 }
2075 None
2076 }
2077
2078 pub fn replace_with(self, key: &str, replacement: CstInputValue) -> Option<CstNode> {
2080 replace_with(self.into(), InsertValue::Property(key, replacement))
2081 }
2082
2083 pub fn remove(self) {
2085 remove_comma_separated(self.into())
2086 }
2087
2088 #[cfg(feature = "serde_json")]
2092 pub fn to_serde_value(&self) -> Option<serde_json::Value> {
2093 self.value()?.to_serde_value()
2094 }
2095}
2096
2097impl Display for CstObjectProp {
2098 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2099 for child in &self.0.borrow().value {
2100 write!(f, "{}", child)?;
2101 }
2102 Ok(())
2103 }
2104}
2105
2106#[derive(Debug, Clone)]
2108pub enum ObjectPropName {
2109 String(CstStringLit),
2110 Word(CstWordLit),
2111}
2112
2113impl ObjectPropName {
2114 add_root_node_method!();
2115 add_parent_info_methods!();
2116
2117 pub fn as_string_lit(&self) -> Option<CstStringLit> {
2119 match self {
2120 ObjectPropName::String(n) => Some(n.clone()),
2121 ObjectPropName::Word(_) => None,
2122 }
2123 }
2124
2125 pub fn as_word_lit(&self) -> Option<CstWordLit> {
2127 match self {
2128 ObjectPropName::String(_) => None,
2129 ObjectPropName::Word(n) => Some(n.clone()),
2130 }
2131 }
2132
2133 pub fn decoded_value(&self) -> Result<String, ParseStringErrorKind> {
2135 match self {
2136 ObjectPropName::String(n) => n.decoded_value(),
2137 ObjectPropName::Word(n) => Ok(n.0.borrow().value.clone()),
2138 }
2139 }
2140
2141 fn parent_info(&self) -> Option<ParentInfo> {
2142 match self {
2143 ObjectPropName::String(n) => n.parent_info(),
2144 ObjectPropName::Word(n) => n.parent_info(),
2145 }
2146 }
2147}
2148
2149impl From<ObjectPropName> for CstNode {
2150 fn from(value: ObjectPropName) -> Self {
2151 match value {
2152 ObjectPropName::String(n) => n.into(),
2153 ObjectPropName::Word(n) => n.into(),
2154 }
2155 }
2156}
2157
2158type CstArrayInner = RefCell<CstChildrenInner>;
2159
2160#[derive(Debug, Clone)]
2162pub struct CstArray(Rc<CstArrayInner>);
2163
2164impl_container_methods!(CstArray, Array);
2165
2166impl CstArray {
2167 add_root_node_method!();
2168
2169 fn new_no_tokens() -> Self {
2170 Self(CstValueInner::new(Vec::new()))
2171 }
2172
2173 fn new_with_tokens() -> Self {
2174 let array = CstArray::new_no_tokens();
2175 let container: CstContainerNode = array.clone().into();
2176 container.raw_append_children(vec![CstToken::new('[').into(), CstToken::new(']').into()]);
2177 array
2178 }
2179
2180 pub fn elements(&self) -> Vec<CstNode> {
2182 self
2183 .0
2184 .borrow()
2185 .value
2186 .iter()
2187 .filter(|child| match child {
2188 CstNode::Container(_) => true,
2189 CstNode::Leaf(leaf) => match leaf {
2190 CstLeafNode::BooleanLit(_)
2191 | CstLeafNode::NullKeyword(_)
2192 | CstLeafNode::NumberLit(_)
2193 | CstLeafNode::StringLit(_)
2194 | CstLeafNode::WordLit(_) => true,
2195 CstLeafNode::Token(_) | CstLeafNode::Whitespace(_) | CstLeafNode::Newline(_) | CstLeafNode::Comment(_) => {
2196 false
2197 }
2198 },
2199 })
2200 .cloned()
2201 .collect()
2202 }
2203
2204 pub fn append(&self, value: CstInputValue) -> CstNode {
2208 self.insert_or_append(None, value)
2209 }
2210
2211 pub fn insert(&self, index: usize, value: CstInputValue) -> CstNode {
2215 self.insert_or_append(Some(index), value)
2216 }
2217
2218 pub fn sort_elements(&self) -> ElementSort<'_> {
2247 ElementSort {
2248 array: self,
2249 options: SortOptions::default(),
2250 }
2251 }
2252
2253 pub fn ensure_multiline(&self) {
2255 ensure_multiline(&self.clone().into());
2256 }
2257
2258 pub fn set_trailing_commas(&self, mode: TrailingCommaMode) {
2260 set_trailing_commas(mode, &self.clone().into(), self.elements().into_iter());
2261 }
2262
2263 fn insert_or_append(&self, index: Option<usize>, value: CstInputValue) -> CstNode {
2264 insert_or_append_to_container(
2265 &CstContainerNode::Array(self.clone()),
2266 self.elements(),
2267 index,
2268 InsertValue::Value(value),
2269 )
2270 }
2271
2272 pub fn replace_with(self, replacement: CstInputValue) -> Option<CstNode> {
2274 replace_with(self.into(), InsertValue::Value(replacement))
2275 }
2276
2277 pub fn remove(self) {
2279 remove_comma_separated(self.into())
2280 }
2281
2282 #[cfg(feature = "serde_json")]
2284 pub fn to_serde_value(&self) -> Option<serde_json::Value> {
2285 let elements: Vec<serde_json::Value> = self
2286 .elements()
2287 .into_iter()
2288 .filter_map(|element| element.to_serde_value())
2289 .collect();
2290 Some(serde_json::Value::Array(elements))
2291 }
2292}
2293
2294impl Display for CstArray {
2295 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2296 for child in &self.0.borrow().value {
2297 write!(f, "{}", child)?;
2298 }
2299 Ok(())
2300 }
2301}
2302
2303#[derive(Debug, Clone)]
2305pub struct CstToken(Rc<RefCell<CstValueInner<char>>>);
2306
2307impl_leaf_methods!(CstToken, Token);
2308
2309impl CstToken {
2310 fn new(value: char) -> Self {
2311 Self(CstValueInner::new(value))
2312 }
2313
2314 pub fn set_value(&self, value: char) {
2316 self.0.borrow_mut().value = value;
2317 }
2318
2319 pub fn value(&self) -> char {
2321 self.0.borrow().value
2322 }
2323
2324 pub fn remove(self) {
2326 Into::<CstNode>::into(self).remove_raw()
2327 }
2328}
2329
2330impl Display for CstToken {
2331 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2332 write!(f, "{}", self.0.borrow().value)
2333 }
2334}
2335
2336#[derive(Debug, Clone)]
2338pub struct CstWhitespace(Rc<RefCell<CstValueInner<String>>>);
2339
2340impl_leaf_methods!(CstWhitespace, Whitespace);
2341
2342impl CstWhitespace {
2343 fn new(value: String) -> Self {
2344 Self(CstValueInner::new(value))
2345 }
2346
2347 pub fn set_value(&self, value: String) {
2349 self.0.borrow_mut().value = value;
2350 }
2351
2352 pub fn value(&self) -> String {
2354 self.0.borrow().value.clone()
2355 }
2356
2357 pub fn remove(self) {
2359 Into::<CstNode>::into(self).remove_raw()
2360 }
2361}
2362
2363impl Display for CstWhitespace {
2364 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2365 write!(f, "{}", self.0.borrow().value)
2366 }
2367}
2368
2369#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
2371pub enum CstNewlineKind {
2372 #[default]
2373 LineFeed,
2374 CarriageReturnLineFeed,
2375}
2376
2377#[derive(Debug, Clone)]
2379pub struct CstNewline(Rc<RefCell<CstValueInner<CstNewlineKind>>>);
2380
2381impl_leaf_methods!(CstNewline, Newline);
2382
2383impl CstNewline {
2384 fn new(kind: CstNewlineKind) -> Self {
2385 Self(CstValueInner::new(kind))
2386 }
2387
2388 pub fn kind(&self) -> CstNewlineKind {
2390 self.0.borrow().value
2391 }
2392
2393 pub fn set_kind(&self, kind: CstNewlineKind) {
2395 self.0.borrow_mut().value = kind;
2396 }
2397
2398 pub fn remove(self) {
2400 Into::<CstNode>::into(self).remove_raw()
2401 }
2402}
2403
2404impl Display for CstNewline {
2405 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2406 match self.0.borrow().value {
2407 #[allow(clippy::write_with_newline)] CstNewlineKind::LineFeed => write!(f, "\n"),
2409 CstNewlineKind::CarriageReturnLineFeed => write!(f, "\r\n"),
2410 }
2411 }
2412}
2413
2414#[derive(Debug, Clone)]
2415pub struct CstComment(Rc<RefCell<CstValueInner<String>>>);
2416
2417impl_leaf_methods!(CstComment, Comment);
2418
2419impl CstComment {
2420 fn new(value: String) -> Self {
2421 Self(CstValueInner::new(value))
2422 }
2423
2424 pub fn is_line_comment(&self) -> bool {
2426 self.0.borrow().value.starts_with("//")
2427 }
2428
2429 pub fn set_raw_value(&self, value: String) {
2434 self.0.borrow_mut().value = value;
2435 }
2436
2437 pub fn raw_value(&self) -> String {
2439 self.0.borrow().value.clone()
2440 }
2441
2442 pub fn remove(self) {
2444 if self.is_line_comment() {
2445 for node in self.previous_siblings() {
2446 if node.is_whitespace() {
2447 node.remove_raw();
2448 } else {
2449 if node.is_newline() {
2450 node.remove_raw();
2451 }
2452 break;
2453 }
2454 }
2455 }
2456
2457 Into::<CstNode>::into(self).remove_raw()
2458 }
2459}
2460
2461impl Display for CstComment {
2462 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2463 write!(f, "{}", self.0.borrow().value)
2464 }
2465}
2466
2467struct CstBuilder<'a> {
2468 pub text: &'a str,
2469 pub tokens: VecDeque<crate::tokens::TokenAndRange<'a>>,
2470}
2471
2472impl<'a> CstBuilder<'a> {
2473 pub fn build(&mut self, ast_value: Option<crate::ast::Value<'a>>) -> CstRootNode {
2474 let root_node = CstContainerNode::Root(CstRootNode(Rc::new(RefCell::new(CstChildrenInner {
2475 parent: None,
2476 value: Vec::new(),
2477 }))));
2478
2479 if let Some(ast_value) = ast_value {
2480 let range = ast_value.range();
2481 self.scan_from_to(&root_node, 0, range.start);
2482 self.build_value(&root_node, ast_value);
2483 self.scan_from_to(&root_node, range.end, self.text.len());
2484 } else {
2485 self.scan_from_to(&root_node, 0, self.text.len());
2486 }
2487
2488 match root_node {
2489 CstContainerNode::Root(node) => node,
2490 _ => unreachable!(),
2491 }
2492 }
2493
2494 fn scan_from_to(&mut self, container: &CstContainerNode, from: usize, to: usize) {
2495 if from == to {
2496 return;
2497 }
2498
2499 let mut last_from = from;
2500 while let Some(token) = self.tokens.front() {
2501 if token.range.end <= from {
2502 self.tokens.pop_front();
2503 } else if token.range.start < to {
2504 if token.range.start > last_from {
2505 self.build_whitespace(container, &self.text[last_from..token.range.start]);
2506 }
2507 let token = self.tokens.pop_front().unwrap();
2508 match token.token {
2509 crate::tokens::Token::OpenBrace
2510 | crate::tokens::Token::CloseBrace
2511 | crate::tokens::Token::OpenBracket
2512 | crate::tokens::Token::CloseBracket
2513 | crate::tokens::Token::Comma
2514 | crate::tokens::Token::Colon => {
2515 self.build_token(container, token.token.as_str().chars().next().unwrap());
2516 }
2517 crate::tokens::Token::Null
2518 | crate::tokens::Token::String(_)
2519 | crate::tokens::Token::Word(_)
2520 | crate::tokens::Token::Boolean(_)
2521 | crate::tokens::Token::Number(_) => unreachable!(
2522 "programming error parsing cst {:?} scanning {} to {}",
2523 token.token, from, to
2524 ),
2525 crate::tokens::Token::CommentLine(_) | crate::tokens::Token::CommentBlock(_) => {
2526 container
2527 .raw_append_child(CstComment::new(self.text[token.range.start..token.range.end].to_string()).into());
2528 }
2529 }
2530 last_from = token.range.end;
2531 } else {
2532 break;
2533 }
2534 }
2535
2536 if last_from < to {
2537 self.build_whitespace(container, &self.text[last_from..to]);
2538 }
2539 }
2540
2541 fn build_value(&mut self, container: &CstContainerNode, ast_value: ast::Value<'_>) {
2542 match ast_value {
2543 ast::Value::StringLit(string_lit) => self.build_string_lit(container, string_lit),
2544 ast::Value::NumberLit(number_lit) => {
2545 container.raw_append_child(CstNumberLit::new(number_lit.value.to_string()).into())
2546 }
2547 ast::Value::BooleanLit(boolean_lit) => container.raw_append_child(CstBooleanLit::new(boolean_lit.value).into()),
2548 ast::Value::Object(object) => {
2549 let object = self.build_object(object);
2550 container.raw_append_child(object.into())
2551 }
2552 ast::Value::Array(array) => {
2553 let array = self.build_array(array);
2554 container.raw_append_child(array.into())
2555 }
2556 ast::Value::NullKeyword(_) => container.raw_append_child(CstNullKeyword::new().into()),
2557 }
2558 }
2559
2560 fn build_object(&mut self, object: ast::Object<'_>) -> CstContainerNode {
2561 let container = CstContainerNode::Object(CstObject::new_no_tokens());
2562 let mut last_range_end = object.range.start;
2563 for prop in object.properties {
2564 self.scan_from_to(&container, last_range_end, prop.range.start);
2565 last_range_end = prop.range.end;
2566 let object_prop = self.build_object_prop(prop);
2567 container.raw_append_child(CstNode::Container(object_prop));
2568 }
2569 self.scan_from_to(&container, last_range_end, object.range.end);
2570
2571 container
2572 }
2573
2574 fn build_object_prop(&mut self, prop: ast::ObjectProp<'_>) -> CstContainerNode {
2575 let container = CstContainerNode::ObjectProp(CstObjectProp::new());
2576 let name_range = prop.name.range();
2577 let value_range = prop.value.range();
2578
2579 match prop.name {
2580 ast::ObjectPropName::String(string_lit) => {
2581 self.build_string_lit(&container, string_lit);
2582 }
2583 ast::ObjectPropName::Word(word_lit) => {
2584 container.raw_append_child(CstWordLit::new(word_lit.value.to_string()).into());
2585 }
2586 }
2587
2588 self.scan_from_to(&container, name_range.end, value_range.start);
2589 self.build_value(&container, prop.value);
2590
2591 container
2592 }
2593
2594 fn build_token(&self, container: &CstContainerNode, value: char) {
2595 container.raw_append_child(CstToken::new(value).into());
2596 }
2597
2598 fn build_whitespace(&self, container: &CstContainerNode, value: &str) {
2599 if value.is_empty() {
2600 return;
2601 }
2602
2603 let mut last_found_index = 0;
2604 let mut chars = value.char_indices().peekable();
2605 let maybe_add_previous_text = |from: usize, to: usize| {
2606 let text = &value[from..to];
2607 if !text.is_empty() {
2608 container.raw_append_child(CstWhitespace::new(text.to_string()).into());
2609 }
2610 };
2611 while let Some((i, c)) = chars.next() {
2612 if c == '\r' && chars.peek().map(|(_, c)| *c) == Some('\n') {
2613 maybe_add_previous_text(last_found_index, i);
2614 container.raw_append_child(CstNewline::new(CstNewlineKind::CarriageReturnLineFeed).into());
2615 last_found_index = i + 2;
2616 chars.next(); } else if c == '\n' {
2618 maybe_add_previous_text(last_found_index, i);
2619 container.raw_append_child(CstNewline::new(CstNewlineKind::LineFeed).into());
2620 last_found_index = i + 1;
2621 }
2622 }
2623
2624 maybe_add_previous_text(last_found_index, value.len());
2625 }
2626
2627 fn build_string_lit(&self, container: &CstContainerNode, lit: ast::StringLit<'_>) {
2628 container.raw_append_child(CstStringLit::new(self.text[lit.range.start..lit.range.end].to_string()).into());
2629 }
2630
2631 fn build_array(&mut self, array: ast::Array<'_>) -> CstContainerNode {
2632 let container = CstContainerNode::Array(CstArray::new_no_tokens());
2633 let mut last_range_end = array.range.start;
2634 for element in array.elements {
2635 let element_range = element.range();
2636 self.scan_from_to(&container, last_range_end, element_range.start);
2637 self.build_value(&container, element);
2638 last_range_end = element_range.end;
2639 }
2640 self.scan_from_to(&container, last_range_end, array.range.end);
2641
2642 container
2643 }
2644}
2645
2646#[must_use = "nothing is sorted until `by` or `by_key` is called"]
2650pub struct PropertySort<'a> {
2651 object: &'a CstObject,
2652 options: SortOptions<'a>,
2653}
2654
2655impl<'a> PropertySort<'a> {
2656 pub fn pin_comment_headers(mut self) -> Self {
2695 self.options.header_rule = Some(Box::new(blank_line_header_rule));
2696 self
2697 }
2698
2699 pub fn pin_comment_headers_with(mut self, mut rule: impl FnMut(&CstObjectProp, &[CstComment]) -> usize + 'a) -> Self {
2717 self.options.header_rule = Some(Box::new(move |element, comments| match element.as_object_prop() {
2718 Some(prop) => rule(&prop, comments),
2719 None => 0,
2720 }));
2721 self
2722 }
2723
2724 pub fn within_groups(mut self) -> Self {
2761 self.options.within_groups = true;
2762 self
2763 }
2764
2765 pub fn by(self, mut compare: impl FnMut(&CstObjectProp, &CstObjectProp) -> Ordering) {
2771 let object = self.object.clone().into();
2772 sort_comma_separated_children(&object, self.options, |groups| {
2773 groups.sort_by(|left, right| {
2774 match (left.element.as_object_prop(), right.element.as_object_prop()) {
2775 (Some(left), Some(right)) => compare(&left, &right),
2776 _ => Ordering::Equal,
2779 }
2780 })
2781 });
2782 }
2783
2784 pub fn by_key<K: Ord>(self, mut key: impl FnMut(&CstObjectProp) -> K) {
2790 let object = self.object.clone().into();
2791 sort_comma_separated_children(&object, self.options, |groups| {
2792 groups.sort_by_cached_key(|group| group.element.as_object_prop().map(|prop| key(&prop)))
2793 });
2794 }
2795}
2796
2797#[must_use = "nothing is sorted until `by` or `by_key` is called"]
2801pub struct ElementSort<'a> {
2802 array: &'a CstArray,
2803 options: SortOptions<'a>,
2804}
2805
2806impl<'a> ElementSort<'a> {
2807 pub fn pin_comment_headers(self) -> Self {
2811 self.pin_comment_headers_with(blank_line_header_rule)
2812 }
2813
2814 pub fn pin_comment_headers_with(mut self, rule: impl FnMut(&CstNode, &[CstComment]) -> usize + 'a) -> Self {
2819 self.options.header_rule = Some(Box::new(rule));
2820 self
2821 }
2822
2823 pub fn within_groups(mut self) -> Self {
2827 self.options.within_groups = true;
2828 self
2829 }
2830
2831 pub fn by(self, mut compare: impl FnMut(&CstNode, &CstNode) -> Ordering) {
2835 let array = self.array.clone().into();
2836 sort_comma_separated_children(&array, self.options, |groups| {
2837 groups.sort_by(|left, right| compare(&left.element, &right.element))
2838 });
2839 }
2840
2841 pub fn by_key<K: Ord>(self, mut key: impl FnMut(&CstNode) -> K) {
2845 let array = self.array.clone().into();
2846 sort_comma_separated_children(&array, self.options, |groups| {
2847 groups.sort_by_cached_key(|group| key(&group.element))
2848 });
2849 }
2850}
2851
2852type HeaderRule<'a> = Box<dyn FnMut(&CstNode, &[CstComment]) -> usize + 'a>;
2854
2855#[derive(Default)]
2857struct SortOptions<'a> {
2858 header_rule: Option<HeaderRule<'a>>,
2859 within_groups: bool,
2860}
2861
2862impl SortOptions<'_> {
2863 fn pinned_comment_count(&mut self, element: &CstNode, comments: &[CstComment]) -> usize {
2865 match &mut self.header_rule {
2866 Some(rule) => rule(element, comments),
2867 None => 0,
2868 }
2869 }
2870}
2871
2872fn blank_line_header_rule(element: &CstNode, comments: &[CstComment]) -> usize {
2875 if element.has_blank_line_before() {
2876 comments.len()
2877 } else {
2878 0
2879 }
2880}
2881
2882struct Separator {
2888 before: Range<usize>,
2891 indent: Range<usize>,
2893}
2894
2895struct SortableGroup {
2899 index: usize,
2901 starts_group: bool,
2904 leading: Range<usize>,
2906 element: CstNode,
2907 trailing: Range<usize>,
2910 comma: Option<usize>,
2912}
2913
2914fn sort_comma_separated_children(
2921 container: &CstContainerNode,
2922 mut options: SortOptions<'_>,
2923 mut sort: impl FnMut(&mut [SortableGroup]),
2924) {
2925 let children = container.children();
2926 if children.len() < 2 || !children[0].is_token() || !children[children.len() - 1].is_token() {
2928 return;
2929 }
2930 let region = &children[1..children.len() - 1];
2931
2932 let mut separators: Vec<Separator> = Vec::new();
2935 let mut groups: Vec<SortableGroup> = Vec::new();
2936 let mut index = 0;
2937 let tail = loop {
2938 let run_start = index;
2939 while index < region.len() && !is_sortable_element(®ion[index]) {
2940 index += 1;
2941 }
2942 if index == region.len() {
2943 break run_start..region.len();
2945 }
2946 let run = run_start..index;
2947 let starts_group = has_blank_line(region[run.clone()].iter().cloned());
2948 let (separator, leading) = split_separator(region, run, ®ion[index], starts_group, &mut options);
2949 separators.push(separator);
2950 let trailing = index + 1..trailing_run_end(region, index + 1);
2951 groups.push(SortableGroup {
2952 index: groups.len(),
2953 starts_group,
2954 leading,
2955 element: region[index].clone(),
2956 comma: region[trailing.clone()]
2957 .iter()
2958 .position(|n| n.is_comma())
2959 .map(|at| trailing.start + at),
2960 trailing: trailing.clone(),
2961 });
2962 index = trailing.end;
2963 };
2964
2965 if groups.len() < 2 {
2966 return;
2967 }
2968
2969 let ends_with_comma = groups[groups.len() - 1].comma.is_some();
2971 if options.within_groups {
2972 for group in groups.chunk_by_mut(|_, next| !next.starts_group) {
2974 sort(group);
2975 }
2976 } else {
2977 sort(&mut groups);
2978 }
2979 let unchanged = container.children().len() == children.len()
2983 && children
2984 .iter()
2985 .enumerate()
2986 .all(|(index, child)| child.parent_info().map(|info| info.child_index) == Some(index));
2987 if !unchanged {
2988 return;
2989 }
2990 if groups
2991 .iter()
2992 .enumerate()
2993 .all(|(position, group)| position == group.index)
2994 {
2995 return;
2996 }
2997
2998 let first_leading = &mut groups[0].leading;
3001 first_leading.start += leading_blank_line_len(®ion[first_leading.clone()]);
3002
3003 let last_index = groups.len() - 1;
3004 let mut new_children = Vec::with_capacity(children.len());
3005 new_children.push(children[0].clone());
3006 for (position, (separator, group)) in separators.into_iter().zip(groups).enumerate() {
3007 new_children.extend_from_slice(®ion[separator.before]);
3008 new_children.extend_from_slice(®ion[group.leading]);
3009 new_children.extend_from_slice(®ion[separator.indent]);
3010 new_children.push(group.element);
3011 let wants_comma = position < last_index || ends_with_comma;
3012 push_trailing(&mut new_children, region, group.trailing, group.comma, wants_comma);
3013 }
3014 new_children.extend_from_slice(®ion[tail]);
3015 new_children.push(children[children.len() - 1].clone());
3016 let newline_kind = container
3017 .root_node()
3018 .map(|root| root.newline_kind())
3019 .unwrap_or(CstNewlineKind::LineFeed);
3020 restore_line_comment_line_ends(&mut new_children, newline_kind);
3021 container.raw_set_children(new_children);
3022}
3023
3024fn is_sortable_element(node: &CstNode) -> bool {
3027 !node.is_trivia() && !node.is_token()
3028}
3029
3030fn leading_blank_line_len(run: &[CstNode]) -> usize {
3035 let mut len = 0;
3036 let mut index = 0;
3037 while index < run.len() {
3038 let mut end = index;
3039 while end < run.len() && run[end].is_whitespace() {
3040 end += 1;
3041 }
3042 if end < run.len() && run[end].is_newline() {
3043 index = end + 1;
3044 len = index;
3045 } else {
3046 break;
3047 }
3048 }
3049 len
3050}
3051
3052fn has_blank_line(run: impl IntoIterator<Item = CstNode>) -> bool {
3057 let mut ended_a_line = false;
3058 for node in run {
3059 if node.is_newline() {
3060 if ended_a_line {
3061 return true;
3062 }
3063 ended_a_line = true;
3064 } else if !node.is_whitespace() {
3065 ended_a_line = false;
3066 }
3067 }
3068 false
3069}
3070
3071fn split_separator(
3080 region: &[CstNode],
3081 run: Range<usize>,
3082 element: &CstNode,
3083 starts_group: bool,
3084 options: &mut SortOptions<'_>,
3085) -> (Separator, Range<usize>) {
3086 let nodes = ®ion[run.clone()];
3087 let Some(newline) = nodes.iter().position(|n| n.is_newline()) else {
3088 let before = nodes.iter().take_while(|n| n.is_whitespace()).count();
3090 return (
3091 Separator {
3092 before: run.start..run.start + before,
3093 indent: run.end..run.end,
3094 },
3095 run.start + before..run.end,
3096 );
3097 };
3098 let indent_len = nodes[newline + 1..]
3099 .iter()
3100 .rev()
3101 .take_while(|n| n.is_whitespace())
3102 .count();
3103 let indent_start = nodes.len() - indent_len;
3104 let leading = &nodes[newline + 1..indent_start];
3105 let header_len = if starts_group && options.within_groups {
3106 leading.len()
3109 } else {
3110 header_len(leading, element, options)
3111 };
3112 let leading_start = newline + 1 + header_len;
3113 (
3114 Separator {
3115 before: run.start..run.start + leading_start,
3116 indent: run.start + indent_start..run.end,
3117 },
3118 run.start + leading_start..run.start + indent_start,
3119 )
3120}
3121
3122fn header_len(leading: &[CstNode], element: &CstNode, options: &mut SortOptions<'_>) -> usize {
3128 if options.header_rule.is_none() {
3130 return 0;
3131 }
3132 let comments = leading
3133 .iter()
3134 .filter_map(|node| match node {
3135 CstNode::Leaf(CstLeafNode::Comment(comment)) => Some(comment.clone()),
3136 _ => None,
3137 })
3138 .collect::<Vec<_>>();
3139 let pinned = options.pinned_comment_count(element, &comments);
3140 if pinned >= comments.len() {
3141 return leading.len();
3142 }
3143 let blank_lines = leading_blank_line_len(leading);
3146 if pinned == 0 {
3147 return blank_lines;
3148 }
3149 let first_travelling = leading
3150 .iter()
3151 .enumerate()
3152 .filter(|(_, node)| node.is_comment())
3153 .map(|(index, _)| index)
3154 .nth(pinned)
3155 .expect("a comment past the pinned ones, since fewer were pinned than there are");
3156 let mut split = first_travelling;
3159 while split > 0 && !leading[split - 1].is_newline() {
3160 split -= 1;
3161 }
3162 split.max(blank_lines)
3163}
3164
3165fn trailing_run_end(region: &[CstNode], start: usize) -> usize {
3171 let mut end = start;
3172 for (index, node) in region.iter().enumerate().skip(start) {
3173 if is_sortable_element(node) {
3174 break;
3175 } else if node.is_comma() {
3176 end = index + 1;
3177 break;
3178 }
3179 }
3180 if rest_of_line_is_trivia(region, end) {
3182 for (index, node) in region.iter().enumerate().skip(end) {
3183 if node.is_newline() {
3184 break;
3185 } else if node.is_comment() {
3186 end = index + 1;
3187 }
3188 }
3189 }
3190 end
3191}
3192
3193fn rest_of_line_is_trivia(region: &[CstNode], start: usize) -> bool {
3196 region
3197 .iter()
3198 .skip(start)
3199 .take_while(|n| !n.is_newline())
3200 .all(|n| n.is_whitespace() || n.is_comment())
3201}
3202
3203fn push_trailing(
3205 out: &mut Vec<CstNode>,
3206 region: &[CstNode],
3207 trailing: Range<usize>,
3208 comma: Option<usize>,
3209 wants_comma: bool,
3210) {
3211 match comma {
3212 Some(comma) if !wants_comma => {
3213 let end = if comma > trailing.start && region[comma - 1].is_whitespace() {
3215 comma - 1
3216 } else {
3217 comma
3218 };
3219 out.extend_from_slice(®ion[trailing.start..end]);
3220 out.extend_from_slice(®ion[comma + 1..trailing.end]);
3221 }
3222 None if wants_comma => {
3223 out.push(CstToken::new(',').into());
3224 out.extend_from_slice(®ion[trailing]);
3225 }
3226 _ => out.extend_from_slice(®ion[trailing]),
3227 }
3228}
3229
3230fn restore_line_comment_line_ends(children: &mut Vec<CstNode>, newline_kind: CstNewlineKind) {
3235 let mut index = 0;
3236 while index < children.len() {
3237 if is_line_comment(&children[index])
3238 && let Some(next) = children[index + 1..].iter().position(|n| !n.is_whitespace())
3239 && !children[index + 1 + next].is_newline()
3240 {
3241 children.insert(index + 1, CstNewline::new(newline_kind).into());
3242 }
3243 index += 1;
3244 }
3245}
3246
3247fn is_line_comment(node: &CstNode) -> bool {
3248 matches!(node, CstNode::Leaf(CstLeafNode::Comment(comment)) if comment.is_line_comment())
3249}
3250
3251fn remove_comma_separated(node: CstNode) {
3252 fn check_next_node_same_line(trailing_comma: &CstToken) -> bool {
3253 for sibling in trailing_comma.next_siblings() {
3254 match sibling {
3255 CstNode::Container(_) => return true,
3256 CstNode::Leaf(n) => match n {
3257 CstLeafNode::BooleanLit(_)
3258 | CstLeafNode::NullKeyword(_)
3259 | CstLeafNode::NumberLit(_)
3260 | CstLeafNode::StringLit(_)
3261 | CstLeafNode::WordLit(_)
3262 | CstLeafNode::Token(_) => return true,
3263 CstLeafNode::Whitespace(_) | CstLeafNode::Comment(_) => {
3264 }
3266 CstLeafNode::Newline(_) => return false,
3267 },
3268 }
3269 }
3270
3271 true
3272 }
3273
3274 let parent = node.parent();
3275 let trailing_comma = node.trailing_comma();
3276 let is_in_array_or_obj = parent
3277 .as_ref()
3278 .map(|p| matches!(p, CstContainerNode::Array(_) | CstContainerNode::Object(_)))
3279 .unwrap_or(false);
3280 let remove_up_to_next_line = trailing_comma
3281 .as_ref()
3282 .map(|c| !check_next_node_same_line(c))
3283 .unwrap_or(true);
3284
3285 for previous in node.previous_siblings() {
3286 if previous.is_trivia() && !previous.is_newline() {
3287 previous.remove_raw();
3288 } else {
3289 break;
3290 }
3291 }
3292
3293 let mut found_newline = false;
3294
3295 if trailing_comma.is_some() {
3297 let mut next_siblings = node.next_siblings();
3298 for next in next_siblings.by_ref() {
3299 let is_comma = next.is_comma();
3300 if next.is_newline() {
3301 found_newline = true;
3302 }
3303 next.remove_raw();
3304 if is_comma {
3305 break;
3306 }
3307 }
3308 } else if is_in_array_or_obj && let Some(previous_comma) = node.previous_siblings().find(|n| n.is_comma()) {
3309 previous_comma.remove();
3310 }
3311
3312 if remove_up_to_next_line && !found_newline {
3314 let mut next_siblings = node.next_siblings().peekable();
3315 while let Some(sibling) = next_siblings.next() {
3316 if sibling.is_trivia() {
3317 if sibling.is_newline() {
3318 sibling.remove_raw();
3319 break;
3320 } else if sibling.is_whitespace()
3321 && next_siblings
3322 .peek()
3323 .map(|n| !n.is_whitespace() && !n.is_newline() && !n.is_comment())
3324 .unwrap_or(false)
3325 {
3326 break;
3327 }
3328 sibling.remove_raw();
3329 } else {
3330 break;
3331 }
3332 }
3333 }
3334
3335 node.remove_raw();
3336
3337 if let Some(parent) = parent {
3338 match parent {
3339 CstContainerNode::Root(n) => {
3340 if n.children().iter().all(|c| c.is_whitespace() || c.is_newline()) {
3341 n.clear_children();
3342 }
3343 }
3344 CstContainerNode::Object(_) | CstContainerNode::Array(_) => {
3345 let children = parent.children();
3346 if children
3347 .iter()
3348 .skip(1)
3349 .take(children.len() - 2)
3350 .all(|c| c.is_whitespace() || c.is_newline())
3351 {
3352 for c in children {
3353 if c.is_whitespace() || c.is_newline() {
3354 c.remove();
3355 }
3356 }
3357 }
3358 }
3359 CstContainerNode::ObjectProp(_) => {}
3360 }
3361 }
3362}
3363
3364fn indent_text(node: &CstNode) -> Option<String> {
3365 let mut last_whitespace: Option<String> = None;
3366 for previous_sibling in node.previous_siblings() {
3367 match previous_sibling {
3368 CstNode::Container(_) => return None,
3369 CstNode::Leaf(leaf) => match leaf {
3370 CstLeafNode::Newline(_) => {
3371 return last_whitespace;
3372 }
3373 CstLeafNode::Whitespace(whitespace) => {
3374 last_whitespace = match last_whitespace {
3375 Some(last_whitespace) => Some(format!("{}{}", whitespace.value(), last_whitespace)),
3376 None => Some(whitespace.value()),
3377 };
3378 }
3379 CstLeafNode::Comment(_) => {
3380 last_whitespace = None;
3381 }
3382 _ => return None,
3383 },
3384 }
3385 }
3386 last_whitespace
3387}
3388
3389fn uses_trailing_commas(node: CstNode) -> bool {
3390 let node = match node {
3391 CstNode::Container(node) => node,
3392 CstNode::Leaf(_) => return false,
3393 };
3394 let mut pending_nodes: VecDeque<CstContainerNode> = VecDeque::from([node.clone()]);
3395 while let Some(node) = pending_nodes.pop_front() {
3396 let children = node.children();
3397 if !node.is_root() {
3398 if let Some(object) = node.as_object() {
3399 if children.iter().any(|c| c.is_whitespace()) {
3400 let properties = object.properties();
3401 if let Some(last_property) = properties.last() {
3402 return last_property.trailing_comma().is_some();
3403 }
3404 }
3405 } else if let Some(object) = node.as_array()
3406 && children.iter().any(|c| c.is_whitespace())
3407 {
3408 let elements = object.elements();
3409 if let Some(last_property) = elements.last() {
3410 return last_property.trailing_comma().is_some();
3411 }
3412 }
3413 }
3414
3415 for child in children {
3416 if let CstNode::Container(child) = child {
3417 pending_nodes.push_back(child);
3418 }
3419 }
3420 }
3421
3422 false }
3424
3425fn replace_with(node: CstNode, replacement: InsertValue) -> Option<CstNode> {
3426 let mut child_index = node.child_index();
3427 let parent = node.parent()?;
3428 let indents = compute_indents(&parent.clone().into());
3429 let style_info = StyleInfo {
3430 newline_kind: parent.root_node().map(|r| r.newline_kind()).unwrap_or_default(),
3431 uses_trailing_commas: uses_trailing_commas(parent.clone().into()),
3432 };
3433 parent.remove_child_set_no_parent(child_index);
3434 parent.raw_insert_value_with_internal_indent(Some(&mut child_index), replacement, &style_info, &indents);
3435 parent.child_at_index(child_index - 1)
3436}
3437
3438enum InsertValue<'a> {
3439 Value(CstInputValue),
3440 Property(&'a str, CstInputValue),
3441}
3442
3443fn insert_or_append_to_container(
3444 container: &CstContainerNode,
3445 elements: Vec<CstNode>,
3446 index: Option<usize>,
3447 value: InsertValue,
3448) -> CstNode {
3449 fn has_separating_newline(siblings: impl Iterator<Item = CstNode>) -> bool {
3450 for sibling in siblings {
3451 if sibling.is_newline() {
3452 return true;
3453 } else if sibling.is_trivia() {
3454 continue;
3455 } else {
3456 break;
3457 }
3458 }
3459 false
3460 }
3461
3462 trim_inner_start_and_end_blanklines(container);
3463
3464 let children = container.children();
3465 let index = index.unwrap_or(elements.len());
3466 let index = std::cmp::min(index, elements.len());
3467 let next_node = elements.get(index);
3468 let previous_node = if index == 0 { None } else { elements.get(index - 1) };
3469 let style_info = StyleInfo {
3470 newline_kind: container.root_node().map(|r| r.newline_kind()).unwrap_or_default(),
3471 uses_trailing_commas: uses_trailing_commas(container.clone().into()),
3472 };
3473 let indents = compute_indents(&container.clone().into());
3474 let child_indents = elements
3475 .first()
3476 .map(compute_indents)
3477 .unwrap_or_else(|| indents.indent());
3478 let has_newline = children.iter().any(|child| child.is_newline());
3479 let force_multiline = has_newline
3480 || match &value {
3481 InsertValue::Value(v) => v.force_multiline(),
3482 InsertValue::Property(..) => true,
3483 };
3484 let mut insert_index: usize;
3485 let inserted_node: CstNode;
3486 if let Some(previous_node) = previous_node {
3487 if previous_node.trailing_comma().is_none() {
3488 let mut index = previous_node.child_index() + 1;
3489 container.raw_insert_child(Some(&mut index), CstToken::new(',').into());
3490 }
3491
3492 let trailing_comma: CstNode = previous_node.trailing_comma().unwrap().into();
3493 insert_index = trailing_comma
3494 .trailing_comments_same_line()
3495 .last()
3496 .map(|t| t.child_index())
3497 .unwrap_or_else(|| trailing_comma.child_index())
3498 + 1;
3499 if force_multiline {
3500 container.raw_insert_children(
3501 Some(&mut insert_index),
3502 vec![
3503 CstNewline::new(style_info.newline_kind).into(),
3504 CstWhitespace::new(child_indents.current_indent.clone()).into(),
3505 ],
3506 );
3507 container.raw_insert_value_with_internal_indent(Some(&mut insert_index), value, &style_info, &child_indents);
3508 inserted_node = container.child_at_index(insert_index - 1).unwrap();
3509 } else {
3510 container.raw_insert_child(Some(&mut insert_index), CstWhitespace::new(" ".to_string()).into());
3511 container.raw_insert_value_with_internal_indent(Some(&mut insert_index), value, &style_info, &child_indents);
3512 inserted_node = container.child_at_index(insert_index - 1).unwrap();
3513 }
3514 } else {
3515 insert_index = if elements.is_empty() {
3516 children
3517 .iter()
3518 .rev()
3519 .skip(1)
3520 .take_while(|t| t.is_whitespace() || t.is_newline())
3521 .last()
3522 .unwrap_or_else(|| children.last().unwrap())
3523 .child_index()
3524 } else {
3525 children.first().unwrap().child_index() + 1
3526 };
3527 if force_multiline {
3528 container.raw_insert_children(
3529 Some(&mut insert_index),
3530 vec![
3531 CstNewline::new(style_info.newline_kind).into(),
3532 CstWhitespace::new(child_indents.current_indent.clone()).into(),
3533 ],
3534 );
3535 container.raw_insert_value_with_internal_indent(Some(&mut insert_index), value, &style_info, &child_indents);
3536 inserted_node = container.child_at_index(insert_index - 1).unwrap();
3537 if next_node.is_none()
3538 && !has_separating_newline(container.child_at_index(insert_index - 1).unwrap().next_siblings())
3539 {
3540 container.raw_insert_children(
3541 Some(&mut insert_index),
3542 vec![
3543 CstNewline::new(style_info.newline_kind).into(),
3544 CstWhitespace::new(indents.current_indent.clone()).into(),
3545 ],
3546 );
3547 }
3548 } else {
3549 container.raw_insert_value_with_internal_indent(Some(&mut insert_index), value, &style_info, &child_indents);
3550 inserted_node = container.child_at_index(insert_index - 1).unwrap();
3551 }
3552 }
3553
3554 if next_node.is_some() {
3555 container.raw_insert_children(Some(&mut insert_index), vec![CstToken::new(',').into()]);
3556
3557 if force_multiline {
3558 let comma_token = container.child_at_index(insert_index - 1).unwrap();
3559 if !has_separating_newline(comma_token.next_siblings()) {
3560 container.raw_insert_children(
3561 Some(&mut insert_index),
3562 vec![
3563 CstNewline::new(style_info.newline_kind).into(),
3564 CstWhitespace::new(indents.current_indent.clone()).into(),
3565 ],
3566 );
3567 }
3568 } else {
3569 container.raw_insert_child(Some(&mut insert_index), CstWhitespace::new(" ".to_string()).into());
3570 }
3571 } else if style_info.uses_trailing_commas && force_multiline {
3572 container.raw_insert_children(Some(&mut insert_index), vec![CstToken::new(',').into()]);
3573 }
3574
3575 inserted_node
3576}
3577
3578fn set_trailing_commas(
3579 mode: TrailingCommaMode,
3580 parent: &CstContainerNode,
3581 elems_or_props: impl Iterator<Item = CstNode>,
3582) {
3583 let mut elems_or_props = elems_or_props.peekable();
3584 let use_trailing_commas = match mode {
3585 TrailingCommaMode::Never => false,
3586 TrailingCommaMode::IfMultiline => true,
3587 };
3588 while let Some(element) = elems_or_props.next() {
3589 if elems_or_props.peek().is_none() {
3591 if use_trailing_commas {
3592 if element.trailing_comma().is_none() && parent.children().iter().any(|c| c.is_newline()) {
3593 let mut insert_index = element.child_index() + 1;
3594 parent.raw_insert_child(Some(&mut insert_index), CstToken::new(',').into());
3595 }
3596 } else if let Some(trailing_comma) = element.trailing_comma() {
3597 trailing_comma.remove();
3598 }
3599 }
3600
3601 let maybe_prop_value = element.as_object_prop().and_then(|p| p.value());
3603 match maybe_prop_value.unwrap_or(element) {
3604 CstNode::Container(CstContainerNode::Array(array)) => {
3605 array.set_trailing_commas(mode);
3606 }
3607 CstNode::Container(CstContainerNode::Object(object)) => {
3608 object.set_trailing_commas(mode);
3609 }
3610 _ => {}
3611 }
3612 }
3613}
3614
3615fn trim_inner_start_and_end_blanklines(node: &CstContainerNode) {
3616 fn remove_blank_lines_after_first(children: &mut Peekable<impl Iterator<Item = CstNode>>) {
3617 for child in children.by_ref() {
3619 if child.is_whitespace() {
3620 } else if child.is_newline() {
3622 break; } else {
3624 return; }
3626 }
3627
3628 let mut pending = Vec::new();
3629 for child in children.by_ref() {
3630 if child.is_whitespace() {
3631 pending.push(child);
3632 } else if child.is_newline() {
3633 child.remove();
3634 for child in pending.drain(..) {
3635 child.remove();
3636 }
3637 } else {
3638 break;
3639 }
3640 }
3641 }
3642
3643 let children = node.children();
3644 let len = children.len();
3645
3646 if len < 2 {
3647 return; }
3649
3650 let mut children = children.into_iter().skip(1).take(len - 2).peekable();
3652 remove_blank_lines_after_first(&mut children);
3653 let mut children = children.rev().peekable();
3654 remove_blank_lines_after_first(&mut children);
3655}
3656
3657fn ensure_multiline(container: &CstContainerNode) {
3658 let children = container.children();
3659 if children.iter().any(|c| c.is_newline()) {
3660 return;
3661 }
3662
3663 let indents = compute_indents(&container.clone().into());
3664 let child_indents = indents.indent();
3665 let newline_kind = container
3666 .root_node()
3667 .map(|r| r.newline_kind())
3668 .unwrap_or(CstNewlineKind::LineFeed);
3669
3670 let children_len = children.len();
3672 let mut children = children.into_iter().skip(1).peekable().take(children_len - 2);
3673 let mut index = 1;
3674 while let Some(child) = children.next() {
3675 if child.is_whitespace() {
3676 child.remove();
3677 continue;
3678 } else {
3679 container.raw_insert_child(Some(&mut index), CstNewline::new(newline_kind).into());
3681 container.raw_insert_child(
3682 Some(&mut index),
3683 CstWhitespace::new(child_indents.current_indent.clone()).into(),
3684 );
3685
3686 index += 1;
3688
3689 let mut trailing_whitespace = Vec::new();
3691 for next_child in children.by_ref() {
3692 if next_child.is_whitespace() {
3693 trailing_whitespace.push(next_child);
3694 } else {
3695 index += 1 + trailing_whitespace.len();
3696 trailing_whitespace.clear();
3697 if next_child.token_char() == Some(',') {
3698 break;
3699 }
3700 }
3701 }
3702
3703 for trailing_whitespace in trailing_whitespace {
3704 trailing_whitespace.remove();
3705 }
3706 }
3707 }
3708
3709 container.raw_insert_child(Some(&mut index), CstNewline::new(newline_kind).into());
3711 if !indents.current_indent.is_empty() {
3712 container.raw_insert_child(Some(&mut index), CstWhitespace::new(indents.current_indent).into());
3713 }
3714}
3715
3716#[derive(Debug)]
3717struct Indents {
3718 current_indent: String,
3719 single_indent: String,
3720}
3721
3722impl Indents {
3723 pub fn indent(&self) -> Indents {
3724 Indents {
3725 current_indent: format!("{}{}", self.current_indent, self.single_indent),
3726 single_indent: self.single_indent.clone(),
3727 }
3728 }
3729}
3730
3731fn compute_indents(node: &CstNode) -> Indents {
3732 let mut indent_level = 0;
3733 let mut stored_last_indent = node.indent_text();
3734 let mut ancestors = node.ancestors().peekable();
3735
3736 while ancestors.peek().and_then(|p| p.as_object_prop()).is_some() {
3737 ancestors.next();
3738 }
3739
3740 while let Some(ancestor) = ancestors.next() {
3741 if ancestor.is_root() {
3742 break;
3743 }
3744
3745 if ancestors.peek().and_then(|p| p.as_object_prop()).is_some() {
3746 continue;
3747 }
3748
3749 indent_level += 1;
3750
3751 if let Some(indent_text) = ancestor.indent_text() {
3752 match stored_last_indent {
3753 Some(last_indent) => {
3754 if let Some(single_indent_text) = last_indent.strip_prefix(&indent_text) {
3755 return Indents {
3756 current_indent: format!("{}{}", last_indent, single_indent_text.repeat(indent_level - 1)),
3757 single_indent: single_indent_text.to_string(),
3758 };
3759 }
3760 stored_last_indent = None;
3761 }
3762 None => {
3763 stored_last_indent = Some(indent_text);
3764 }
3765 }
3766 } else {
3767 stored_last_indent = None;
3768 }
3769 }
3770
3771 if indent_level == 1
3772 && let Some(indent_text) = node.indent_text()
3773 {
3774 return Indents {
3775 current_indent: indent_text.clone(),
3776 single_indent: indent_text,
3777 };
3778 }
3779
3780 if let Some(root_value) = node.root_node().and_then(|r| r.value()) {
3782 for child in root_value.children() {
3783 if let Some(single_indent) = child.indent_text() {
3784 return Indents {
3785 current_indent: single_indent.repeat(indent_level),
3786 single_indent,
3787 };
3788 }
3789 }
3790 }
3791
3792 let single_indent = " ";
3794 Indents {
3795 current_indent: single_indent.repeat(indent_level),
3796 single_indent: single_indent.to_string(),
3797 }
3798}
3799
3800struct AncestorIterator {
3801 next: Option<CstContainerNode>,
3804}
3805
3806impl AncestorIterator {
3807 pub fn new(node: CstNode) -> Self {
3808 Self {
3809 next: node.parent_info().map(|i| i.parent.as_container_node()),
3810 }
3811 }
3812}
3813
3814impl Iterator for AncestorIterator {
3815 type Item = CstContainerNode;
3816
3817 fn next(&mut self) -> Option<Self::Item> {
3818 let next = self.next.take()?;
3819 self.next = next.parent_info().map(|i| i.parent.as_container_node());
3820 Some(next)
3821 }
3822}
3823
3824struct NextSiblingIterator {
3825 next: Option<CstNode>,
3828}
3829
3830impl NextSiblingIterator {
3831 pub fn new(node: CstNode) -> Self {
3832 Self {
3833 next: node.next_sibling(),
3834 }
3835 }
3836}
3837
3838impl Iterator for NextSiblingIterator {
3839 type Item = CstNode;
3840
3841 fn next(&mut self) -> Option<Self::Item> {
3842 let next_sibling = self.next.take()?;
3843 self.next = next_sibling.next_sibling();
3844 Some(next_sibling)
3845 }
3846}
3847
3848struct PreviousSiblingIterator {
3849 previous: Option<CstNode>,
3852}
3853
3854impl PreviousSiblingIterator {
3855 pub fn new(node: CstNode) -> Self {
3856 Self {
3857 previous: node.previous_sibling(),
3858 }
3859 }
3860}
3861
3862impl Iterator for PreviousSiblingIterator {
3863 type Item = CstNode;
3864
3865 fn next(&mut self) -> Option<Self::Item> {
3866 let previous_sibling = self.previous.take()?;
3867 self.previous = previous_sibling.previous_sibling();
3868 Some(previous_sibling)
3869 }
3870}
3871
3872#[cfg(test)]
3873mod test {
3874 use pretty_assertions::assert_eq;
3875
3876 use crate::cst::CstInputValue;
3877 use crate::cst::TrailingCommaMode;
3878 use crate::json;
3879
3880 use super::CstRootNode;
3881
3882 #[test]
3883 fn single_indent_text() {
3884 let cases = [
3885 (
3886 " ",
3887 r#"
3888{
3889 "prop": {
3890 "nested": 4
3891 }
3892}
3893 "#,
3894 ),
3895 (
3896 " ",
3897 r#"
3898{
3899 /* test */ "prop": {}
3900}
3901 "#,
3902 ),
3903 (
3904 " ",
3905 r#"
3906{
3907 /* test */ "prop": {}
3908}
3909 "#,
3910 ),
3911 (
3912 "\t",
3913 "
3914{
3915\t/* test */ \"prop\": {}
3916}
3917 ",
3918 ),
3919 ];
3920 for (expected, text) in cases {
3921 let root = build_cst(text);
3922 assert_eq!(root.single_indent_text(), Some(expected.to_string()), "Text: {}", text);
3923 }
3924 }
3925
3926 #[test]
3927 fn modify_values() {
3928 let cst = build_cst(
3929 r#"{
3930 "value": 5,
3931 // comment
3932 "value2": "hello",
3933 value3: true
3934}"#,
3935 );
3936
3937 let root_value = cst.value().unwrap();
3938 let root_obj = root_value.as_object().unwrap();
3939 {
3940 let prop = root_obj.get("value").unwrap();
3941 prop
3942 .value()
3943 .unwrap()
3944 .as_number_lit()
3945 .unwrap()
3946 .set_raw_value("10".to_string());
3947 assert!(prop.trailing_comma().is_some());
3948 assert!(prop.previous_property().is_none());
3949 assert_eq!(
3950 prop.next_property().unwrap().name().unwrap().decoded_value().unwrap(),
3951 "value2"
3952 );
3953 assert_eq!(prop.indent_text().unwrap(), " ");
3954 }
3955 {
3956 let prop = root_obj.get("value2").unwrap();
3957 prop
3958 .value()
3959 .unwrap()
3960 .as_string_lit()
3961 .unwrap()
3962 .set_raw_value("\"5\"".to_string());
3963 assert!(prop.trailing_comma().is_some());
3964 assert_eq!(
3965 prop
3966 .previous_property()
3967 .unwrap()
3968 .name()
3969 .unwrap()
3970 .decoded_value()
3971 .unwrap(),
3972 "value"
3973 );
3974 assert_eq!(
3975 prop.next_property().unwrap().name().unwrap().decoded_value().unwrap(),
3976 "value3"
3977 );
3978 }
3979 {
3980 let prop = root_obj.get("value3").unwrap();
3981 prop.value().unwrap().as_boolean_lit().unwrap().set_value(false);
3982 prop
3983 .name()
3984 .unwrap()
3985 .as_word_lit()
3986 .unwrap()
3987 .set_raw_value("value4".to_string());
3988 assert!(prop.trailing_comma().is_none());
3989 assert_eq!(
3990 prop
3991 .previous_property()
3992 .unwrap()
3993 .name()
3994 .unwrap()
3995 .decoded_value()
3996 .unwrap(),
3997 "value2"
3998 );
3999 assert!(prop.next_property().is_none());
4000 }
4001
4002 assert_eq!(
4003 cst.to_string(),
4004 r#"{
4005 "value": 10,
4006 // comment
4007 "value2": "5",
4008 value4: false
4009}"#
4010 );
4011 }
4012
4013 #[test]
4014 fn remove_properties() {
4015 fn run_test(prop_name: &str, json: &str, expected: &str) {
4016 let cst = build_cst(json);
4017 let root_value = cst.value().unwrap();
4018 let root_obj = root_value.as_object().unwrap();
4019 let prop = root_obj.get(prop_name).unwrap();
4020 prop.remove();
4021 assert_eq!(cst.to_string(), expected);
4022 }
4023
4024 run_test(
4025 "value2",
4026 r#"{
4027 "value": 5,
4028 // comment
4029 "value2": "hello",
4030 value3: true
4031}"#,
4032 r#"{
4033 "value": 5,
4034 // comment
4035 value3: true
4036}"#,
4037 );
4038
4039 run_test(
4040 "value2",
4041 r#"{
4042 "value": 5,
4043 // comment
4044 "value2": "hello"
4045 ,value3: true
4046}"#,
4047 r#"{
4049 "value": 5,
4050 // comment
4051value3: true
4052}"#,
4053 );
4054
4055 run_test("value", r#"{ "value": 5 }"#, r#"{}"#);
4056 run_test("value", r#"{ "value": 5, "value2": 6 }"#, r#"{ "value2": 6 }"#);
4057 run_test("value2", r#"{ "value": 5, "value2": 6 }"#, r#"{ "value": 5 }"#);
4058 }
4059
4060 #[test]
4061 fn insert_properties() {
4062 fn run_test(index: usize, prop_name: &str, value: CstInputValue, json: &str, expected: &str) {
4063 let cst = build_cst(json);
4064 let root_value = cst.value().unwrap();
4065 let root_obj = root_value.as_object().unwrap();
4066 root_obj.insert(index, prop_name, value);
4067 assert_eq!(cst.to_string(), expected, "Initial text: {}", json);
4068 }
4069
4070 run_test(
4071 0,
4072 "propName",
4073 json!([1]),
4074 r#"{}"#,
4075 r#"{
4076 "propName": [1]
4077}"#,
4078 );
4079
4080 run_test(
4082 0,
4083 "value0",
4084 json!([1]),
4085 r#"{
4086 "value1": 5
4087}"#,
4088 r#"{
4089 "value0": [1],
4090 "value1": 5
4091}"#,
4092 );
4093
4094 run_test(
4096 0,
4097 "value0",
4098 json!([1]),
4099 r#"{
4100 // some comment
4101 "value1": 5
4102}"#,
4103 r#"{
4104 "value0": [1],
4105 // some comment
4106 "value1": 5
4107}"#,
4108 );
4109
4110 run_test(
4112 1,
4113 "value1",
4114 json!({
4115 "value": 1
4116 }),
4117 r#"{
4118 "value0": 5 // comment
4119}"#,
4120 r#"{
4121 "value0": 5, // comment
4122 "value1": {
4123 "value": 1
4124 }
4125}"#,
4126 );
4127
4128 run_test(
4130 1,
4131 "propName",
4132 json!(true),
4133 r#"{
4134 "value": 4,
4135}"#,
4136 r#"{
4137 "value": 4,
4138 "propName": true,
4139}"#,
4140 );
4141
4142 run_test(
4144 1,
4145 "propName",
4146 json!(true),
4147 r#"{ "value": 4 }"#,
4148 r#"{
4149 "value": 4,
4150 "propName": true
4151}"#,
4152 );
4153
4154 run_test(
4156 1,
4157 "propName",
4158 json!(true),
4159 r#"{ "value": 4, }"#,
4160 r#"{
4161 "value": 4,
4162 "propName": true,
4163}"#,
4164 );
4165 }
4166
4167 #[test]
4168 fn remove_array_elements() {
4169 fn run_test(index: usize, json: &str, expected: &str) {
4170 let cst = build_cst(json);
4171 let root_value = cst.value().unwrap();
4172 let root_array = root_value.as_array().unwrap();
4173 let element = root_array.elements().get(index).unwrap().clone();
4174 element.remove();
4175 assert_eq!(cst.to_string(), expected);
4176 }
4177
4178 run_test(
4179 0,
4180 r#"[
4181 1,
4182]"#,
4183 r#"[]"#,
4184 );
4185 run_test(
4186 0,
4187 r#"[
4188 1,
4189 2,
4190]"#,
4191 r#"[
4192 2,
4193]"#,
4194 );
4195 run_test(
4196 0,
4197 r#"[
4198 1,
4199 2,
4200]"#,
4201 r#"[
4202 2,
4203]"#,
4204 );
4205
4206 run_test(
4207 1,
4208 r#"[
4209 1, // other comment
4210 2, // trailing comment
4211]"#,
4212 r#"[
4213 1, // other comment
4214]"#,
4215 );
4216
4217 run_test(
4218 1,
4219 r#"[
4220 1, // comment
4221 2
4222]"#,
4223 r#"[
4224 1 // comment
4225]"#,
4226 );
4227
4228 run_test(1, r#"[1, 2]"#, r#"[1]"#);
4229 run_test(1, r#"[ 1, 2 /* test */ ]"#, r#"[ 1 ]"#);
4230 run_test(1, r#"[1, /* test */ 2]"#, r#"[1]"#);
4231 run_test(
4232 1,
4233 r#"[1 /* a */, /* b */ 2 /* c */, /* d */ true]"#,
4234 r#"[1 /* a */, /* d */ true]"#,
4235 );
4236 }
4237
4238 #[test]
4239 fn insert_array_element() {
4240 #[track_caller]
4241 fn run_test(index: usize, value: CstInputValue, json: &str, expected: &str) {
4242 let cst = build_cst(json);
4243 let root_value = cst.value().unwrap();
4244 let root_array = root_value.as_array().unwrap();
4245 root_array.insert(index, value);
4246 assert_eq!(cst.to_string(), expected, "Initial text: {}", json);
4247 }
4248
4249 run_test(0, json!([1]), r#"[]"#, r#"[[1]]"#);
4250 run_test(0, json!([1, true, false, {}]), r#"[]"#, r#"[[1, true, false, {}]]"#);
4251 run_test(0, json!(10), r#"[]"#, r#"[10]"#);
4252 run_test(0, json!(10), r#"[1]"#, r#"[10, 1]"#);
4253 run_test(1, json!(10), r#"[1]"#, r#"[1, 10]"#);
4254 run_test(
4255 0,
4256 json!(10),
4257 r#"[
4258 1
4259]"#,
4260 r#"[
4261 10,
4262 1
4263]"#,
4264 );
4265 run_test(
4266 0,
4267 json!(10),
4268 r#"[
4269 /* test */ 1
4270]"#,
4271 r#"[
4272 10,
4273 /* test */ 1
4274]"#,
4275 );
4276
4277 run_test(
4278 0,
4279 json!({
4280 "value": 1,
4281 }),
4282 r#"[]"#,
4283 r#"[
4284 {
4285 "value": 1
4286 }
4287]"#,
4288 );
4289
4290 run_test(
4292 0,
4293 json!({
4294 "value": 1,
4295 }),
4296 r#"[
4297 // comment
4298]"#,
4299 r#"[
4300 // comment
4301 {
4302 "value": 1
4303 }
4304]"#,
4305 );
4306
4307 run_test(
4309 0,
4310 json!({
4311 "value": 1,
4312 }),
4313 r#"[
4314
4315]"#,
4316 r#"[
4317 {
4318 "value": 1
4319 }
4320]"#,
4321 );
4322 }
4323
4324 #[test]
4325 fn append_to_multiline_array_does_not_expose_phantom_string_lit() {
4326 let cst = build_cst(
4328 r#"{
4329 "servers": [
4330 {"name": "linear"},
4331 {"name": "supabase"}
4332 ]
4333}"#,
4334 );
4335 let arr = cst.object_value_or_create().unwrap().array_value("servers").unwrap();
4336 arr.append(CstInputValue::Object(vec![(
4337 "name".to_string(),
4338 CstInputValue::String("github".to_string()),
4339 )]));
4340
4341 let elements = arr.elements();
4342 assert_eq!(elements.len(), 3);
4343 for el in &elements {
4344 assert!(
4345 el.as_string_lit().is_none(),
4346 "element should not be a string lit: {:?}",
4347 el
4348 );
4349 assert!(el.as_object().is_some(), "element should be an object: {:?}", el);
4350 }
4351 }
4352
4353 #[test]
4354 fn insert_array_element_trailing_commas() {
4355 let cst = build_cst(
4356 r#"{
4357 "prop": [
4358 1,
4359 2,
4360 ]
4361}"#,
4362 );
4363 cst
4364 .object_value_or_create()
4365 .unwrap()
4366 .array_value("prop")
4367 .unwrap()
4368 .append(json!(3));
4369 assert_eq!(
4370 cst.to_string(),
4371 r#"{
4372 "prop": [
4373 1,
4374 2,
4375 3,
4376 ]
4377}"#
4378 );
4379 }
4380
4381 #[test]
4382 fn remove_comment() {
4383 #[track_caller]
4384 fn run_test(json: &str, expected: &str) {
4385 let cst = build_cst(json);
4386 let root_value = cst.value().unwrap();
4387 let root_obj = root_value.as_object().unwrap();
4388 root_obj
4389 .children()
4390 .into_iter()
4391 .filter_map(|c| c.as_comment())
4392 .next()
4393 .unwrap()
4394 .remove();
4395 assert_eq!(cst.to_string(), expected);
4396 }
4397
4398 run_test(
4399 r#"{
4400 "value": 5,
4401 // comment
4402 "value2": "hello",
4403 value3: true
4404}"#,
4405 r#"{
4406 "value": 5,
4407 "value2": "hello",
4408 value3: true
4409}"#,
4410 );
4411
4412 run_test(
4413 r#"{
4414 "value": 5, // comment
4415 "value2": "hello",
4416 value3: true
4417}"#,
4418 r#"{
4419 "value": 5,
4420 "value2": "hello",
4421 value3: true
4422}"#,
4423 );
4424 }
4425
4426 #[test]
4427 fn object_value_or_create() {
4428 {
4430 let cst = build_cst(r#"{ "value": 1 }"#);
4431 let obj = cst.object_value_or_create().unwrap();
4432 assert!(obj.get("value").is_some());
4433 }
4434 {
4436 let cst = build_cst(r#""#);
4437 cst.object_value_or_create().unwrap();
4438 assert_eq!(cst.to_string(), "{}\n");
4439 }
4440 {
4442 let cst = build_cst("// Copyright something");
4443 cst.object_value_or_create().unwrap();
4444 assert_eq!(cst.to_string(), "// Copyright something\n{}\n");
4445 }
4446 {
4448 let cst = build_cst("// Copyright something\n");
4449 cst.object_value_or_create().unwrap();
4450 assert_eq!(cst.to_string(), "// Copyright something\n{}\n");
4451 }
4452 }
4453
4454 #[test]
4455 fn array_ensure_multiline() {
4456 {
4458 let cst = build_cst(r#"[]"#);
4459 cst.value().unwrap().as_array().unwrap().ensure_multiline();
4460 assert_eq!(cst.to_string(), "[\n]");
4461 }
4462 {
4464 let cst = build_cst(r#"[ ]"#);
4465 cst.value().unwrap().as_array().unwrap().ensure_multiline();
4466 assert_eq!(cst.to_string(), "[\n]");
4467 }
4468 {
4470 let cst = build_cst(r#"[ /* test */ ]"#);
4471 cst.value().unwrap().as_array().unwrap().ensure_multiline();
4472 assert_eq!(cst.to_string(), "[\n /* test */\n]");
4473 }
4474 {
4476 let cst = build_cst(r#"[ 1, 2, /* test */ 3 ]"#);
4477 cst.value().unwrap().as_array().unwrap().ensure_multiline();
4478 assert_eq!(
4479 cst.to_string(),
4480 r#"[
4481 1,
4482 2,
4483 /* test */ 3
4484]"#
4485 );
4486 }
4487 {
4489 let cst = build_cst(
4490 r#"{
4491 "prop": {
4492 "value": [ 1, 2, /* test */ 3 ]
4493 }
4494}"#,
4495 );
4496 cst
4497 .value()
4498 .unwrap()
4499 .as_object()
4500 .unwrap()
4501 .get("prop")
4502 .unwrap()
4503 .value()
4504 .unwrap()
4505 .as_object()
4506 .unwrap()
4507 .get("value")
4508 .unwrap()
4509 .value()
4510 .unwrap()
4511 .as_array()
4512 .unwrap()
4513 .ensure_multiline();
4514 assert_eq!(
4515 cst.to_string(),
4516 r#"{
4517 "prop": {
4518 "value": [
4519 1,
4520 2,
4521 /* test */ 3
4522 ]
4523 }
4524}"#
4525 );
4526 }
4527 {
4529 let cst = build_cst("[ 1, 2, /* test */ 3 ]\r\n");
4530 cst.value().unwrap().as_array().unwrap().ensure_multiline();
4531 assert_eq!(cst.to_string(), "[\r\n 1,\r\n 2,\r\n /* test */ 3\r\n]\r\n");
4532 }
4533 }
4534
4535 #[test]
4536 fn object_ensure_multiline() {
4537 {
4539 let cst = build_cst(r#"{}"#);
4540 cst.value().unwrap().as_object().unwrap().ensure_multiline();
4541 assert_eq!(cst.to_string(), "{\n}");
4542 }
4543 {
4545 let cst = build_cst(r#"{ }"#);
4546 cst.value().unwrap().as_object().unwrap().ensure_multiline();
4547 assert_eq!(cst.to_string(), "{\n}");
4548 }
4549 {
4551 let cst = build_cst(r#"{ /* test */ }"#);
4552 cst.value().unwrap().as_object().unwrap().ensure_multiline();
4553 assert_eq!(cst.to_string(), "{\n /* test */\n}");
4554 }
4555 {
4557 let cst = build_cst(r#"{ prop: 1, prop2: 2, /* test */ prop3: 3 }"#);
4558 cst.value().unwrap().as_object().unwrap().ensure_multiline();
4559 assert_eq!(
4560 cst.to_string(),
4561 r#"{
4562 prop: 1,
4563 prop2: 2,
4564 /* test */ prop3: 3
4565}"#
4566 );
4567 }
4568 {
4570 let cst = build_cst(
4571 r#"{
4572 "prop": {
4573 "value": { prop: 1, prop2: 2, /* test */ prop3: 3 }
4574 }
4575}"#,
4576 );
4577 cst
4578 .value()
4579 .unwrap()
4580 .as_object()
4581 .unwrap()
4582 .get("prop")
4583 .unwrap()
4584 .value()
4585 .unwrap()
4586 .as_object()
4587 .unwrap()
4588 .get("value")
4589 .unwrap()
4590 .value()
4591 .unwrap()
4592 .as_object()
4593 .unwrap()
4594 .ensure_multiline();
4595 assert_eq!(
4596 cst.to_string(),
4597 r#"{
4598 "prop": {
4599 "value": {
4600 prop: 1,
4601 prop2: 2,
4602 /* test */ prop3: 3
4603 }
4604 }
4605}"#
4606 );
4607 }
4608 }
4609
4610 #[test]
4611 fn sets_trailing_commas() {
4612 fn run_test(input: &str, mode: crate::cst::TrailingCommaMode, expected: &str) {
4613 let cst = build_cst(input);
4614 let root_value = cst.value().unwrap();
4615 let root_obj = root_value.as_object().unwrap();
4616 root_obj.set_trailing_commas(mode);
4617 assert_eq!(cst.to_string(), expected);
4618 }
4619
4620 run_test(
4622 r#"{
4623}"#,
4624 TrailingCommaMode::Never,
4625 r#"{
4626}"#,
4627 );
4628 run_test(
4629 r#"{
4630 // test
4631}"#,
4632 TrailingCommaMode::IfMultiline,
4633 r#"{
4634 // test
4635}"#,
4636 );
4637
4638 run_test(r#"{"a": 1}"#, TrailingCommaMode::Never, r#"{"a": 1}"#);
4640 run_test(r#"{"a": 1}"#, TrailingCommaMode::IfMultiline, r#"{"a": 1}"#);
4641 run_test(
4643 r#"{
4644 "a": 1,
4645 "b": 2,
4646 "c": [1, 2, 3],
4647 "d": [
4648 1
4649 ]
4650}"#,
4651 TrailingCommaMode::IfMultiline,
4652 r#"{
4653 "a": 1,
4654 "b": 2,
4655 "c": [1, 2, 3],
4656 "d": [
4657 1,
4658 ],
4659}"#,
4660 );
4661 run_test(
4662 r#"{
4663"a": 1,
4664"b": 2,
4665}"#,
4666 TrailingCommaMode::Never,
4667 r#"{
4668"a": 1,
4669"b": 2
4670}"#,
4671 );
4672 }
4673
4674 #[test]
4675 fn or_create_methods() {
4676 let cst = build_cst("");
4677 let obj = cst.object_value_or_create().unwrap();
4678 assert_eq!(cst.to_string(), "{}\n");
4679 assert!(cst.array_value_or_create().is_none());
4680 assert_eq!(obj.object_value_or_create("prop").unwrap().to_string(), "{}");
4681 assert!(obj.array_value_or_create("prop").is_none());
4682 assert_eq!(obj.array_value_or_create("prop2").unwrap().to_string(), "[]");
4683 assert_eq!(
4684 cst.to_string(),
4685 r#"{
4686 "prop": {},
4687 "prop2": []
4688}
4689"#
4690 );
4691 }
4692
4693 #[test]
4694 fn or_set_methods() {
4695 let cst = build_cst("");
4696 let array = cst.array_value_or_set();
4697 assert_eq!(array.to_string(), "[]");
4698 assert_eq!(cst.to_string(), "[]\n");
4699 let object = cst.object_value_or_set();
4700 assert_eq!(object.to_string(), "{}");
4701 assert_eq!(cst.to_string(), "{}\n");
4702 let value = object.array_value_or_set("test");
4703 assert_eq!(value.to_string(), "[]");
4704 assert_eq!(cst.to_string(), "{\n \"test\": []\n}\n");
4705 let value = object.object_value_or_set("test");
4706 assert_eq!(value.to_string(), "{}");
4707 assert_eq!(cst.to_string(), "{\n \"test\": {}\n}\n");
4708 let value = object.array_value_or_set("test");
4709 assert_eq!(value.to_string(), "[]");
4710 assert_eq!(cst.to_string(), "{\n \"test\": []\n}\n");
4711 value.append(json!(1));
4712 assert_eq!(cst.to_string(), "{\n \"test\": [1]\n}\n");
4713 let value = object.object_value_or_set("test");
4714 assert_eq!(value.to_string(), "{}");
4715 assert_eq!(cst.to_string(), "{\n \"test\": {}\n}\n");
4716 let test_prop = object.get("test").unwrap();
4717 assert!(test_prop.object_value().is_some());
4718 assert!(test_prop.array_value().is_none());
4719 test_prop.array_value_or_set();
4720 assert_eq!(cst.to_string(), "{\n \"test\": []\n}\n");
4721 assert!(test_prop.object_value().is_none());
4722 assert!(test_prop.array_value().is_some());
4723 test_prop.object_value_or_set();
4724 assert_eq!(cst.to_string(), "{\n \"test\": {}\n}\n");
4725 }
4726
4727 #[test]
4728 fn expression_properties_and_values() {
4729 #[track_caller]
4730 fn run_test(value: CstInputValue, expected: &str) {
4731 let cst = build_cst("");
4732 cst.set_value(value);
4733 assert_eq!(cst.to_string(), format!("{}\n", expected));
4734 }
4735
4736 run_test(json!(1), "1");
4737 run_test(json!("test"), "\"test\"");
4738 {
4739 let text = "test";
4740 run_test(json!(text), "\"test\"");
4741 }
4742 {
4743 let num = 1;
4744 run_test(json!(num), "1");
4745 }
4746 {
4747 let vec = vec![1, 2, 3];
4748 run_test(json!(vec), "[1, 2, 3]");
4749 }
4750 {
4751 let vec = vec![1, 2, 3];
4752 run_test(
4753 json!({
4754 "value": vec,
4755 }),
4756 r#"{
4757 "value": [1, 2, 3]
4758}"#,
4759 );
4760 }
4761 run_test(
4762 json!({
4763 notQuoted: 1,
4764 "quoted": 2,
4765 }),
4766 r#"{
4767 "notQuoted": 1,
4768 "quoted": 2
4769}"#,
4770 )
4771 }
4772
4773 #[test]
4774 fn property_index() {
4775 let cst = build_cst("{ \"prop\": 1, \"prop2\": 2, \"prop3\": 3 }");
4776 let object = cst.object_value().unwrap();
4777 for (i, prop) in object.properties().into_iter().enumerate() {
4778 assert_eq!(prop.property_index(), i);
4779 }
4780 }
4781
4782 #[test]
4783 fn element_index() {
4784 let cst = build_cst("[1, 2, true ,false]");
4785 let array = cst.array_value().unwrap();
4786 for (i, prop) in array.elements().into_iter().enumerate() {
4787 assert_eq!(prop.element_index().unwrap(), i);
4788 }
4789 }
4790
4791 #[test]
4792 fn missing_comma_between_array_elements() {
4793 build_cst("[1 2]");
4794
4795 let options = crate::ParseOptions {
4797 allow_missing_commas: false,
4798 ..Default::default()
4799 };
4800 assert_eq!(
4801 CstRootNode::parse("[1 2]", &options).err().unwrap().to_string(),
4802 "Expected comma on line 1 column 3"
4803 );
4804 CstRootNode::parse("[1, 2]", &options).unwrap();
4805 }
4806
4807 #[test]
4808 fn sort_properties() {
4809 #[track_caller]
4810 fn run_test(json: &str, expected: &str) {
4811 let cst = build_cst(json);
4812 let root_obj = cst.object_value().unwrap();
4813 root_obj.sort_properties().by_key(|prop| prop.decoded_name());
4814 assert_eq!(cst.to_string(), expected);
4815 build_cst(&cst.to_string());
4817 let sorted = cst.to_string();
4818 root_obj.sort_properties().by_key(|prop| prop.decoded_name());
4819 assert_eq!(cst.to_string(), sorted);
4820 }
4821
4822 run_test("{\n \"b\": 2,\n \"a\": 1\n}", "{\n \"a\": 1,\n \"b\": 2\n}");
4823 run_test("{ \"b\": 2, \"a\": 1 }", "{ \"a\": 1, \"b\": 2 }");
4825 run_test("{\"b\":2,\"a\":1}", "{\"a\":1,\"b\":2}");
4826 run_test("{\n \"b\": 2,\n \"a\": 1,\n}", "{\n \"a\": 1,\n \"b\": 2,\n}");
4828 run_test("{}", "{}");
4830 run_test("{ \"a\": 1 }", "{ \"a\": 1 }");
4831 run_test("{\n \"a\": 1,\n \"b\": 2\n}", "{\n \"a\": 1,\n \"b\": 2\n}");
4832 run_test(
4834 "{\n \"b\": { \"z\": 1 },\n \"a\": [3, 1]\n}",
4835 "{\n \"a\": [3, 1],\n \"b\": { \"z\": 1 }\n}",
4836 );
4837 run_test("{\n b: 2,\n a: 1\n}", "{\n a: 1,\n b: 2\n}");
4839 run_test(
4841 "{\n \"b\": 2,\n \"\\u0061\": 1\n}",
4842 "{\n \"\\u0061\": 1,\n \"b\": 2\n}",
4843 );
4844 run_test(
4846 "{\n \"b\": 2,\n \"a\": \"first\",\n \"a\": \"second\"\n}",
4847 "{\n \"a\": \"first\",\n \"a\": \"second\",\n \"b\": 2\n}",
4848 );
4849 run_test("{\n \"b\": 2\n \"a\": 1\n}", "{\n \"a\": 1,\n \"b\": 2\n}");
4851 run_test("{\n \"b\": 2\n , \"a\": 1\n}", "{\n \"a\": 1, \"b\": 2\n\n}");
4853 run_test("{ \"b\": 2 , \"a\": 1 }", "{ \"a\": 1, \"b\": 2 }");
4855 run_test("{\n \"b\": 2, \"a\": 1\n}", "{\n \"a\": 1, \"b\": 2\n}");
4857 run_test(
4859 "{\r\n \"b\": 2,\r\n \"a\": 1\r\n}",
4860 "{\r\n \"a\": 1,\r\n \"b\": 2\r\n}",
4861 );
4862 }
4863
4864 #[test]
4865 fn sort_properties_moves_comments_and_blank_lines() {
4866 #[track_caller]
4867 fn run_test(json: &str, expected: &str) {
4868 let cst = build_cst(json);
4869 let root_obj = cst.object_value().unwrap();
4870 root_obj.sort_properties().by_key(|prop| prop.decoded_name());
4871 assert_eq!(cst.to_string(), expected);
4872 build_cst(&cst.to_string());
4873 let sorted = cst.to_string();
4874 root_obj.sort_properties().by_key(|prop| prop.decoded_name());
4875 assert_eq!(cst.to_string(), sorted);
4876 }
4877
4878 run_test(
4880 "{\n // about b\n \"b\": 2,\n \"a\": 1\n}",
4881 "{\n \"a\": 1,\n // about b\n \"b\": 2\n}",
4882 );
4883 run_test(
4885 "{\n \"b\": 2, // about b\n \"a\": 1\n}",
4886 "{\n \"a\": 1,\n \"b\": 2 // about b\n}",
4887 );
4888 run_test(
4890 "{\n \"b\": 2,\n \"a\": 1 // about a\n}",
4891 "{\n \"a\": 1, // about a\n \"b\": 2\n}",
4892 );
4893 run_test(
4895 "{ // about the object\n \"b\": 2,\n \"a\": 1\n}",
4896 "{ // about the object\n \"a\": 1,\n \"b\": 2\n}",
4897 );
4898 run_test(
4900 "{\n \"b\": 2,\n \"a\": 1\n // dangling\n}",
4901 "{\n \"a\": 1,\n \"b\": 2\n // dangling\n}",
4902 );
4903 run_test(
4905 "{ \"b\": 2, /* between */ \"a\": 1 }",
4906 "{ /* between */ \"a\": 1, \"b\": 2 }",
4907 );
4908 run_test(
4910 "{\n /* about b */\n \"b\": 2,\n \"a\": 1\n}",
4911 "{\n \"a\": 1,\n /* about b */\n \"b\": 2\n}",
4912 );
4913 run_test(
4915 "{\n \"c\": 3,\n \"a\": 1,\n\n \"b\": 2\n}",
4916 "{\n \"a\": 1,\n\n \"b\": 2,\n \"c\": 3\n}",
4917 );
4918 run_test("{\n \"b\": 2,\n\n \"a\": 1\n}", "{\n \"a\": 1,\n \"b\": 2\n}");
4920 }
4921
4922 #[test]
4923 fn sort_properties_pinning_comment_headers() {
4924 #[track_caller]
4925 fn run_test(json: &str, expected: &str) {
4926 let cst = build_cst(json);
4927 let root_obj = cst.object_value().unwrap();
4928 root_obj
4929 .sort_properties()
4930 .pin_comment_headers()
4931 .by_key(|prop| prop.decoded_name());
4932 assert_eq!(cst.to_string(), expected);
4933 build_cst(&cst.to_string());
4934 }
4935
4936 run_test(
4938 "{\n \"prop\": 1,\n\n // section\n \"prop2\": 2,\n \"prop1\": 1\n}",
4939 "{\n \"prop\": 1,\n\n // section\n \"prop1\": 1,\n \"prop2\": 2\n}",
4940 );
4941 run_test(
4943 "{\n // about b\n \"b\": 2,\n \"a\": 1\n}",
4944 "{\n \"a\": 1,\n // about b\n \"b\": 2\n}",
4945 );
4946 run_test(
4948 "{\n \"c\": 3,\n\n // section\n // about b\n \"b\": 2,\n \"a\": 1\n}",
4949 "{\n \"a\": 1,\n\n // section\n // about b\n \"b\": 2,\n \"c\": 3\n}",
4950 );
4951 run_test(
4953 "{\n \"c\": 3,\n\n \"b\": 2,\n \"a\": 1\n}",
4954 "{\n \"a\": 1,\n\n \"b\": 2,\n \"c\": 3\n}",
4955 );
4956 run_test(
4958 "{\n\n // first\n \"d\": 4,\n \"c\": 3,\n\n // second\n \"b\": 2,\n \"a\": 1\n}",
4959 "{\n\n // first\n \"a\": 1,\n \"b\": 2,\n\n // second\n \"c\": 3,\n \"d\": 4\n}",
4960 );
4961 run_test(
4963 "{\n \"c\": 3,\n\n /* section */\n \"b\": 2,\n \"a\": 1\n}",
4964 "{\n \"a\": 1,\n\n /* section */\n \"b\": 2,\n \"c\": 3\n}",
4965 );
4966 run_test("{\n \"b\": 2,\n \"a\": 1\n}", "{\n \"a\": 1,\n \"b\": 2\n}");
4968 }
4969
4970 #[test]
4971 fn sort_properties_within_groups() {
4972 #[track_caller]
4973 fn run_test(json: &str, expected: &str) {
4974 let cst = build_cst(json);
4975 let root_obj = cst.object_value().unwrap();
4976 root_obj
4977 .sort_properties()
4978 .within_groups()
4979 .by_key(|prop| prop.decoded_name());
4980 assert_eq!(cst.to_string(), expected);
4981 build_cst(&cst.to_string());
4982 }
4983
4984 run_test(
4986 "{\n \"m\": 1,\n\n // section\n \"z\": 2,\n \"a\": 3\n}",
4987 "{\n \"m\": 1,\n\n // section\n \"a\": 3,\n \"z\": 2\n}",
4988 );
4989 run_test(
4991 "{\n \"d\": 4,\n \"c\": 3,\n\n \"b\": 2,\n \"a\": 1\n}",
4992 "{\n \"c\": 3,\n \"d\": 4,\n\n \"a\": 1,\n \"b\": 2\n}",
4993 );
4994 run_test(
4996 "{\n \"b\": 2,\n\n \"d\": 4,\n \"c\": 3,\n}",
4997 "{\n \"b\": 2,\n\n \"c\": 3,\n \"d\": 4,\n}",
4998 );
4999 run_test("{\n \"b\": 2,\n\n \"a\": 1\n}", "{\n \"b\": 2,\n\n \"a\": 1\n}");
5001 run_test("{\n \"b\": 2,\n \"a\": 1\n}", "{\n \"a\": 1,\n \"b\": 2\n}");
5003 run_test(
5005 "{\n \"z\": 1,\n\n // section\n \"b\": 2,\n \"a\": 3\n}",
5006 "{\n \"z\": 1,\n\n // section\n \"a\": 3,\n \"b\": 2\n}",
5007 );
5008 run_test(
5010 "{\n \"z\": 1,\n\n \"c\": 3,\n // about b\n \"b\": 2,\n \"a\": 0\n}",
5011 "{\n \"z\": 1,\n\n \"a\": 0,\n // about b\n \"b\": 2,\n \"c\": 3\n}",
5012 );
5013 }
5014
5015 #[test]
5016 fn sort_properties_pinning_some_of_the_comments() {
5017 #[track_caller]
5018 fn run_test(json: &str, expected: &str) {
5019 let cst = build_cst(json);
5020 let root_obj = cst.object_value().unwrap();
5021 root_obj
5023 .sort_properties()
5024 .pin_comment_headers_with(|prop, _| if prop.has_blank_line_before() { 1 } else { 0 })
5025 .by_key(|prop| prop.decoded_name());
5026 assert_eq!(cst.to_string(), expected);
5027 build_cst(&cst.to_string());
5028 }
5029
5030 run_test(
5032 "{\n \"c\": 3,\n\n // section\n // about b\n \"b\": 2,\n \"a\": 1\n}",
5033 "{\n \"a\": 1,\n\n // section\n // about b\n \"b\": 2,\n \"c\": 3\n}",
5034 );
5035 run_test(
5037 "{\n \"c\": 3,\n\n // section\n\n // about b\n \"b\": 2,\n \"a\": 1\n}",
5038 "{\n \"a\": 1,\n\n // section\n\n // about b\n \"b\": 2,\n \"c\": 3\n}",
5039 );
5040 }
5041
5042 #[test]
5043 fn sort_gives_up_when_the_comparator_changes_the_object() {
5044 let text = "{
5045 \"b\": 2,
5046 \"a\": 1
5047}";
5048 let cst = build_cst(text);
5049 let root_obj = cst.object_value().unwrap();
5050 root_obj.sort_properties().by_key(|prop| {
5051 if prop.decoded_name().as_deref() == Some("b") {
5053 prop.clone().remove();
5054 }
5055 prop.decoded_name()
5056 });
5057
5058 assert_eq!(
5060 cst.to_string(),
5061 "{
5062 \"a\": 1
5063}"
5064 );
5065 }
5066
5067 #[test]
5068 fn sort_gives_up_when_the_comparator_replaces_a_member() {
5069 let cst = build_cst("{\n \"b\": 2,\n \"a\": 1\n}");
5070 let root_obj = cst.object_value().unwrap();
5071 root_obj.sort_properties().by_key(|prop| {
5072 let name = prop.decoded_name();
5073 if name.as_deref() == Some("b") {
5075 prop.clone().replace_with("zzz", json!(9));
5076 }
5077 name
5078 });
5079
5080 assert_eq!(cst.to_string(), "{\n \"zzz\": 9,\n \"a\": 1\n}");
5082 }
5083
5084 #[test]
5085 fn sort_keeps_line_comments_ending_their_line() {
5086 #[track_caller]
5087 fn run_test(json: &str, expected: &str) {
5088 let cst = build_cst(json);
5089 let root_obj = cst.object_value().unwrap();
5090 root_obj.sort_properties().by_key(|prop| prop.decoded_name());
5091 assert_eq!(cst.to_string(), expected);
5092 build_cst(&cst.to_string());
5094 let sorted = cst.to_string();
5095 root_obj.sort_properties().by_key(|prop| prop.decoded_name());
5096 assert_eq!(cst.to_string(), sorted);
5097 }
5098
5099 run_test(
5101 "{\"b\": 2, \"a\": 1 // about a\n}",
5102 "{\"a\": 1, // about a\n \"b\": 2\n}",
5103 );
5104 run_test(
5106 "{ \"b\": 2, // about b\n \"a\": 1 }",
5107 "{ \"a\": 1,\n \"b\": 2 // about b\n }",
5108 );
5109 run_test(
5111 "{\"b\": 2, \"a\": 1 /* about a */}",
5112 "{\"a\": 1, /* about a */ \"b\": 2}",
5113 );
5114 }
5115
5116 #[test]
5117 fn sort_properties_keeps_the_tree_usable() {
5118 let cst = build_cst("{\n \"b\": 2,\n \"a\": 1\n}");
5119 let root_obj = cst.object_value().unwrap();
5120 let b = root_obj.get("b").unwrap();
5121 root_obj.sort_properties().by_key(|prop| prop.decoded_name());
5122
5123 assert_eq!(b.decoded_name().unwrap(), "b");
5125 assert_eq!(b.property_index(), 1);
5126 assert_eq!(
5127 root_obj
5128 .properties()
5129 .iter()
5130 .map(|p| p.decoded_name().unwrap())
5131 .collect::<Vec<_>>(),
5132 ["a", "b"]
5133 );
5134 b.set_value(json!(3));
5136 assert_eq!(cst.to_string(), "{\n \"a\": 1,\n \"b\": 3\n}");
5137 }
5138
5139 #[test]
5140 fn sort_elements() {
5141 #[track_caller]
5142 fn run_test(json: &str, expected: &str) {
5143 let cst = build_cst(json);
5144 let array = cst.array_value().unwrap();
5145 array.sort_elements().by_key(|element| element.to_string());
5146 assert_eq!(cst.to_string(), expected);
5147 build_cst(&cst.to_string());
5148 let sorted = cst.to_string();
5149 array.sort_elements().by_key(|element| element.to_string());
5150 assert_eq!(cst.to_string(), sorted);
5151 }
5152
5153 run_test("[3, 1, 2]", "[1, 2, 3]");
5154 run_test("[\n 3,\n 1\n]", "[\n 1,\n 3\n]");
5155 run_test("[\n 3,\n 1,\n]", "[\n 1,\n 3,\n]");
5157 run_test("[\n // about 3\n 3,\n 1\n]", "[\n 1,\n // about 3\n 3\n]");
5159 run_test("[\n 3, // about 3\n 1\n]", "[\n 1,\n 3 // about 3\n]");
5161 run_test("[2, // about 2\n1]", "[1,\n2 // about 2\n]");
5163 run_test("[\n 3,\n\n 1\n]", "[\n 1,\n 3\n]");
5165 run_test("[]", "[]");
5167 run_test("[1]", "[1]");
5168 run_test("[\n [3, 2],\n {\"a\": 1}\n]", "[\n [3, 2],\n {\"a\": 1}\n]");
5170 }
5171
5172 #[track_caller]
5173 fn build_cst(text: &str) -> CstRootNode {
5174 CstRootNode::parse(text, &crate::ParseOptions::default()).unwrap()
5175 }
5176
5177 #[cfg(feature = "serde_json")]
5178 mod serde_tests {
5179 use super::build_cst;
5180 use serde_json::Value as SerdeValue;
5181 use std::str::FromStr;
5182
5183 #[test]
5184 fn test_cst_to_serde_value_primitives() {
5185 let root = build_cst(r#"42"#);
5186 let value = root.to_serde_value().unwrap();
5187 assert_eq!(value, SerdeValue::Number(serde_json::Number::from_str("42").unwrap()));
5188
5189 let root = build_cst(r#""hello""#);
5190 let value = root.to_serde_value().unwrap();
5191 assert_eq!(value, SerdeValue::String("hello".to_string()));
5192
5193 let root = build_cst(r#"true"#);
5194 let value = root.to_serde_value().unwrap();
5195 assert_eq!(value, SerdeValue::Bool(true));
5196
5197 let root = build_cst(r#"false"#);
5198 let value = root.to_serde_value().unwrap();
5199 assert_eq!(value, SerdeValue::Bool(false));
5200
5201 let root = build_cst(r#"null"#);
5202 let value = root.to_serde_value().unwrap();
5203 assert_eq!(value, SerdeValue::Null);
5204 }
5205
5206 #[test]
5207 fn test_cst_to_serde_value_array() {
5208 let root = build_cst(r#"[1, 2, 3]"#);
5209 let value = root.to_serde_value().unwrap();
5210 let expected = SerdeValue::Array(vec![
5211 SerdeValue::Number(serde_json::Number::from_str("1").unwrap()),
5212 SerdeValue::Number(serde_json::Number::from_str("2").unwrap()),
5213 SerdeValue::Number(serde_json::Number::from_str("3").unwrap()),
5214 ]);
5215 assert_eq!(value, expected);
5216 }
5217
5218 #[test]
5219 fn test_cst_to_serde_value_array_with_comments() {
5220 let root = build_cst(
5221 r#"[
5222 // comment 1
5223 1,
5224 2, // comment 2
5225 3
5226 ]"#,
5227 );
5228 let value = root.to_serde_value().unwrap();
5229 let expected = SerdeValue::Array(vec![
5230 SerdeValue::Number(serde_json::Number::from_str("1").unwrap()),
5231 SerdeValue::Number(serde_json::Number::from_str("2").unwrap()),
5232 SerdeValue::Number(serde_json::Number::from_str("3").unwrap()),
5233 ]);
5234 assert_eq!(value, expected);
5235 }
5236
5237 #[test]
5238 fn test_cst_to_serde_value_object() {
5239 let root = build_cst(
5240 r#"{
5241 "name": "Alice",
5242 "age": 30,
5243 "active": true
5244 }"#,
5245 );
5246 let value = root.to_serde_value().unwrap();
5247
5248 let mut expected_map = serde_json::map::Map::new();
5249 expected_map.insert("name".to_string(), SerdeValue::String("Alice".to_string()));
5250 expected_map.insert(
5251 "age".to_string(),
5252 SerdeValue::Number(serde_json::Number::from_str("30").unwrap()),
5253 );
5254 expected_map.insert("active".to_string(), SerdeValue::Bool(true));
5255
5256 assert_eq!(value, SerdeValue::Object(expected_map));
5257 }
5258
5259 #[test]
5260 fn test_cst_to_serde_value_object_with_comments() {
5261 let root = build_cst(
5262 r#"{
5263 // This is a name
5264 "name": "Bob",
5265 /* age field */
5266 "age": 25
5267 }"#,
5268 );
5269 let value = root.to_serde_value().unwrap();
5270
5271 let mut expected_map = serde_json::map::Map::new();
5272 expected_map.insert("name".to_string(), SerdeValue::String("Bob".to_string()));
5273 expected_map.insert(
5274 "age".to_string(),
5275 SerdeValue::Number(serde_json::Number::from_str("25").unwrap()),
5276 );
5277
5278 assert_eq!(value, SerdeValue::Object(expected_map));
5279 }
5280
5281 #[test]
5282 fn test_cst_to_serde_value_nested() {
5283 let root = build_cst(
5284 r#"{
5285 "person": {
5286 "name": "Charlie",
5287 "hobbies": ["reading", "gaming"]
5288 },
5289 "count": 42
5290 }"#,
5291 );
5292 let value = root.to_serde_value().unwrap();
5293
5294 let mut hobbies = Vec::new();
5295 hobbies.push(SerdeValue::String("reading".to_string()));
5296 hobbies.push(SerdeValue::String("gaming".to_string()));
5297
5298 let mut person_map = serde_json::map::Map::new();
5299 person_map.insert("name".to_string(), SerdeValue::String("Charlie".to_string()));
5300 person_map.insert("hobbies".to_string(), SerdeValue::Array(hobbies));
5301
5302 let mut expected_map = serde_json::map::Map::new();
5303 expected_map.insert("person".to_string(), SerdeValue::Object(person_map));
5304 expected_map.insert(
5305 "count".to_string(),
5306 SerdeValue::Number(serde_json::Number::from_str("42").unwrap()),
5307 );
5308
5309 assert_eq!(value, SerdeValue::Object(expected_map));
5310 }
5311
5312 #[test]
5313 fn test_cst_to_serde_value_with_trailing_comma() {
5314 let root = build_cst(
5315 r#"{
5316 "a": 1,
5317 "b": 2,
5318 }"#,
5319 );
5320 let value = root.to_serde_value().unwrap();
5321
5322 let mut expected_map = serde_json::map::Map::new();
5323 expected_map.insert(
5324 "a".to_string(),
5325 SerdeValue::Number(serde_json::Number::from_str("1").unwrap()),
5326 );
5327 expected_map.insert(
5328 "b".to_string(),
5329 SerdeValue::Number(serde_json::Number::from_str("2").unwrap()),
5330 );
5331
5332 assert_eq!(value, SerdeValue::Object(expected_map));
5333 }
5334
5335 #[test]
5336 fn test_cst_to_serde_value_empty_structures() {
5337 let root = build_cst(r#"{}"#);
5338 let value = root.to_serde_value().unwrap();
5339 assert_eq!(value, SerdeValue::Object(serde_json::map::Map::new()));
5340
5341 let root = build_cst(r#"[]"#);
5342 let value = root.to_serde_value().unwrap();
5343 assert_eq!(value, SerdeValue::Array(Vec::new()));
5344 }
5345
5346 #[test]
5347 fn test_cst_to_serde_value_scientific_notation() {
5348 let root = build_cst(r#"0.3e+025"#);
5349 let value = root.to_serde_value().unwrap();
5350 assert_eq!(
5351 value,
5352 SerdeValue::Number(serde_json::Number::from_str("0.3e+025").unwrap())
5353 );
5354 }
5355
5356 #[test]
5357 fn test_cst_node_to_serde_value() {
5358 let root = build_cst(r#"{ "test": 123 }"#);
5359 let value_node = root.value().unwrap();
5360 let json_value = value_node.to_serde_value().unwrap();
5361
5362 let mut expected_map = serde_json::map::Map::new();
5363 expected_map.insert(
5364 "test".to_string(),
5365 SerdeValue::Number(serde_json::Number::from_str("123").unwrap()),
5366 );
5367
5368 assert_eq!(json_value, SerdeValue::Object(expected_map));
5369 }
5370
5371 #[test]
5372 fn test_cst_object_prop_to_serde_value() {
5373 let root = build_cst(r#"{ "key": [1, 2, 3] }"#);
5374 let obj = root.value().unwrap().as_object().unwrap();
5375 let prop = obj.get("key").unwrap();
5376 let prop_value = prop.to_serde_value().unwrap();
5377
5378 let expected = SerdeValue::Array(vec![
5379 SerdeValue::Number(serde_json::Number::from_str("1").unwrap()),
5380 SerdeValue::Number(serde_json::Number::from_str("2").unwrap()),
5381 SerdeValue::Number(serde_json::Number::from_str("3").unwrap()),
5382 ]);
5383
5384 assert_eq!(prop_value, expected);
5385 }
5386 }
5387
5388 #[test]
5389 fn new_escaped_handles_backslashes() {
5390 let cst = build_cst(r#"{"key": "old"}"#);
5391 let root_obj = cst.object_value().unwrap();
5392 let prop = root_obj.get("key").unwrap();
5393 prop.set_value(json!("/.github/workflows/lint\\.yaml$/"));
5395 assert_eq!(cst.to_string(), r#"{"key": "/.github/workflows/lint\\.yaml$/"}"#,);
5396 let decoded = root_obj
5398 .get("key")
5399 .unwrap()
5400 .value()
5401 .unwrap()
5402 .as_string_lit()
5403 .unwrap()
5404 .decoded_value()
5405 .unwrap();
5406 assert_eq!(decoded, "/.github/workflows/lint\\.yaml$/");
5407 }
5408
5409 #[test]
5410 fn new_escaped_handles_control_characters() {
5411 let cst = build_cst(r#"{}"#);
5412 let root_obj = cst.object_value_or_create().unwrap();
5413
5414 root_obj.append("tab", json!("hello\tworld"));
5415 root_obj.append("newline", json!("hello\nworld"));
5416 root_obj.append("cr", json!("hello\rworld"));
5417 root_obj.append("backspace", json!("hello\u{08}world"));
5418 root_obj.append("formfeed", json!("hello\u{0c}world"));
5419
5420 let text = cst.to_string();
5421 assert!(text.contains(r#""hello\tworld""#), "tab not escaped: {}", text);
5422 assert!(text.contains(r#""hello\nworld""#), "newline not escaped: {}", text);
5423 assert!(text.contains(r#""hello\rworld""#), "cr not escaped: {}", text);
5424 assert!(text.contains(r#""hello\bworld""#), "backspace not escaped: {}", text);
5425 assert!(text.contains(r#""hello\fworld""#), "formfeed not escaped: {}", text);
5426
5427 for (key, expected) in [
5429 ("tab", "hello\tworld"),
5430 ("newline", "hello\nworld"),
5431 ("cr", "hello\rworld"),
5432 ("backspace", "hello\u{08}world"),
5433 ("formfeed", "hello\u{0c}world"),
5434 ] {
5435 let decoded = root_obj
5436 .get(key)
5437 .unwrap()
5438 .value()
5439 .unwrap()
5440 .as_string_lit()
5441 .unwrap()
5442 .decoded_value()
5443 .unwrap();
5444 assert_eq!(decoded, expected, "roundtrip failed for key: {}", key);
5445 }
5446 }
5447
5448 #[test]
5449 fn new_escaped_handles_quotes_and_backslashes_together() {
5450 let cst = build_cst(r#"{}"#);
5451 let root_obj = cst.object_value_or_create().unwrap();
5452
5453 root_obj.append("mixed", json!("say \"hello\\world\""));
5454
5455 let text = cst.to_string();
5456 assert!(
5457 text.contains(r#""say \"hello\\world\"""#),
5458 "mixed escaping failed: {}",
5459 text
5460 );
5461
5462 let decoded = root_obj
5463 .get("mixed")
5464 .unwrap()
5465 .value()
5466 .unwrap()
5467 .as_string_lit()
5468 .unwrap()
5469 .decoded_value()
5470 .unwrap();
5471 assert_eq!(decoded, "say \"hello\\world\"");
5472 }
5473
5474 #[test]
5475 fn new_escaped_in_array_values() {
5476 let cst = build_cst(r#"{"items": []}"#);
5477 let root_obj = cst.object_value().unwrap();
5478 let arr = root_obj.array_value("items").unwrap();
5479
5480 arr.append(json!("path\\to\\file"));
5481 arr.append(json!("line1\nline2"));
5482
5483 let text = cst.to_string();
5484 assert!(
5485 text.contains(r#""path\\to\\file""#),
5486 "backslash in array element: {}",
5487 text
5488 );
5489 assert!(text.contains(r#""line1\nline2""#), "newline in array element: {}", text);
5490 }
5491
5492 #[test]
5493 fn new_escaped_property_name_with_special_chars() {
5494 let cst = build_cst(r#"{}"#);
5495 let root_obj = cst.object_value_or_create().unwrap();
5496
5497 root_obj.append("key\\with\\backslash", json!("value"));
5498
5499 let text = cst.to_string();
5500 assert!(
5501 text.contains(r#""key\\with\\backslash""#),
5502 "property name escaping failed: {}",
5503 text
5504 );
5505
5506 let decoded = root_obj
5507 .properties()
5508 .first()
5509 .unwrap()
5510 .name()
5511 .unwrap()
5512 .decoded_value()
5513 .unwrap();
5514 assert_eq!(decoded, "key\\with\\backslash");
5515 }
5516}