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 parsed = serde_json::Number::from_str(&crate::common::fill_bare_decimal_point(raw.trim_start_matches('+')));
1522 match parsed {
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 CarriageReturn,
2376}
2377
2378#[derive(Debug, Clone)]
2380pub struct CstNewline(Rc<RefCell<CstValueInner<CstNewlineKind>>>);
2381
2382impl_leaf_methods!(CstNewline, Newline);
2383
2384impl CstNewline {
2385 fn new(kind: CstNewlineKind) -> Self {
2386 Self(CstValueInner::new(kind))
2387 }
2388
2389 pub fn kind(&self) -> CstNewlineKind {
2391 self.0.borrow().value
2392 }
2393
2394 pub fn set_kind(&self, kind: CstNewlineKind) {
2396 self.0.borrow_mut().value = kind;
2397 }
2398
2399 pub fn remove(self) {
2401 Into::<CstNode>::into(self).remove_raw()
2402 }
2403}
2404
2405impl Display for CstNewline {
2406 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2407 match self.0.borrow().value {
2408 #[allow(clippy::write_with_newline)] CstNewlineKind::LineFeed => write!(f, "\n"),
2410 CstNewlineKind::CarriageReturnLineFeed => write!(f, "\r\n"),
2411 CstNewlineKind::CarriageReturn => write!(f, "\r"),
2412 }
2413 }
2414}
2415
2416#[derive(Debug, Clone)]
2417pub struct CstComment(Rc<RefCell<CstValueInner<String>>>);
2418
2419impl_leaf_methods!(CstComment, Comment);
2420
2421impl CstComment {
2422 fn new(value: String) -> Self {
2423 Self(CstValueInner::new(value))
2424 }
2425
2426 pub fn is_line_comment(&self) -> bool {
2428 self.0.borrow().value.starts_with("//")
2429 }
2430
2431 pub fn set_raw_value(&self, value: String) {
2436 self.0.borrow_mut().value = value;
2437 }
2438
2439 pub fn raw_value(&self) -> String {
2441 self.0.borrow().value.clone()
2442 }
2443
2444 pub fn remove(self) {
2446 if self.is_line_comment() {
2447 for node in self.previous_siblings() {
2448 if node.is_whitespace() {
2449 node.remove_raw();
2450 } else {
2451 if node.is_newline() {
2452 node.remove_raw();
2453 }
2454 break;
2455 }
2456 }
2457 }
2458
2459 Into::<CstNode>::into(self).remove_raw()
2460 }
2461}
2462
2463impl Display for CstComment {
2464 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2465 write!(f, "{}", self.0.borrow().value)
2466 }
2467}
2468
2469struct CstBuilder<'a> {
2470 pub text: &'a str,
2471 pub tokens: VecDeque<crate::tokens::TokenAndRange<'a>>,
2472}
2473
2474impl<'a> CstBuilder<'a> {
2475 pub fn build(&mut self, ast_value: Option<crate::ast::Value<'a>>) -> CstRootNode {
2476 let root_node = CstContainerNode::Root(CstRootNode(Rc::new(RefCell::new(CstChildrenInner {
2477 parent: None,
2478 value: Vec::new(),
2479 }))));
2480
2481 if let Some(ast_value) = ast_value {
2482 let range = ast_value.range();
2483 self.scan_from_to(&root_node, 0, range.start);
2484 self.build_value(&root_node, ast_value);
2485 self.scan_from_to(&root_node, range.end, self.text.len());
2486 } else {
2487 self.scan_from_to(&root_node, 0, self.text.len());
2488 }
2489
2490 match root_node {
2491 CstContainerNode::Root(node) => node,
2492 _ => unreachable!(),
2493 }
2494 }
2495
2496 fn scan_from_to(&mut self, container: &CstContainerNode, from: usize, to: usize) {
2497 if from == to {
2498 return;
2499 }
2500
2501 let mut last_from = from;
2502 while let Some(token) = self.tokens.front() {
2503 if token.range.end <= from {
2504 self.tokens.pop_front();
2505 } else if token.range.start < to {
2506 if token.range.start > last_from {
2507 self.build_whitespace(container, &self.text[last_from..token.range.start]);
2508 }
2509 let token = self.tokens.pop_front().unwrap();
2510 match token.token {
2511 crate::tokens::Token::OpenBrace
2512 | crate::tokens::Token::CloseBrace
2513 | crate::tokens::Token::OpenBracket
2514 | crate::tokens::Token::CloseBracket
2515 | crate::tokens::Token::Comma
2516 | crate::tokens::Token::Colon => {
2517 self.build_token(container, token.token.as_str().chars().next().unwrap());
2518 }
2519 crate::tokens::Token::Null
2520 | crate::tokens::Token::String(_)
2521 | crate::tokens::Token::Word(_)
2522 | crate::tokens::Token::Boolean(_)
2523 | crate::tokens::Token::Number(_) => unreachable!(
2524 "programming error parsing cst {:?} scanning {} to {}",
2525 token.token, from, to
2526 ),
2527 crate::tokens::Token::CommentLine(_) | crate::tokens::Token::CommentBlock(_) => {
2528 container
2529 .raw_append_child(CstComment::new(self.text[token.range.start..token.range.end].to_string()).into());
2530 }
2531 }
2532 last_from = token.range.end;
2533 } else {
2534 break;
2535 }
2536 }
2537
2538 if last_from < to {
2539 self.build_whitespace(container, &self.text[last_from..to]);
2540 }
2541 }
2542
2543 fn build_value(&mut self, container: &CstContainerNode, ast_value: ast::Value<'_>) {
2544 match ast_value {
2545 ast::Value::StringLit(string_lit) => self.build_string_lit(container, string_lit),
2546 ast::Value::NumberLit(number_lit) => {
2547 container.raw_append_child(CstNumberLit::new(number_lit.value.to_string()).into())
2548 }
2549 ast::Value::BooleanLit(boolean_lit) => container.raw_append_child(CstBooleanLit::new(boolean_lit.value).into()),
2550 ast::Value::Object(object) => {
2551 let object = self.build_object(object);
2552 container.raw_append_child(object.into())
2553 }
2554 ast::Value::Array(array) => {
2555 let array = self.build_array(array);
2556 container.raw_append_child(array.into())
2557 }
2558 ast::Value::NullKeyword(_) => container.raw_append_child(CstNullKeyword::new().into()),
2559 }
2560 }
2561
2562 fn build_object(&mut self, object: ast::Object<'_>) -> CstContainerNode {
2563 let container = CstContainerNode::Object(CstObject::new_no_tokens());
2564 let mut last_range_end = object.range.start;
2565 for prop in object.properties {
2566 self.scan_from_to(&container, last_range_end, prop.range.start);
2567 last_range_end = prop.range.end;
2568 let object_prop = self.build_object_prop(prop);
2569 container.raw_append_child(CstNode::Container(object_prop));
2570 }
2571 self.scan_from_to(&container, last_range_end, object.range.end);
2572
2573 container
2574 }
2575
2576 fn build_object_prop(&mut self, prop: ast::ObjectProp<'_>) -> CstContainerNode {
2577 let container = CstContainerNode::ObjectProp(CstObjectProp::new());
2578 let name_range = prop.name.range();
2579 let value_range = prop.value.range();
2580
2581 match prop.name {
2582 ast::ObjectPropName::String(string_lit) => {
2583 self.build_string_lit(&container, string_lit);
2584 }
2585 ast::ObjectPropName::Word(word_lit) => {
2586 container.raw_append_child(CstWordLit::new(word_lit.value.to_string()).into());
2587 }
2588 }
2589
2590 self.scan_from_to(&container, name_range.end, value_range.start);
2591 self.build_value(&container, prop.value);
2592
2593 container
2594 }
2595
2596 fn build_token(&self, container: &CstContainerNode, value: char) {
2597 container.raw_append_child(CstToken::new(value).into());
2598 }
2599
2600 fn build_whitespace(&self, container: &CstContainerNode, value: &str) {
2601 if value.is_empty() {
2602 return;
2603 }
2604
2605 let mut last_found_index = 0;
2606 let mut chars = value.char_indices().peekable();
2607 let maybe_add_previous_text = |from: usize, to: usize| {
2608 let text = &value[from..to];
2609 if !text.is_empty() {
2610 container.raw_append_child(CstWhitespace::new(text.to_string()).into());
2611 }
2612 };
2613 while let Some((i, c)) = chars.next() {
2614 if c == '\r' && chars.peek().map(|(_, c)| *c) == Some('\n') {
2615 maybe_add_previous_text(last_found_index, i);
2616 container.raw_append_child(CstNewline::new(CstNewlineKind::CarriageReturnLineFeed).into());
2617 last_found_index = i + 2;
2618 chars.next(); } else if c == '\r' {
2620 maybe_add_previous_text(last_found_index, i);
2621 container.raw_append_child(CstNewline::new(CstNewlineKind::CarriageReturn).into());
2622 last_found_index = i + 1;
2623 } else if c == '\n' {
2624 maybe_add_previous_text(last_found_index, i);
2625 container.raw_append_child(CstNewline::new(CstNewlineKind::LineFeed).into());
2626 last_found_index = i + 1;
2627 }
2628 }
2629
2630 maybe_add_previous_text(last_found_index, value.len());
2631 }
2632
2633 fn build_string_lit(&self, container: &CstContainerNode, lit: ast::StringLit<'_>) {
2634 container.raw_append_child(CstStringLit::new(self.text[lit.range.start..lit.range.end].to_string()).into());
2635 }
2636
2637 fn build_array(&mut self, array: ast::Array<'_>) -> CstContainerNode {
2638 let container = CstContainerNode::Array(CstArray::new_no_tokens());
2639 let mut last_range_end = array.range.start;
2640 for element in array.elements {
2641 let element_range = element.range();
2642 self.scan_from_to(&container, last_range_end, element_range.start);
2643 self.build_value(&container, element);
2644 last_range_end = element_range.end;
2645 }
2646 self.scan_from_to(&container, last_range_end, array.range.end);
2647
2648 container
2649 }
2650}
2651
2652#[must_use = "nothing is sorted until `by` or `by_key` is called"]
2656pub struct PropertySort<'a> {
2657 object: &'a CstObject,
2658 options: SortOptions<'a>,
2659}
2660
2661impl<'a> PropertySort<'a> {
2662 pub fn pin_comment_headers(mut self) -> Self {
2701 self.options.header_rule = Some(Box::new(blank_line_header_rule));
2702 self
2703 }
2704
2705 pub fn pin_comment_headers_with(mut self, mut rule: impl FnMut(&CstObjectProp, &[CstComment]) -> usize + 'a) -> Self {
2723 self.options.header_rule = Some(Box::new(move |element, comments| match element.as_object_prop() {
2724 Some(prop) => rule(&prop, comments),
2725 None => 0,
2726 }));
2727 self
2728 }
2729
2730 pub fn within_groups(mut self) -> Self {
2767 self.options.within_groups = true;
2768 self
2769 }
2770
2771 pub fn by(self, mut compare: impl FnMut(&CstObjectProp, &CstObjectProp) -> Ordering) {
2777 let object = self.object.clone().into();
2778 sort_comma_separated_children(&object, self.options, |groups| {
2779 groups.sort_by(|left, right| {
2780 match (left.element.as_object_prop(), right.element.as_object_prop()) {
2781 (Some(left), Some(right)) => compare(&left, &right),
2782 _ => Ordering::Equal,
2785 }
2786 })
2787 });
2788 }
2789
2790 pub fn by_key<K: Ord>(self, mut key: impl FnMut(&CstObjectProp) -> K) {
2796 let object = self.object.clone().into();
2797 sort_comma_separated_children(&object, self.options, |groups| {
2798 groups.sort_by_cached_key(|group| group.element.as_object_prop().map(|prop| key(&prop)))
2799 });
2800 }
2801}
2802
2803#[must_use = "nothing is sorted until `by` or `by_key` is called"]
2807pub struct ElementSort<'a> {
2808 array: &'a CstArray,
2809 options: SortOptions<'a>,
2810}
2811
2812impl<'a> ElementSort<'a> {
2813 pub fn pin_comment_headers(self) -> Self {
2817 self.pin_comment_headers_with(blank_line_header_rule)
2818 }
2819
2820 pub fn pin_comment_headers_with(mut self, rule: impl FnMut(&CstNode, &[CstComment]) -> usize + 'a) -> Self {
2825 self.options.header_rule = Some(Box::new(rule));
2826 self
2827 }
2828
2829 pub fn within_groups(mut self) -> Self {
2833 self.options.within_groups = true;
2834 self
2835 }
2836
2837 pub fn by(self, mut compare: impl FnMut(&CstNode, &CstNode) -> Ordering) {
2841 let array = self.array.clone().into();
2842 sort_comma_separated_children(&array, self.options, |groups| {
2843 groups.sort_by(|left, right| compare(&left.element, &right.element))
2844 });
2845 }
2846
2847 pub fn by_key<K: Ord>(self, mut key: impl FnMut(&CstNode) -> K) {
2851 let array = self.array.clone().into();
2852 sort_comma_separated_children(&array, self.options, |groups| {
2853 groups.sort_by_cached_key(|group| key(&group.element))
2854 });
2855 }
2856}
2857
2858type HeaderRule<'a> = Box<dyn FnMut(&CstNode, &[CstComment]) -> usize + 'a>;
2860
2861#[derive(Default)]
2863struct SortOptions<'a> {
2864 header_rule: Option<HeaderRule<'a>>,
2865 within_groups: bool,
2866}
2867
2868impl SortOptions<'_> {
2869 fn pinned_comment_count(&mut self, element: &CstNode, comments: &[CstComment]) -> usize {
2871 match &mut self.header_rule {
2872 Some(rule) => rule(element, comments),
2873 None => 0,
2874 }
2875 }
2876}
2877
2878fn blank_line_header_rule(element: &CstNode, comments: &[CstComment]) -> usize {
2881 if element.has_blank_line_before() {
2882 comments.len()
2883 } else {
2884 0
2885 }
2886}
2887
2888struct Separator {
2894 before: Range<usize>,
2897 indent: Range<usize>,
2899}
2900
2901struct SortableGroup {
2905 index: usize,
2907 starts_group: bool,
2910 leading: Range<usize>,
2912 element: CstNode,
2913 trailing: Range<usize>,
2916 comma: Option<usize>,
2918}
2919
2920fn sort_comma_separated_children(
2927 container: &CstContainerNode,
2928 mut options: SortOptions<'_>,
2929 mut sort: impl FnMut(&mut [SortableGroup]),
2930) {
2931 let children = container.children();
2932 if children.len() < 2 || !children[0].is_token() || !children[children.len() - 1].is_token() {
2934 return;
2935 }
2936 let region = &children[1..children.len() - 1];
2937
2938 let mut separators: Vec<Separator> = Vec::new();
2941 let mut groups: Vec<SortableGroup> = Vec::new();
2942 let mut index = 0;
2943 let tail = loop {
2944 let run_start = index;
2945 while index < region.len() && !is_sortable_element(®ion[index]) {
2946 index += 1;
2947 }
2948 if index == region.len() {
2949 break run_start..region.len();
2951 }
2952 let run = run_start..index;
2953 let starts_group = has_blank_line(region[run.clone()].iter().cloned());
2954 let (separator, leading) = split_separator(region, run, ®ion[index], starts_group, &mut options);
2955 separators.push(separator);
2956 let trailing = index + 1..trailing_run_end(region, index + 1);
2957 groups.push(SortableGroup {
2958 index: groups.len(),
2959 starts_group,
2960 leading,
2961 element: region[index].clone(),
2962 comma: region[trailing.clone()]
2963 .iter()
2964 .position(|n| n.is_comma())
2965 .map(|at| trailing.start + at),
2966 trailing: trailing.clone(),
2967 });
2968 index = trailing.end;
2969 };
2970
2971 if groups.len() < 2 {
2972 return;
2973 }
2974
2975 let ends_with_comma = groups[groups.len() - 1].comma.is_some();
2977 if options.within_groups {
2978 for group in groups.chunk_by_mut(|_, next| !next.starts_group) {
2980 sort(group);
2981 }
2982 } else {
2983 sort(&mut groups);
2984 }
2985 let unchanged = container.children().len() == children.len()
2989 && children
2990 .iter()
2991 .enumerate()
2992 .all(|(index, child)| child.parent_info().map(|info| info.child_index) == Some(index));
2993 if !unchanged {
2994 return;
2995 }
2996 if groups
2997 .iter()
2998 .enumerate()
2999 .all(|(position, group)| position == group.index)
3000 {
3001 return;
3002 }
3003
3004 let first_leading = &mut groups[0].leading;
3007 first_leading.start += leading_blank_line_len(®ion[first_leading.clone()]);
3008
3009 let last_index = groups.len() - 1;
3010 let mut new_children = Vec::with_capacity(children.len());
3011 new_children.push(children[0].clone());
3012 for (position, (separator, group)) in separators.into_iter().zip(groups).enumerate() {
3013 new_children.extend_from_slice(®ion[separator.before]);
3014 new_children.extend_from_slice(®ion[group.leading]);
3015 new_children.extend_from_slice(®ion[separator.indent]);
3016 new_children.push(group.element);
3017 let wants_comma = position < last_index || ends_with_comma;
3018 push_trailing(&mut new_children, region, group.trailing, group.comma, wants_comma);
3019 }
3020 new_children.extend_from_slice(®ion[tail]);
3021 new_children.push(children[children.len() - 1].clone());
3022 let newline_kind = container
3023 .root_node()
3024 .map(|root| root.newline_kind())
3025 .unwrap_or(CstNewlineKind::LineFeed);
3026 restore_line_comment_line_ends(&mut new_children, newline_kind);
3027 container.raw_set_children(new_children);
3028}
3029
3030fn is_sortable_element(node: &CstNode) -> bool {
3033 !node.is_trivia() && !node.is_token()
3034}
3035
3036fn leading_blank_line_len(run: &[CstNode]) -> usize {
3041 let mut len = 0;
3042 let mut index = 0;
3043 while index < run.len() {
3044 let mut end = index;
3045 while end < run.len() && run[end].is_whitespace() {
3046 end += 1;
3047 }
3048 if end < run.len() && run[end].is_newline() {
3049 index = end + 1;
3050 len = index;
3051 } else {
3052 break;
3053 }
3054 }
3055 len
3056}
3057
3058fn has_blank_line(run: impl IntoIterator<Item = CstNode>) -> bool {
3063 let mut ended_a_line = false;
3064 for node in run {
3065 if node.is_newline() {
3066 if ended_a_line {
3067 return true;
3068 }
3069 ended_a_line = true;
3070 } else if !node.is_whitespace() {
3071 ended_a_line = false;
3072 }
3073 }
3074 false
3075}
3076
3077fn split_separator(
3086 region: &[CstNode],
3087 run: Range<usize>,
3088 element: &CstNode,
3089 starts_group: bool,
3090 options: &mut SortOptions<'_>,
3091) -> (Separator, Range<usize>) {
3092 let nodes = ®ion[run.clone()];
3093 let Some(newline) = nodes.iter().position(|n| n.is_newline()) else {
3094 let before = nodes.iter().take_while(|n| n.is_whitespace()).count();
3096 return (
3097 Separator {
3098 before: run.start..run.start + before,
3099 indent: run.end..run.end,
3100 },
3101 run.start + before..run.end,
3102 );
3103 };
3104 let indent_len = nodes[newline + 1..]
3105 .iter()
3106 .rev()
3107 .take_while(|n| n.is_whitespace())
3108 .count();
3109 let indent_start = nodes.len() - indent_len;
3110 let leading = &nodes[newline + 1..indent_start];
3111 let header_len = if starts_group && options.within_groups {
3112 leading.len()
3115 } else {
3116 header_len(leading, element, options)
3117 };
3118 let leading_start = newline + 1 + header_len;
3119 (
3120 Separator {
3121 before: run.start..run.start + leading_start,
3122 indent: run.start + indent_start..run.end,
3123 },
3124 run.start + leading_start..run.start + indent_start,
3125 )
3126}
3127
3128fn header_len(leading: &[CstNode], element: &CstNode, options: &mut SortOptions<'_>) -> usize {
3134 if options.header_rule.is_none() {
3136 return 0;
3137 }
3138 let comments = leading
3139 .iter()
3140 .filter_map(|node| match node {
3141 CstNode::Leaf(CstLeafNode::Comment(comment)) => Some(comment.clone()),
3142 _ => None,
3143 })
3144 .collect::<Vec<_>>();
3145 let pinned = options.pinned_comment_count(element, &comments);
3146 if pinned >= comments.len() {
3147 return leading.len();
3148 }
3149 let blank_lines = leading_blank_line_len(leading);
3152 if pinned == 0 {
3153 return blank_lines;
3154 }
3155 let first_travelling = leading
3156 .iter()
3157 .enumerate()
3158 .filter(|(_, node)| node.is_comment())
3159 .map(|(index, _)| index)
3160 .nth(pinned)
3161 .expect("a comment past the pinned ones, since fewer were pinned than there are");
3162 let mut split = first_travelling;
3165 while split > 0 && !leading[split - 1].is_newline() {
3166 split -= 1;
3167 }
3168 split.max(blank_lines)
3169}
3170
3171fn trailing_run_end(region: &[CstNode], start: usize) -> usize {
3177 let mut end = start;
3178 for (index, node) in region.iter().enumerate().skip(start) {
3179 if is_sortable_element(node) {
3180 break;
3181 } else if node.is_comma() {
3182 end = index + 1;
3183 break;
3184 }
3185 }
3186 if rest_of_line_is_trivia(region, end) {
3188 for (index, node) in region.iter().enumerate().skip(end) {
3189 if node.is_newline() {
3190 break;
3191 } else if node.is_comment() {
3192 end = index + 1;
3193 }
3194 }
3195 }
3196 end
3197}
3198
3199fn rest_of_line_is_trivia(region: &[CstNode], start: usize) -> bool {
3202 region
3203 .iter()
3204 .skip(start)
3205 .take_while(|n| !n.is_newline())
3206 .all(|n| n.is_whitespace() || n.is_comment())
3207}
3208
3209fn push_trailing(
3211 out: &mut Vec<CstNode>,
3212 region: &[CstNode],
3213 trailing: Range<usize>,
3214 comma: Option<usize>,
3215 wants_comma: bool,
3216) {
3217 match comma {
3218 Some(comma) if !wants_comma => {
3219 let end = if comma > trailing.start && region[comma - 1].is_whitespace() {
3221 comma - 1
3222 } else {
3223 comma
3224 };
3225 out.extend_from_slice(®ion[trailing.start..end]);
3226 out.extend_from_slice(®ion[comma + 1..trailing.end]);
3227 }
3228 None if wants_comma => {
3229 out.push(CstToken::new(',').into());
3230 out.extend_from_slice(®ion[trailing]);
3231 }
3232 _ => out.extend_from_slice(®ion[trailing]),
3233 }
3234}
3235
3236fn restore_line_comment_line_ends(children: &mut Vec<CstNode>, newline_kind: CstNewlineKind) {
3241 let mut index = 0;
3242 while index < children.len() {
3243 if is_line_comment(&children[index])
3244 && let Some(next) = children[index + 1..].iter().position(|n| !n.is_whitespace())
3245 && !children[index + 1 + next].is_newline()
3246 {
3247 children.insert(index + 1, CstNewline::new(newline_kind).into());
3248 }
3249 index += 1;
3250 }
3251}
3252
3253fn is_line_comment(node: &CstNode) -> bool {
3254 matches!(node, CstNode::Leaf(CstLeafNode::Comment(comment)) if comment.is_line_comment())
3255}
3256
3257fn remove_comma_separated(node: CstNode) {
3258 fn check_next_node_same_line(trailing_comma: &CstToken) -> bool {
3259 for sibling in trailing_comma.next_siblings() {
3260 match sibling {
3261 CstNode::Container(_) => return true,
3262 CstNode::Leaf(n) => match n {
3263 CstLeafNode::BooleanLit(_)
3264 | CstLeafNode::NullKeyword(_)
3265 | CstLeafNode::NumberLit(_)
3266 | CstLeafNode::StringLit(_)
3267 | CstLeafNode::WordLit(_)
3268 | CstLeafNode::Token(_) => return true,
3269 CstLeafNode::Whitespace(_) | CstLeafNode::Comment(_) => {
3270 }
3272 CstLeafNode::Newline(_) => return false,
3273 },
3274 }
3275 }
3276
3277 true
3278 }
3279
3280 let parent = node.parent();
3281 let trailing_comma = node.trailing_comma();
3282 let is_in_array_or_obj = parent
3283 .as_ref()
3284 .map(|p| matches!(p, CstContainerNode::Array(_) | CstContainerNode::Object(_)))
3285 .unwrap_or(false);
3286 let remove_up_to_next_line = trailing_comma
3287 .as_ref()
3288 .map(|c| !check_next_node_same_line(c))
3289 .unwrap_or(true);
3290
3291 for previous in node.previous_siblings() {
3292 if previous.is_trivia() && !previous.is_newline() {
3293 previous.remove_raw();
3294 } else {
3295 break;
3296 }
3297 }
3298
3299 let mut found_newline = false;
3300
3301 if trailing_comma.is_some() {
3303 let mut next_siblings = node.next_siblings();
3304 for next in next_siblings.by_ref() {
3305 let is_comma = next.is_comma();
3306 if next.is_newline() {
3307 found_newline = true;
3308 }
3309 next.remove_raw();
3310 if is_comma {
3311 break;
3312 }
3313 }
3314 } else if is_in_array_or_obj && let Some(previous_comma) = node.previous_siblings().find(|n| n.is_comma()) {
3315 previous_comma.remove();
3316 }
3317
3318 if remove_up_to_next_line && !found_newline {
3320 let mut next_siblings = node.next_siblings().peekable();
3321 while let Some(sibling) = next_siblings.next() {
3322 if sibling.is_trivia() {
3323 if sibling.is_newline() {
3324 sibling.remove_raw();
3325 break;
3326 } else if sibling.is_whitespace()
3327 && next_siblings
3328 .peek()
3329 .map(|n| !n.is_whitespace() && !n.is_newline() && !n.is_comment())
3330 .unwrap_or(false)
3331 {
3332 break;
3333 }
3334 sibling.remove_raw();
3335 } else {
3336 break;
3337 }
3338 }
3339 }
3340
3341 node.remove_raw();
3342
3343 if let Some(parent) = parent {
3344 match parent {
3345 CstContainerNode::Root(n) => {
3346 if n.children().iter().all(|c| c.is_whitespace() || c.is_newline()) {
3347 n.clear_children();
3348 }
3349 }
3350 CstContainerNode::Object(_) | CstContainerNode::Array(_) => {
3351 let children = parent.children();
3352 if children
3353 .iter()
3354 .skip(1)
3355 .take(children.len() - 2)
3356 .all(|c| c.is_whitespace() || c.is_newline())
3357 {
3358 for c in children {
3359 if c.is_whitespace() || c.is_newline() {
3360 c.remove();
3361 }
3362 }
3363 }
3364 }
3365 CstContainerNode::ObjectProp(_) => {}
3366 }
3367 }
3368}
3369
3370fn indent_text(node: &CstNode) -> Option<String> {
3371 let mut last_whitespace: Option<String> = None;
3372 for previous_sibling in node.previous_siblings() {
3373 match previous_sibling {
3374 CstNode::Container(_) => return None,
3375 CstNode::Leaf(leaf) => match leaf {
3376 CstLeafNode::Newline(_) => {
3377 return last_whitespace;
3378 }
3379 CstLeafNode::Whitespace(whitespace) => {
3380 last_whitespace = match last_whitespace {
3381 Some(last_whitespace) => Some(format!("{}{}", whitespace.value(), last_whitespace)),
3382 None => Some(whitespace.value()),
3383 };
3384 }
3385 CstLeafNode::Comment(_) => {
3386 last_whitespace = None;
3387 }
3388 _ => return None,
3389 },
3390 }
3391 }
3392 last_whitespace
3393}
3394
3395fn uses_trailing_commas(node: CstNode) -> bool {
3396 let node = match node {
3397 CstNode::Container(node) => node,
3398 CstNode::Leaf(_) => return false,
3399 };
3400 let mut pending_nodes: VecDeque<CstContainerNode> = VecDeque::from([node.clone()]);
3401 while let Some(node) = pending_nodes.pop_front() {
3402 let children = node.children();
3403 if !node.is_root() {
3404 if let Some(object) = node.as_object() {
3405 if children.iter().any(|c| c.is_whitespace()) {
3406 let properties = object.properties();
3407 if let Some(last_property) = properties.last() {
3408 return last_property.trailing_comma().is_some();
3409 }
3410 }
3411 } else if let Some(object) = node.as_array()
3412 && children.iter().any(|c| c.is_whitespace())
3413 {
3414 let elements = object.elements();
3415 if let Some(last_property) = elements.last() {
3416 return last_property.trailing_comma().is_some();
3417 }
3418 }
3419 }
3420
3421 for child in children {
3422 if let CstNode::Container(child) = child {
3423 pending_nodes.push_back(child);
3424 }
3425 }
3426 }
3427
3428 false }
3430
3431fn replace_with(node: CstNode, replacement: InsertValue) -> Option<CstNode> {
3432 let mut child_index = node.child_index();
3433 let parent = node.parent()?;
3434 let indents = compute_indents(&parent.clone().into());
3435 let style_info = StyleInfo {
3436 newline_kind: parent.root_node().map(|r| r.newline_kind()).unwrap_or_default(),
3437 uses_trailing_commas: uses_trailing_commas(parent.clone().into()),
3438 };
3439 parent.remove_child_set_no_parent(child_index);
3440 parent.raw_insert_value_with_internal_indent(Some(&mut child_index), replacement, &style_info, &indents);
3441 parent.child_at_index(child_index - 1)
3442}
3443
3444enum InsertValue<'a> {
3445 Value(CstInputValue),
3446 Property(&'a str, CstInputValue),
3447}
3448
3449fn insert_or_append_to_container(
3450 container: &CstContainerNode,
3451 elements: Vec<CstNode>,
3452 index: Option<usize>,
3453 value: InsertValue,
3454) -> CstNode {
3455 fn has_separating_newline(siblings: impl Iterator<Item = CstNode>) -> bool {
3456 for sibling in siblings {
3457 if sibling.is_newline() {
3458 return true;
3459 } else if sibling.is_trivia() {
3460 continue;
3461 } else {
3462 break;
3463 }
3464 }
3465 false
3466 }
3467
3468 trim_inner_start_and_end_blanklines(container);
3469
3470 let children = container.children();
3471 let index = index.unwrap_or(elements.len());
3472 let index = std::cmp::min(index, elements.len());
3473 let next_node = elements.get(index);
3474 let previous_node = if index == 0 { None } else { elements.get(index - 1) };
3475 let style_info = StyleInfo {
3476 newline_kind: container.root_node().map(|r| r.newline_kind()).unwrap_or_default(),
3477 uses_trailing_commas: uses_trailing_commas(container.clone().into()),
3478 };
3479 let indents = compute_indents(&container.clone().into());
3480 let child_indents = elements
3481 .first()
3482 .map(compute_indents)
3483 .unwrap_or_else(|| indents.indent());
3484 let has_newline = children.iter().any(|child| child.is_newline());
3485 let force_multiline = has_newline
3486 || match &value {
3487 InsertValue::Value(v) => v.force_multiline(),
3488 InsertValue::Property(..) => true,
3489 };
3490 let mut insert_index: usize;
3491 let inserted_node: CstNode;
3492 if let Some(previous_node) = previous_node {
3493 if previous_node.trailing_comma().is_none() {
3494 let mut index = previous_node.child_index() + 1;
3495 container.raw_insert_child(Some(&mut index), CstToken::new(',').into());
3496 }
3497
3498 let trailing_comma: CstNode = previous_node.trailing_comma().unwrap().into();
3499 insert_index = trailing_comma
3500 .trailing_comments_same_line()
3501 .last()
3502 .map(|t| t.child_index())
3503 .unwrap_or_else(|| trailing_comma.child_index())
3504 + 1;
3505 if force_multiline {
3506 container.raw_insert_children(
3507 Some(&mut insert_index),
3508 vec![
3509 CstNewline::new(style_info.newline_kind).into(),
3510 CstWhitespace::new(child_indents.current_indent.clone()).into(),
3511 ],
3512 );
3513 container.raw_insert_value_with_internal_indent(Some(&mut insert_index), value, &style_info, &child_indents);
3514 inserted_node = container.child_at_index(insert_index - 1).unwrap();
3515 } else {
3516 container.raw_insert_child(Some(&mut insert_index), CstWhitespace::new(" ".to_string()).into());
3517 container.raw_insert_value_with_internal_indent(Some(&mut insert_index), value, &style_info, &child_indents);
3518 inserted_node = container.child_at_index(insert_index - 1).unwrap();
3519 }
3520 } else {
3521 insert_index = if elements.is_empty() {
3522 children
3523 .iter()
3524 .rev()
3525 .skip(1)
3526 .take_while(|t| t.is_whitespace() || t.is_newline())
3527 .last()
3528 .unwrap_or_else(|| children.last().unwrap())
3529 .child_index()
3530 } else {
3531 children.first().unwrap().child_index() + 1
3532 };
3533 if force_multiline {
3534 container.raw_insert_children(
3535 Some(&mut insert_index),
3536 vec![
3537 CstNewline::new(style_info.newline_kind).into(),
3538 CstWhitespace::new(child_indents.current_indent.clone()).into(),
3539 ],
3540 );
3541 container.raw_insert_value_with_internal_indent(Some(&mut insert_index), value, &style_info, &child_indents);
3542 inserted_node = container.child_at_index(insert_index - 1).unwrap();
3543 if next_node.is_none()
3544 && !has_separating_newline(container.child_at_index(insert_index - 1).unwrap().next_siblings())
3545 {
3546 container.raw_insert_children(
3547 Some(&mut insert_index),
3548 vec![
3549 CstNewline::new(style_info.newline_kind).into(),
3550 CstWhitespace::new(indents.current_indent.clone()).into(),
3551 ],
3552 );
3553 }
3554 } else {
3555 container.raw_insert_value_with_internal_indent(Some(&mut insert_index), value, &style_info, &child_indents);
3556 inserted_node = container.child_at_index(insert_index - 1).unwrap();
3557 }
3558 }
3559
3560 if next_node.is_some() {
3561 container.raw_insert_children(Some(&mut insert_index), vec![CstToken::new(',').into()]);
3562
3563 if force_multiline {
3564 let comma_token = container.child_at_index(insert_index - 1).unwrap();
3565 if !has_separating_newline(comma_token.next_siblings()) {
3566 container.raw_insert_children(
3567 Some(&mut insert_index),
3568 vec![
3569 CstNewline::new(style_info.newline_kind).into(),
3570 CstWhitespace::new(indents.current_indent.clone()).into(),
3571 ],
3572 );
3573 }
3574 } else {
3575 container.raw_insert_child(Some(&mut insert_index), CstWhitespace::new(" ".to_string()).into());
3576 }
3577 } else if style_info.uses_trailing_commas && force_multiline {
3578 container.raw_insert_children(Some(&mut insert_index), vec![CstToken::new(',').into()]);
3579 }
3580
3581 inserted_node
3582}
3583
3584fn set_trailing_commas(
3585 mode: TrailingCommaMode,
3586 parent: &CstContainerNode,
3587 elems_or_props: impl Iterator<Item = CstNode>,
3588) {
3589 let mut elems_or_props = elems_or_props.peekable();
3590 let use_trailing_commas = match mode {
3591 TrailingCommaMode::Never => false,
3592 TrailingCommaMode::IfMultiline => true,
3593 };
3594 while let Some(element) = elems_or_props.next() {
3595 if elems_or_props.peek().is_none() {
3597 if use_trailing_commas {
3598 if element.trailing_comma().is_none() && parent.children().iter().any(|c| c.is_newline()) {
3599 let mut insert_index = element.child_index() + 1;
3600 parent.raw_insert_child(Some(&mut insert_index), CstToken::new(',').into());
3601 }
3602 } else if let Some(trailing_comma) = element.trailing_comma() {
3603 trailing_comma.remove();
3604 }
3605 }
3606
3607 let maybe_prop_value = element.as_object_prop().and_then(|p| p.value());
3609 match maybe_prop_value.unwrap_or(element) {
3610 CstNode::Container(CstContainerNode::Array(array)) => {
3611 array.set_trailing_commas(mode);
3612 }
3613 CstNode::Container(CstContainerNode::Object(object)) => {
3614 object.set_trailing_commas(mode);
3615 }
3616 _ => {}
3617 }
3618 }
3619}
3620
3621fn trim_inner_start_and_end_blanklines(node: &CstContainerNode) {
3622 fn remove_blank_lines_after_first(children: &mut Peekable<impl Iterator<Item = CstNode>>) {
3623 for child in children.by_ref() {
3625 if child.is_whitespace() {
3626 } else if child.is_newline() {
3628 break; } else {
3630 return; }
3632 }
3633
3634 let mut pending = Vec::new();
3635 for child in children.by_ref() {
3636 if child.is_whitespace() {
3637 pending.push(child);
3638 } else if child.is_newline() {
3639 child.remove();
3640 for child in pending.drain(..) {
3641 child.remove();
3642 }
3643 } else {
3644 break;
3645 }
3646 }
3647 }
3648
3649 let children = node.children();
3650 let len = children.len();
3651
3652 if len < 2 {
3653 return; }
3655
3656 let mut children = children.into_iter().skip(1).take(len - 2).peekable();
3658 remove_blank_lines_after_first(&mut children);
3659 let mut children = children.rev().peekable();
3660 remove_blank_lines_after_first(&mut children);
3661}
3662
3663fn ensure_multiline(container: &CstContainerNode) {
3664 let children = container.children();
3665 if children.iter().any(|c| c.is_newline()) {
3666 return;
3667 }
3668
3669 let indents = compute_indents(&container.clone().into());
3670 let child_indents = indents.indent();
3671 let newline_kind = container
3672 .root_node()
3673 .map(|r| r.newline_kind())
3674 .unwrap_or(CstNewlineKind::LineFeed);
3675
3676 let children_len = children.len();
3678 let mut children = children.into_iter().skip(1).peekable().take(children_len - 2);
3679 let mut index = 1;
3680 while let Some(child) = children.next() {
3681 if child.is_whitespace() {
3682 child.remove();
3683 continue;
3684 } else {
3685 container.raw_insert_child(Some(&mut index), CstNewline::new(newline_kind).into());
3687 container.raw_insert_child(
3688 Some(&mut index),
3689 CstWhitespace::new(child_indents.current_indent.clone()).into(),
3690 );
3691
3692 index += 1;
3694
3695 let mut trailing_whitespace = Vec::new();
3697 for next_child in children.by_ref() {
3698 if next_child.is_whitespace() {
3699 trailing_whitespace.push(next_child);
3700 } else {
3701 index += 1 + trailing_whitespace.len();
3702 trailing_whitespace.clear();
3703 if next_child.token_char() == Some(',') {
3704 break;
3705 }
3706 }
3707 }
3708
3709 for trailing_whitespace in trailing_whitespace {
3710 trailing_whitespace.remove();
3711 }
3712 }
3713 }
3714
3715 container.raw_insert_child(Some(&mut index), CstNewline::new(newline_kind).into());
3717 if !indents.current_indent.is_empty() {
3718 container.raw_insert_child(Some(&mut index), CstWhitespace::new(indents.current_indent).into());
3719 }
3720}
3721
3722#[derive(Debug)]
3723struct Indents {
3724 current_indent: String,
3725 single_indent: String,
3726}
3727
3728impl Indents {
3729 pub fn indent(&self) -> Indents {
3730 Indents {
3731 current_indent: format!("{}{}", self.current_indent, self.single_indent),
3732 single_indent: self.single_indent.clone(),
3733 }
3734 }
3735}
3736
3737fn compute_indents(node: &CstNode) -> Indents {
3738 let mut indent_level = 0;
3739 let mut stored_last_indent = node.indent_text();
3740 let mut ancestors = node.ancestors().peekable();
3741
3742 while ancestors.peek().and_then(|p| p.as_object_prop()).is_some() {
3743 ancestors.next();
3744 }
3745
3746 while let Some(ancestor) = ancestors.next() {
3747 if ancestor.is_root() {
3748 break;
3749 }
3750
3751 if ancestors.peek().and_then(|p| p.as_object_prop()).is_some() {
3752 continue;
3753 }
3754
3755 indent_level += 1;
3756
3757 if let Some(indent_text) = ancestor.indent_text() {
3758 match stored_last_indent {
3759 Some(last_indent) => {
3760 if let Some(single_indent_text) = last_indent.strip_prefix(&indent_text) {
3761 return Indents {
3762 current_indent: format!("{}{}", last_indent, single_indent_text.repeat(indent_level - 1)),
3763 single_indent: single_indent_text.to_string(),
3764 };
3765 }
3766 stored_last_indent = None;
3767 }
3768 None => {
3769 stored_last_indent = Some(indent_text);
3770 }
3771 }
3772 } else {
3773 stored_last_indent = None;
3774 }
3775 }
3776
3777 if indent_level == 1
3778 && let Some(indent_text) = node.indent_text()
3779 {
3780 return Indents {
3781 current_indent: indent_text.clone(),
3782 single_indent: indent_text,
3783 };
3784 }
3785
3786 if let Some(root_value) = node.root_node().and_then(|r| r.value()) {
3788 for child in root_value.children() {
3789 if let Some(single_indent) = child.indent_text() {
3790 return Indents {
3791 current_indent: single_indent.repeat(indent_level),
3792 single_indent,
3793 };
3794 }
3795 }
3796 }
3797
3798 let single_indent = " ";
3800 Indents {
3801 current_indent: single_indent.repeat(indent_level),
3802 single_indent: single_indent.to_string(),
3803 }
3804}
3805
3806struct AncestorIterator {
3807 next: Option<CstContainerNode>,
3810}
3811
3812impl AncestorIterator {
3813 pub fn new(node: CstNode) -> Self {
3814 Self {
3815 next: node.parent_info().map(|i| i.parent.as_container_node()),
3816 }
3817 }
3818}
3819
3820impl Iterator for AncestorIterator {
3821 type Item = CstContainerNode;
3822
3823 fn next(&mut self) -> Option<Self::Item> {
3824 let next = self.next.take()?;
3825 self.next = next.parent_info().map(|i| i.parent.as_container_node());
3826 Some(next)
3827 }
3828}
3829
3830struct NextSiblingIterator {
3831 next: Option<CstNode>,
3834}
3835
3836impl NextSiblingIterator {
3837 pub fn new(node: CstNode) -> Self {
3838 Self {
3839 next: node.next_sibling(),
3840 }
3841 }
3842}
3843
3844impl Iterator for NextSiblingIterator {
3845 type Item = CstNode;
3846
3847 fn next(&mut self) -> Option<Self::Item> {
3848 let next_sibling = self.next.take()?;
3849 self.next = next_sibling.next_sibling();
3850 Some(next_sibling)
3851 }
3852}
3853
3854struct PreviousSiblingIterator {
3855 previous: Option<CstNode>,
3858}
3859
3860impl PreviousSiblingIterator {
3861 pub fn new(node: CstNode) -> Self {
3862 Self {
3863 previous: node.previous_sibling(),
3864 }
3865 }
3866}
3867
3868impl Iterator for PreviousSiblingIterator {
3869 type Item = CstNode;
3870
3871 fn next(&mut self) -> Option<Self::Item> {
3872 let previous_sibling = self.previous.take()?;
3873 self.previous = previous_sibling.previous_sibling();
3874 Some(previous_sibling)
3875 }
3876}
3877
3878#[cfg(test)]
3879mod test {
3880 use pretty_assertions::assert_eq;
3881
3882 use crate::cst::CstInputValue;
3883 use crate::cst::CstNewlineKind;
3884 use crate::cst::TrailingCommaMode;
3885 use crate::json;
3886
3887 use super::CstRootNode;
3888
3889 #[test]
3890 fn single_indent_text() {
3891 let cases = [
3892 (
3893 " ",
3894 r#"
3895{
3896 "prop": {
3897 "nested": 4
3898 }
3899}
3900 "#,
3901 ),
3902 (
3903 " ",
3904 r#"
3905{
3906 /* test */ "prop": {}
3907}
3908 "#,
3909 ),
3910 (
3911 " ",
3912 r#"
3913{
3914 /* test */ "prop": {}
3915}
3916 "#,
3917 ),
3918 (
3919 "\t",
3920 "
3921{
3922\t/* test */ \"prop\": {}
3923}
3924 ",
3925 ),
3926 ];
3927 for (expected, text) in cases {
3928 let root = build_cst(text);
3929 assert_eq!(root.single_indent_text(), Some(expected.to_string()), "Text: {}", text);
3930 }
3931 }
3932
3933 #[test]
3934 fn modify_values() {
3935 let cst = build_cst(
3936 r#"{
3937 "value": 5,
3938 // comment
3939 "value2": "hello",
3940 value3: true
3941}"#,
3942 );
3943
3944 let root_value = cst.value().unwrap();
3945 let root_obj = root_value.as_object().unwrap();
3946 {
3947 let prop = root_obj.get("value").unwrap();
3948 prop
3949 .value()
3950 .unwrap()
3951 .as_number_lit()
3952 .unwrap()
3953 .set_raw_value("10".to_string());
3954 assert!(prop.trailing_comma().is_some());
3955 assert!(prop.previous_property().is_none());
3956 assert_eq!(
3957 prop.next_property().unwrap().name().unwrap().decoded_value().unwrap(),
3958 "value2"
3959 );
3960 assert_eq!(prop.indent_text().unwrap(), " ");
3961 }
3962 {
3963 let prop = root_obj.get("value2").unwrap();
3964 prop
3965 .value()
3966 .unwrap()
3967 .as_string_lit()
3968 .unwrap()
3969 .set_raw_value("\"5\"".to_string());
3970 assert!(prop.trailing_comma().is_some());
3971 assert_eq!(
3972 prop
3973 .previous_property()
3974 .unwrap()
3975 .name()
3976 .unwrap()
3977 .decoded_value()
3978 .unwrap(),
3979 "value"
3980 );
3981 assert_eq!(
3982 prop.next_property().unwrap().name().unwrap().decoded_value().unwrap(),
3983 "value3"
3984 );
3985 }
3986 {
3987 let prop = root_obj.get("value3").unwrap();
3988 prop.value().unwrap().as_boolean_lit().unwrap().set_value(false);
3989 prop
3990 .name()
3991 .unwrap()
3992 .as_word_lit()
3993 .unwrap()
3994 .set_raw_value("value4".to_string());
3995 assert!(prop.trailing_comma().is_none());
3996 assert_eq!(
3997 prop
3998 .previous_property()
3999 .unwrap()
4000 .name()
4001 .unwrap()
4002 .decoded_value()
4003 .unwrap(),
4004 "value2"
4005 );
4006 assert!(prop.next_property().is_none());
4007 }
4008
4009 assert_eq!(
4010 cst.to_string(),
4011 r#"{
4012 "value": 10,
4013 // comment
4014 "value2": "5",
4015 value4: false
4016}"#
4017 );
4018 }
4019
4020 #[test]
4021 fn remove_properties() {
4022 fn run_test(prop_name: &str, json: &str, expected: &str) {
4023 let cst = build_cst(json);
4024 let root_value = cst.value().unwrap();
4025 let root_obj = root_value.as_object().unwrap();
4026 let prop = root_obj.get(prop_name).unwrap();
4027 prop.remove();
4028 assert_eq!(cst.to_string(), expected);
4029 }
4030
4031 run_test(
4032 "value2",
4033 r#"{
4034 "value": 5,
4035 // comment
4036 "value2": "hello",
4037 value3: true
4038}"#,
4039 r#"{
4040 "value": 5,
4041 // comment
4042 value3: true
4043}"#,
4044 );
4045
4046 run_test(
4047 "value2",
4048 r#"{
4049 "value": 5,
4050 // comment
4051 "value2": "hello"
4052 ,value3: true
4053}"#,
4054 r#"{
4056 "value": 5,
4057 // comment
4058value3: true
4059}"#,
4060 );
4061
4062 run_test("value", r#"{ "value": 5 }"#, r#"{}"#);
4063 run_test("value", r#"{ "value": 5, "value2": 6 }"#, r#"{ "value2": 6 }"#);
4064 run_test("value2", r#"{ "value": 5, "value2": 6 }"#, r#"{ "value": 5 }"#);
4065 }
4066
4067 #[test]
4068 fn insert_properties() {
4069 fn run_test(index: usize, prop_name: &str, value: CstInputValue, json: &str, expected: &str) {
4070 let cst = build_cst(json);
4071 let root_value = cst.value().unwrap();
4072 let root_obj = root_value.as_object().unwrap();
4073 root_obj.insert(index, prop_name, value);
4074 assert_eq!(cst.to_string(), expected, "Initial text: {}", json);
4075 }
4076
4077 run_test(
4078 0,
4079 "propName",
4080 json!([1]),
4081 r#"{}"#,
4082 r#"{
4083 "propName": [1]
4084}"#,
4085 );
4086
4087 run_test(
4089 0,
4090 "value0",
4091 json!([1]),
4092 r#"{
4093 "value1": 5
4094}"#,
4095 r#"{
4096 "value0": [1],
4097 "value1": 5
4098}"#,
4099 );
4100
4101 run_test(
4103 0,
4104 "value0",
4105 json!([1]),
4106 r#"{
4107 // some comment
4108 "value1": 5
4109}"#,
4110 r#"{
4111 "value0": [1],
4112 // some comment
4113 "value1": 5
4114}"#,
4115 );
4116
4117 run_test(
4119 1,
4120 "value1",
4121 json!({
4122 "value": 1
4123 }),
4124 r#"{
4125 "value0": 5 // comment
4126}"#,
4127 r#"{
4128 "value0": 5, // comment
4129 "value1": {
4130 "value": 1
4131 }
4132}"#,
4133 );
4134
4135 run_test(
4137 1,
4138 "propName",
4139 json!(true),
4140 r#"{
4141 "value": 4,
4142}"#,
4143 r#"{
4144 "value": 4,
4145 "propName": true,
4146}"#,
4147 );
4148
4149 run_test(
4151 1,
4152 "propName",
4153 json!(true),
4154 r#"{ "value": 4 }"#,
4155 r#"{
4156 "value": 4,
4157 "propName": true
4158}"#,
4159 );
4160
4161 run_test(
4163 1,
4164 "propName",
4165 json!(true),
4166 r#"{ "value": 4, }"#,
4167 r#"{
4168 "value": 4,
4169 "propName": true,
4170}"#,
4171 );
4172 }
4173
4174 #[test]
4175 fn remove_array_elements() {
4176 fn run_test(index: usize, json: &str, expected: &str) {
4177 let cst = build_cst(json);
4178 let root_value = cst.value().unwrap();
4179 let root_array = root_value.as_array().unwrap();
4180 let element = root_array.elements().get(index).unwrap().clone();
4181 element.remove();
4182 assert_eq!(cst.to_string(), expected);
4183 }
4184
4185 run_test(
4186 0,
4187 r#"[
4188 1,
4189]"#,
4190 r#"[]"#,
4191 );
4192 run_test(
4193 0,
4194 r#"[
4195 1,
4196 2,
4197]"#,
4198 r#"[
4199 2,
4200]"#,
4201 );
4202 run_test(
4203 0,
4204 r#"[
4205 1,
4206 2,
4207]"#,
4208 r#"[
4209 2,
4210]"#,
4211 );
4212
4213 run_test(
4214 1,
4215 r#"[
4216 1, // other comment
4217 2, // trailing comment
4218]"#,
4219 r#"[
4220 1, // other comment
4221]"#,
4222 );
4223
4224 run_test(
4225 1,
4226 r#"[
4227 1, // comment
4228 2
4229]"#,
4230 r#"[
4231 1 // comment
4232]"#,
4233 );
4234
4235 run_test(1, r#"[1, 2]"#, r#"[1]"#);
4236 run_test(1, r#"[ 1, 2 /* test */ ]"#, r#"[ 1 ]"#);
4237 run_test(1, r#"[1, /* test */ 2]"#, r#"[1]"#);
4238 run_test(
4239 1,
4240 r#"[1 /* a */, /* b */ 2 /* c */, /* d */ true]"#,
4241 r#"[1 /* a */, /* d */ true]"#,
4242 );
4243 }
4244
4245 #[test]
4246 fn insert_array_element() {
4247 #[track_caller]
4248 fn run_test(index: usize, value: CstInputValue, json: &str, expected: &str) {
4249 let cst = build_cst(json);
4250 let root_value = cst.value().unwrap();
4251 let root_array = root_value.as_array().unwrap();
4252 root_array.insert(index, value);
4253 assert_eq!(cst.to_string(), expected, "Initial text: {}", json);
4254 }
4255
4256 run_test(0, json!([1]), r#"[]"#, r#"[[1]]"#);
4257 run_test(0, json!([1, true, false, {}]), r#"[]"#, r#"[[1, true, false, {}]]"#);
4258 run_test(0, json!(10), r#"[]"#, r#"[10]"#);
4259 run_test(0, json!(10), r#"[1]"#, r#"[10, 1]"#);
4260 run_test(1, json!(10), r#"[1]"#, r#"[1, 10]"#);
4261 run_test(
4262 0,
4263 json!(10),
4264 r#"[
4265 1
4266]"#,
4267 r#"[
4268 10,
4269 1
4270]"#,
4271 );
4272 run_test(
4273 0,
4274 json!(10),
4275 r#"[
4276 /* test */ 1
4277]"#,
4278 r#"[
4279 10,
4280 /* test */ 1
4281]"#,
4282 );
4283
4284 run_test(
4285 0,
4286 json!({
4287 "value": 1,
4288 }),
4289 r#"[]"#,
4290 r#"[
4291 {
4292 "value": 1
4293 }
4294]"#,
4295 );
4296
4297 run_test(
4299 0,
4300 json!({
4301 "value": 1,
4302 }),
4303 r#"[
4304 // comment
4305]"#,
4306 r#"[
4307 // comment
4308 {
4309 "value": 1
4310 }
4311]"#,
4312 );
4313
4314 run_test(
4316 0,
4317 json!({
4318 "value": 1,
4319 }),
4320 r#"[
4321
4322]"#,
4323 r#"[
4324 {
4325 "value": 1
4326 }
4327]"#,
4328 );
4329 }
4330
4331 #[test]
4332 fn append_to_multiline_array_does_not_expose_phantom_string_lit() {
4333 let cst = build_cst(
4335 r#"{
4336 "servers": [
4337 {"name": "linear"},
4338 {"name": "supabase"}
4339 ]
4340}"#,
4341 );
4342 let arr = cst.object_value_or_create().unwrap().array_value("servers").unwrap();
4343 arr.append(CstInputValue::Object(vec![(
4344 "name".to_string(),
4345 CstInputValue::String("github".to_string()),
4346 )]));
4347
4348 let elements = arr.elements();
4349 assert_eq!(elements.len(), 3);
4350 for el in &elements {
4351 assert!(
4352 el.as_string_lit().is_none(),
4353 "element should not be a string lit: {:?}",
4354 el
4355 );
4356 assert!(el.as_object().is_some(), "element should be an object: {:?}", el);
4357 }
4358 }
4359
4360 #[test]
4361 fn insert_array_element_trailing_commas() {
4362 let cst = build_cst(
4363 r#"{
4364 "prop": [
4365 1,
4366 2,
4367 ]
4368}"#,
4369 );
4370 cst
4371 .object_value_or_create()
4372 .unwrap()
4373 .array_value("prop")
4374 .unwrap()
4375 .append(json!(3));
4376 assert_eq!(
4377 cst.to_string(),
4378 r#"{
4379 "prop": [
4380 1,
4381 2,
4382 3,
4383 ]
4384}"#
4385 );
4386 }
4387
4388 #[test]
4389 fn remove_comment() {
4390 #[track_caller]
4391 fn run_test(json: &str, expected: &str) {
4392 let cst = build_cst(json);
4393 let root_value = cst.value().unwrap();
4394 let root_obj = root_value.as_object().unwrap();
4395 root_obj
4396 .children()
4397 .into_iter()
4398 .filter_map(|c| c.as_comment())
4399 .next()
4400 .unwrap()
4401 .remove();
4402 assert_eq!(cst.to_string(), expected);
4403 }
4404
4405 run_test(
4406 r#"{
4407 "value": 5,
4408 // comment
4409 "value2": "hello",
4410 value3: true
4411}"#,
4412 r#"{
4413 "value": 5,
4414 "value2": "hello",
4415 value3: true
4416}"#,
4417 );
4418
4419 run_test(
4420 r#"{
4421 "value": 5, // comment
4422 "value2": "hello",
4423 value3: true
4424}"#,
4425 r#"{
4426 "value": 5,
4427 "value2": "hello",
4428 value3: true
4429}"#,
4430 );
4431 }
4432
4433 #[test]
4434 fn object_value_or_create() {
4435 {
4437 let cst = build_cst(r#"{ "value": 1 }"#);
4438 let obj = cst.object_value_or_create().unwrap();
4439 assert!(obj.get("value").is_some());
4440 }
4441 {
4443 let cst = build_cst(r#""#);
4444 cst.object_value_or_create().unwrap();
4445 assert_eq!(cst.to_string(), "{}\n");
4446 }
4447 {
4449 let cst = build_cst("// Copyright something");
4450 cst.object_value_or_create().unwrap();
4451 assert_eq!(cst.to_string(), "// Copyright something\n{}\n");
4452 }
4453 {
4455 let cst = build_cst("// Copyright something\n");
4456 cst.object_value_or_create().unwrap();
4457 assert_eq!(cst.to_string(), "// Copyright something\n{}\n");
4458 }
4459 }
4460
4461 #[test]
4462 fn array_ensure_multiline() {
4463 {
4465 let cst = build_cst(r#"[]"#);
4466 cst.value().unwrap().as_array().unwrap().ensure_multiline();
4467 assert_eq!(cst.to_string(), "[\n]");
4468 }
4469 {
4471 let cst = build_cst(r#"[ ]"#);
4472 cst.value().unwrap().as_array().unwrap().ensure_multiline();
4473 assert_eq!(cst.to_string(), "[\n]");
4474 }
4475 {
4477 let cst = build_cst(r#"[ /* test */ ]"#);
4478 cst.value().unwrap().as_array().unwrap().ensure_multiline();
4479 assert_eq!(cst.to_string(), "[\n /* test */\n]");
4480 }
4481 {
4483 let cst = build_cst(r#"[ 1, 2, /* test */ 3 ]"#);
4484 cst.value().unwrap().as_array().unwrap().ensure_multiline();
4485 assert_eq!(
4486 cst.to_string(),
4487 r#"[
4488 1,
4489 2,
4490 /* test */ 3
4491]"#
4492 );
4493 }
4494 {
4496 let cst = build_cst(
4497 r#"{
4498 "prop": {
4499 "value": [ 1, 2, /* test */ 3 ]
4500 }
4501}"#,
4502 );
4503 cst
4504 .value()
4505 .unwrap()
4506 .as_object()
4507 .unwrap()
4508 .get("prop")
4509 .unwrap()
4510 .value()
4511 .unwrap()
4512 .as_object()
4513 .unwrap()
4514 .get("value")
4515 .unwrap()
4516 .value()
4517 .unwrap()
4518 .as_array()
4519 .unwrap()
4520 .ensure_multiline();
4521 assert_eq!(
4522 cst.to_string(),
4523 r#"{
4524 "prop": {
4525 "value": [
4526 1,
4527 2,
4528 /* test */ 3
4529 ]
4530 }
4531}"#
4532 );
4533 }
4534 {
4536 let cst = build_cst("[ 1, 2, /* test */ 3 ]\r\n");
4537 cst.value().unwrap().as_array().unwrap().ensure_multiline();
4538 assert_eq!(cst.to_string(), "[\r\n 1,\r\n 2,\r\n /* test */ 3\r\n]\r\n");
4539 }
4540 }
4541
4542 #[test]
4543 fn object_ensure_multiline() {
4544 {
4546 let cst = build_cst(r#"{}"#);
4547 cst.value().unwrap().as_object().unwrap().ensure_multiline();
4548 assert_eq!(cst.to_string(), "{\n}");
4549 }
4550 {
4552 let cst = build_cst(r#"{ }"#);
4553 cst.value().unwrap().as_object().unwrap().ensure_multiline();
4554 assert_eq!(cst.to_string(), "{\n}");
4555 }
4556 {
4558 let cst = build_cst(r#"{ /* test */ }"#);
4559 cst.value().unwrap().as_object().unwrap().ensure_multiline();
4560 assert_eq!(cst.to_string(), "{\n /* test */\n}");
4561 }
4562 {
4564 let cst = build_cst(r#"{ prop: 1, prop2: 2, /* test */ prop3: 3 }"#);
4565 cst.value().unwrap().as_object().unwrap().ensure_multiline();
4566 assert_eq!(
4567 cst.to_string(),
4568 r#"{
4569 prop: 1,
4570 prop2: 2,
4571 /* test */ prop3: 3
4572}"#
4573 );
4574 }
4575 {
4577 let cst = build_cst(
4578 r#"{
4579 "prop": {
4580 "value": { prop: 1, prop2: 2, /* test */ prop3: 3 }
4581 }
4582}"#,
4583 );
4584 cst
4585 .value()
4586 .unwrap()
4587 .as_object()
4588 .unwrap()
4589 .get("prop")
4590 .unwrap()
4591 .value()
4592 .unwrap()
4593 .as_object()
4594 .unwrap()
4595 .get("value")
4596 .unwrap()
4597 .value()
4598 .unwrap()
4599 .as_object()
4600 .unwrap()
4601 .ensure_multiline();
4602 assert_eq!(
4603 cst.to_string(),
4604 r#"{
4605 "prop": {
4606 "value": {
4607 prop: 1,
4608 prop2: 2,
4609 /* test */ prop3: 3
4610 }
4611 }
4612}"#
4613 );
4614 }
4615 }
4616
4617 #[test]
4618 fn sets_trailing_commas() {
4619 fn run_test(input: &str, mode: crate::cst::TrailingCommaMode, expected: &str) {
4620 let cst = build_cst(input);
4621 let root_value = cst.value().unwrap();
4622 let root_obj = root_value.as_object().unwrap();
4623 root_obj.set_trailing_commas(mode);
4624 assert_eq!(cst.to_string(), expected);
4625 }
4626
4627 run_test(
4629 r#"{
4630}"#,
4631 TrailingCommaMode::Never,
4632 r#"{
4633}"#,
4634 );
4635 run_test(
4636 r#"{
4637 // test
4638}"#,
4639 TrailingCommaMode::IfMultiline,
4640 r#"{
4641 // test
4642}"#,
4643 );
4644
4645 run_test(r#"{"a": 1}"#, TrailingCommaMode::Never, r#"{"a": 1}"#);
4647 run_test(r#"{"a": 1}"#, TrailingCommaMode::IfMultiline, r#"{"a": 1}"#);
4648 run_test(
4650 r#"{
4651 "a": 1,
4652 "b": 2,
4653 "c": [1, 2, 3],
4654 "d": [
4655 1
4656 ]
4657}"#,
4658 TrailingCommaMode::IfMultiline,
4659 r#"{
4660 "a": 1,
4661 "b": 2,
4662 "c": [1, 2, 3],
4663 "d": [
4664 1,
4665 ],
4666}"#,
4667 );
4668 run_test(
4669 r#"{
4670"a": 1,
4671"b": 2,
4672}"#,
4673 TrailingCommaMode::Never,
4674 r#"{
4675"a": 1,
4676"b": 2
4677}"#,
4678 );
4679 }
4680
4681 #[test]
4682 fn or_create_methods() {
4683 let cst = build_cst("");
4684 let obj = cst.object_value_or_create().unwrap();
4685 assert_eq!(cst.to_string(), "{}\n");
4686 assert!(cst.array_value_or_create().is_none());
4687 assert_eq!(obj.object_value_or_create("prop").unwrap().to_string(), "{}");
4688 assert!(obj.array_value_or_create("prop").is_none());
4689 assert_eq!(obj.array_value_or_create("prop2").unwrap().to_string(), "[]");
4690 assert_eq!(
4691 cst.to_string(),
4692 r#"{
4693 "prop": {},
4694 "prop2": []
4695}
4696"#
4697 );
4698 }
4699
4700 #[test]
4701 fn or_set_methods() {
4702 let cst = build_cst("");
4703 let array = cst.array_value_or_set();
4704 assert_eq!(array.to_string(), "[]");
4705 assert_eq!(cst.to_string(), "[]\n");
4706 let object = cst.object_value_or_set();
4707 assert_eq!(object.to_string(), "{}");
4708 assert_eq!(cst.to_string(), "{}\n");
4709 let value = object.array_value_or_set("test");
4710 assert_eq!(value.to_string(), "[]");
4711 assert_eq!(cst.to_string(), "{\n \"test\": []\n}\n");
4712 let value = object.object_value_or_set("test");
4713 assert_eq!(value.to_string(), "{}");
4714 assert_eq!(cst.to_string(), "{\n \"test\": {}\n}\n");
4715 let value = object.array_value_or_set("test");
4716 assert_eq!(value.to_string(), "[]");
4717 assert_eq!(cst.to_string(), "{\n \"test\": []\n}\n");
4718 value.append(json!(1));
4719 assert_eq!(cst.to_string(), "{\n \"test\": [1]\n}\n");
4720 let value = object.object_value_or_set("test");
4721 assert_eq!(value.to_string(), "{}");
4722 assert_eq!(cst.to_string(), "{\n \"test\": {}\n}\n");
4723 let test_prop = object.get("test").unwrap();
4724 assert!(test_prop.object_value().is_some());
4725 assert!(test_prop.array_value().is_none());
4726 test_prop.array_value_or_set();
4727 assert_eq!(cst.to_string(), "{\n \"test\": []\n}\n");
4728 assert!(test_prop.object_value().is_none());
4729 assert!(test_prop.array_value().is_some());
4730 test_prop.object_value_or_set();
4731 assert_eq!(cst.to_string(), "{\n \"test\": {}\n}\n");
4732 }
4733
4734 #[test]
4735 fn expression_properties_and_values() {
4736 #[track_caller]
4737 fn run_test(value: CstInputValue, expected: &str) {
4738 let cst = build_cst("");
4739 cst.set_value(value);
4740 assert_eq!(cst.to_string(), format!("{}\n", expected));
4741 }
4742
4743 run_test(json!(1), "1");
4744 run_test(json!("test"), "\"test\"");
4745 {
4746 let text = "test";
4747 run_test(json!(text), "\"test\"");
4748 }
4749 {
4750 let num = 1;
4751 run_test(json!(num), "1");
4752 }
4753 {
4754 let vec = vec![1, 2, 3];
4755 run_test(json!(vec), "[1, 2, 3]");
4756 }
4757 {
4758 let vec = vec![1, 2, 3];
4759 run_test(
4760 json!({
4761 "value": vec,
4762 }),
4763 r#"{
4764 "value": [1, 2, 3]
4765}"#,
4766 );
4767 }
4768 run_test(
4769 json!({
4770 notQuoted: 1,
4771 "quoted": 2,
4772 }),
4773 r#"{
4774 "notQuoted": 1,
4775 "quoted": 2
4776}"#,
4777 )
4778 }
4779
4780 #[test]
4781 fn property_index() {
4782 let cst = build_cst("{ \"prop\": 1, \"prop2\": 2, \"prop3\": 3 }");
4783 let object = cst.object_value().unwrap();
4784 for (i, prop) in object.properties().into_iter().enumerate() {
4785 assert_eq!(prop.property_index(), i);
4786 }
4787 }
4788
4789 #[test]
4790 fn element_index() {
4791 let cst = build_cst("[1, 2, true ,false]");
4792 let array = cst.array_value().unwrap();
4793 for (i, prop) in array.elements().into_iter().enumerate() {
4794 assert_eq!(prop.element_index().unwrap(), i);
4795 }
4796 }
4797
4798 #[test]
4799 fn missing_comma_between_array_elements() {
4800 build_cst("[1 2]");
4801
4802 let options = crate::ParseOptions {
4804 allow_missing_commas: false,
4805 ..Default::default()
4806 };
4807 assert_eq!(
4808 CstRootNode::parse("[1 2]", &options).err().unwrap().to_string(),
4809 "Expected comma on line 1 column 3"
4810 );
4811 CstRootNode::parse("[1, 2]", &options).unwrap();
4812 }
4813
4814 #[test]
4815 fn sort_properties() {
4816 #[track_caller]
4817 fn run_test(json: &str, expected: &str) {
4818 let cst = build_cst(json);
4819 let root_obj = cst.object_value().unwrap();
4820 root_obj.sort_properties().by_key(|prop| prop.decoded_name());
4821 assert_eq!(cst.to_string(), expected);
4822 build_cst(&cst.to_string());
4824 let sorted = cst.to_string();
4825 root_obj.sort_properties().by_key(|prop| prop.decoded_name());
4826 assert_eq!(cst.to_string(), sorted);
4827 }
4828
4829 run_test("{\n \"b\": 2,\n \"a\": 1\n}", "{\n \"a\": 1,\n \"b\": 2\n}");
4830 run_test("{ \"b\": 2, \"a\": 1 }", "{ \"a\": 1, \"b\": 2 }");
4832 run_test("{\"b\":2,\"a\":1}", "{\"a\":1,\"b\":2}");
4833 run_test("{\n \"b\": 2,\n \"a\": 1,\n}", "{\n \"a\": 1,\n \"b\": 2,\n}");
4835 run_test("{}", "{}");
4837 run_test("{ \"a\": 1 }", "{ \"a\": 1 }");
4838 run_test("{\n \"a\": 1,\n \"b\": 2\n}", "{\n \"a\": 1,\n \"b\": 2\n}");
4839 run_test(
4841 "{\n \"b\": { \"z\": 1 },\n \"a\": [3, 1]\n}",
4842 "{\n \"a\": [3, 1],\n \"b\": { \"z\": 1 }\n}",
4843 );
4844 run_test("{\n b: 2,\n a: 1\n}", "{\n a: 1,\n b: 2\n}");
4846 run_test(
4848 "{\n \"b\": 2,\n \"\\u0061\": 1\n}",
4849 "{\n \"\\u0061\": 1,\n \"b\": 2\n}",
4850 );
4851 run_test(
4853 "{\n \"b\": 2,\n \"a\": \"first\",\n \"a\": \"second\"\n}",
4854 "{\n \"a\": \"first\",\n \"a\": \"second\",\n \"b\": 2\n}",
4855 );
4856 run_test("{\n \"b\": 2\n \"a\": 1\n}", "{\n \"a\": 1,\n \"b\": 2\n}");
4858 run_test("{\n \"b\": 2\n , \"a\": 1\n}", "{\n \"a\": 1, \"b\": 2\n\n}");
4860 run_test("{ \"b\": 2 , \"a\": 1 }", "{ \"a\": 1, \"b\": 2 }");
4862 run_test("{\n \"b\": 2, \"a\": 1\n}", "{\n \"a\": 1, \"b\": 2\n}");
4864 run_test(
4866 "{\r\n \"b\": 2,\r\n \"a\": 1\r\n}",
4867 "{\r\n \"a\": 1,\r\n \"b\": 2\r\n}",
4868 );
4869 }
4870
4871 #[test]
4872 fn sort_properties_moves_comments_and_blank_lines() {
4873 #[track_caller]
4874 fn run_test(json: &str, expected: &str) {
4875 let cst = build_cst(json);
4876 let root_obj = cst.object_value().unwrap();
4877 root_obj.sort_properties().by_key(|prop| prop.decoded_name());
4878 assert_eq!(cst.to_string(), expected);
4879 build_cst(&cst.to_string());
4880 let sorted = cst.to_string();
4881 root_obj.sort_properties().by_key(|prop| prop.decoded_name());
4882 assert_eq!(cst.to_string(), sorted);
4883 }
4884
4885 run_test(
4887 "{\n // about b\n \"b\": 2,\n \"a\": 1\n}",
4888 "{\n \"a\": 1,\n // about b\n \"b\": 2\n}",
4889 );
4890 run_test(
4892 "{\n \"b\": 2, // about b\n \"a\": 1\n}",
4893 "{\n \"a\": 1,\n \"b\": 2 // about b\n}",
4894 );
4895 run_test(
4897 "{\n \"b\": 2,\n \"a\": 1 // about a\n}",
4898 "{\n \"a\": 1, // about a\n \"b\": 2\n}",
4899 );
4900 run_test(
4902 "{ // about the object\n \"b\": 2,\n \"a\": 1\n}",
4903 "{ // about the object\n \"a\": 1,\n \"b\": 2\n}",
4904 );
4905 run_test(
4907 "{\n \"b\": 2,\n \"a\": 1\n // dangling\n}",
4908 "{\n \"a\": 1,\n \"b\": 2\n // dangling\n}",
4909 );
4910 run_test(
4912 "{ \"b\": 2, /* between */ \"a\": 1 }",
4913 "{ /* between */ \"a\": 1, \"b\": 2 }",
4914 );
4915 run_test(
4917 "{\n /* about b */\n \"b\": 2,\n \"a\": 1\n}",
4918 "{\n \"a\": 1,\n /* about b */\n \"b\": 2\n}",
4919 );
4920 run_test(
4922 "{\n \"c\": 3,\n \"a\": 1,\n\n \"b\": 2\n}",
4923 "{\n \"a\": 1,\n\n \"b\": 2,\n \"c\": 3\n}",
4924 );
4925 run_test("{\n \"b\": 2,\n\n \"a\": 1\n}", "{\n \"a\": 1,\n \"b\": 2\n}");
4927 }
4928
4929 #[test]
4930 fn sort_properties_pinning_comment_headers() {
4931 #[track_caller]
4932 fn run_test(json: &str, expected: &str) {
4933 let cst = build_cst(json);
4934 let root_obj = cst.object_value().unwrap();
4935 root_obj
4936 .sort_properties()
4937 .pin_comment_headers()
4938 .by_key(|prop| prop.decoded_name());
4939 assert_eq!(cst.to_string(), expected);
4940 build_cst(&cst.to_string());
4941 }
4942
4943 run_test(
4945 "{\n \"prop\": 1,\n\n // section\n \"prop2\": 2,\n \"prop1\": 1\n}",
4946 "{\n \"prop\": 1,\n\n // section\n \"prop1\": 1,\n \"prop2\": 2\n}",
4947 );
4948 run_test(
4950 "{\n // about b\n \"b\": 2,\n \"a\": 1\n}",
4951 "{\n \"a\": 1,\n // about b\n \"b\": 2\n}",
4952 );
4953 run_test(
4955 "{\n \"c\": 3,\n\n // section\n // about b\n \"b\": 2,\n \"a\": 1\n}",
4956 "{\n \"a\": 1,\n\n // section\n // about b\n \"b\": 2,\n \"c\": 3\n}",
4957 );
4958 run_test(
4960 "{\n \"c\": 3,\n\n \"b\": 2,\n \"a\": 1\n}",
4961 "{\n \"a\": 1,\n\n \"b\": 2,\n \"c\": 3\n}",
4962 );
4963 run_test(
4965 "{\n\n // first\n \"d\": 4,\n \"c\": 3,\n\n // second\n \"b\": 2,\n \"a\": 1\n}",
4966 "{\n\n // first\n \"a\": 1,\n \"b\": 2,\n\n // second\n \"c\": 3,\n \"d\": 4\n}",
4967 );
4968 run_test(
4970 "{\n \"c\": 3,\n\n /* section */\n \"b\": 2,\n \"a\": 1\n}",
4971 "{\n \"a\": 1,\n\n /* section */\n \"b\": 2,\n \"c\": 3\n}",
4972 );
4973 run_test("{\n \"b\": 2,\n \"a\": 1\n}", "{\n \"a\": 1,\n \"b\": 2\n}");
4975 }
4976
4977 #[test]
4978 fn sort_properties_within_groups() {
4979 #[track_caller]
4980 fn run_test(json: &str, expected: &str) {
4981 let cst = build_cst(json);
4982 let root_obj = cst.object_value().unwrap();
4983 root_obj
4984 .sort_properties()
4985 .within_groups()
4986 .by_key(|prop| prop.decoded_name());
4987 assert_eq!(cst.to_string(), expected);
4988 build_cst(&cst.to_string());
4989 }
4990
4991 run_test(
4993 "{\n \"m\": 1,\n\n // section\n \"z\": 2,\n \"a\": 3\n}",
4994 "{\n \"m\": 1,\n\n // section\n \"a\": 3,\n \"z\": 2\n}",
4995 );
4996 run_test(
4998 "{\n \"d\": 4,\n \"c\": 3,\n\n \"b\": 2,\n \"a\": 1\n}",
4999 "{\n \"c\": 3,\n \"d\": 4,\n\n \"a\": 1,\n \"b\": 2\n}",
5000 );
5001 run_test(
5003 "{\n \"b\": 2,\n\n \"d\": 4,\n \"c\": 3,\n}",
5004 "{\n \"b\": 2,\n\n \"c\": 3,\n \"d\": 4,\n}",
5005 );
5006 run_test("{\n \"b\": 2,\n\n \"a\": 1\n}", "{\n \"b\": 2,\n\n \"a\": 1\n}");
5008 run_test("{\n \"b\": 2,\n \"a\": 1\n}", "{\n \"a\": 1,\n \"b\": 2\n}");
5010 run_test(
5012 "{\n \"z\": 1,\n\n // section\n \"b\": 2,\n \"a\": 3\n}",
5013 "{\n \"z\": 1,\n\n // section\n \"a\": 3,\n \"b\": 2\n}",
5014 );
5015 run_test(
5017 "{\n \"z\": 1,\n\n \"c\": 3,\n // about b\n \"b\": 2,\n \"a\": 0\n}",
5018 "{\n \"z\": 1,\n\n \"a\": 0,\n // about b\n \"b\": 2,\n \"c\": 3\n}",
5019 );
5020 }
5021
5022 #[test]
5023 fn sort_properties_pinning_some_of_the_comments() {
5024 #[track_caller]
5025 fn run_test(json: &str, expected: &str) {
5026 let cst = build_cst(json);
5027 let root_obj = cst.object_value().unwrap();
5028 root_obj
5030 .sort_properties()
5031 .pin_comment_headers_with(|prop, _| if prop.has_blank_line_before() { 1 } else { 0 })
5032 .by_key(|prop| prop.decoded_name());
5033 assert_eq!(cst.to_string(), expected);
5034 build_cst(&cst.to_string());
5035 }
5036
5037 run_test(
5039 "{\n \"c\": 3,\n\n // section\n // about b\n \"b\": 2,\n \"a\": 1\n}",
5040 "{\n \"a\": 1,\n\n // section\n // about b\n \"b\": 2,\n \"c\": 3\n}",
5041 );
5042 run_test(
5044 "{\n \"c\": 3,\n\n // section\n\n // about b\n \"b\": 2,\n \"a\": 1\n}",
5045 "{\n \"a\": 1,\n\n // section\n\n // about b\n \"b\": 2,\n \"c\": 3\n}",
5046 );
5047 }
5048
5049 #[test]
5050 fn sort_gives_up_when_the_comparator_changes_the_object() {
5051 let text = "{
5052 \"b\": 2,
5053 \"a\": 1
5054}";
5055 let cst = build_cst(text);
5056 let root_obj = cst.object_value().unwrap();
5057 root_obj.sort_properties().by_key(|prop| {
5058 if prop.decoded_name().as_deref() == Some("b") {
5060 prop.clone().remove();
5061 }
5062 prop.decoded_name()
5063 });
5064
5065 assert_eq!(
5067 cst.to_string(),
5068 "{
5069 \"a\": 1
5070}"
5071 );
5072 }
5073
5074 #[test]
5075 fn sort_gives_up_when_the_comparator_replaces_a_member() {
5076 let cst = build_cst("{\n \"b\": 2,\n \"a\": 1\n}");
5077 let root_obj = cst.object_value().unwrap();
5078 root_obj.sort_properties().by_key(|prop| {
5079 let name = prop.decoded_name();
5080 if name.as_deref() == Some("b") {
5082 prop.clone().replace_with("zzz", json!(9));
5083 }
5084 name
5085 });
5086
5087 assert_eq!(cst.to_string(), "{\n \"zzz\": 9,\n \"a\": 1\n}");
5089 }
5090
5091 #[test]
5092 fn sort_keeps_line_comments_ending_their_line() {
5093 #[track_caller]
5094 fn run_test(json: &str, expected: &str) {
5095 let cst = build_cst(json);
5096 let root_obj = cst.object_value().unwrap();
5097 root_obj.sort_properties().by_key(|prop| prop.decoded_name());
5098 assert_eq!(cst.to_string(), expected);
5099 build_cst(&cst.to_string());
5101 let sorted = cst.to_string();
5102 root_obj.sort_properties().by_key(|prop| prop.decoded_name());
5103 assert_eq!(cst.to_string(), sorted);
5104 }
5105
5106 run_test(
5108 "{\"b\": 2, \"a\": 1 // about a\n}",
5109 "{\"a\": 1, // about a\n \"b\": 2\n}",
5110 );
5111 run_test(
5113 "{ \"b\": 2, // about b\n \"a\": 1 }",
5114 "{ \"a\": 1,\n \"b\": 2 // about b\n }",
5115 );
5116 run_test(
5118 "{\"b\": 2, \"a\": 1 /* about a */}",
5119 "{\"a\": 1, /* about a */ \"b\": 2}",
5120 );
5121 }
5122
5123 #[test]
5124 fn sort_properties_keeps_the_tree_usable() {
5125 let cst = build_cst("{\n \"b\": 2,\n \"a\": 1\n}");
5126 let root_obj = cst.object_value().unwrap();
5127 let b = root_obj.get("b").unwrap();
5128 root_obj.sort_properties().by_key(|prop| prop.decoded_name());
5129
5130 assert_eq!(b.decoded_name().unwrap(), "b");
5132 assert_eq!(b.property_index(), 1);
5133 assert_eq!(
5134 root_obj
5135 .properties()
5136 .iter()
5137 .map(|p| p.decoded_name().unwrap())
5138 .collect::<Vec<_>>(),
5139 ["a", "b"]
5140 );
5141 b.set_value(json!(3));
5143 assert_eq!(cst.to_string(), "{\n \"a\": 1,\n \"b\": 3\n}");
5144 }
5145
5146 #[test]
5147 fn sort_elements() {
5148 #[track_caller]
5149 fn run_test(json: &str, expected: &str) {
5150 let cst = build_cst(json);
5151 let array = cst.array_value().unwrap();
5152 array.sort_elements().by_key(|element| element.to_string());
5153 assert_eq!(cst.to_string(), expected);
5154 build_cst(&cst.to_string());
5155 let sorted = cst.to_string();
5156 array.sort_elements().by_key(|element| element.to_string());
5157 assert_eq!(cst.to_string(), sorted);
5158 }
5159
5160 run_test("[3, 1, 2]", "[1, 2, 3]");
5161 run_test("[\n 3,\n 1\n]", "[\n 1,\n 3\n]");
5162 run_test("[\n 3,\n 1,\n]", "[\n 1,\n 3,\n]");
5164 run_test("[\n // about 3\n 3,\n 1\n]", "[\n 1,\n // about 3\n 3\n]");
5166 run_test("[\n 3, // about 3\n 1\n]", "[\n 1,\n 3 // about 3\n]");
5168 run_test("[2, // about 2\n1]", "[1,\n2 // about 2\n]");
5170 run_test("[\n 3,\n\n 1\n]", "[\n 1,\n 3\n]");
5172 run_test("[]", "[]");
5174 run_test("[1]", "[1]");
5175 run_test("[\n [3, 2],\n {\"a\": 1}\n]", "[\n [3, 2],\n {\"a\": 1}\n]");
5177 }
5178
5179 #[track_caller]
5180 fn build_cst(text: &str) -> CstRootNode {
5181 CstRootNode::parse(text, &crate::ParseOptions::default()).unwrap()
5182 }
5183
5184 #[cfg(feature = "serde_json")]
5185 mod serde_tests {
5186 use super::build_cst;
5187 use serde_json::Value as SerdeValue;
5188 use std::str::FromStr;
5189
5190 #[test]
5191 fn test_cst_to_serde_value_primitives() {
5192 let root = build_cst(r#"42"#);
5193 let value = root.to_serde_value().unwrap();
5194 assert_eq!(value, SerdeValue::Number(serde_json::Number::from_str("42").unwrap()));
5195
5196 let root = build_cst(r#""hello""#);
5197 let value = root.to_serde_value().unwrap();
5198 assert_eq!(value, SerdeValue::String("hello".to_string()));
5199
5200 let root = build_cst(r#"true"#);
5201 let value = root.to_serde_value().unwrap();
5202 assert_eq!(value, SerdeValue::Bool(true));
5203
5204 let root = build_cst(r#"false"#);
5205 let value = root.to_serde_value().unwrap();
5206 assert_eq!(value, SerdeValue::Bool(false));
5207
5208 let root = build_cst(r#"null"#);
5209 let value = root.to_serde_value().unwrap();
5210 assert_eq!(value, SerdeValue::Null);
5211 }
5212
5213 #[test]
5214 fn test_cst_to_serde_value_json5_numbers() {
5215 let root = build_cst(r#"[.5, -.5, +5., 5.e3, NaN]"#);
5216 let value = root.to_serde_value().unwrap();
5217 assert_eq!(value, serde_json::json!([0.5, -0.5, 5.0, 5000.0, "NaN"]));
5218 assert!(value[2].is_f64());
5219 assert_eq!(root.to_string(), "[.5, -.5, +5., 5.e3, NaN]");
5220 }
5221
5222 #[test]
5223 fn test_cst_json5_strings_and_line_terminators() {
5224 let text = "{\r // a\r 'k': 'line\\\ncontinued \\x41\\v',\u{2028} // b\r \"it\\'s\": 1,\r}";
5225 let root = build_cst(text);
5226 assert_eq!(root.to_string(), text);
5227 assert_eq!(
5228 root.to_serde_value().unwrap(),
5229 serde_json::json!({ "k": "linecontinued A\u{0B}", "it's": 1 })
5230 );
5231 }
5232
5233 #[test]
5234 fn test_cst_to_serde_value_array() {
5235 let root = build_cst(r#"[1, 2, 3]"#);
5236 let value = root.to_serde_value().unwrap();
5237 let expected = SerdeValue::Array(vec![
5238 SerdeValue::Number(serde_json::Number::from_str("1").unwrap()),
5239 SerdeValue::Number(serde_json::Number::from_str("2").unwrap()),
5240 SerdeValue::Number(serde_json::Number::from_str("3").unwrap()),
5241 ]);
5242 assert_eq!(value, expected);
5243 }
5244
5245 #[test]
5246 fn test_cst_to_serde_value_array_with_comments() {
5247 let root = build_cst(
5248 r#"[
5249 // comment 1
5250 1,
5251 2, // comment 2
5252 3
5253 ]"#,
5254 );
5255 let value = root.to_serde_value().unwrap();
5256 let expected = SerdeValue::Array(vec![
5257 SerdeValue::Number(serde_json::Number::from_str("1").unwrap()),
5258 SerdeValue::Number(serde_json::Number::from_str("2").unwrap()),
5259 SerdeValue::Number(serde_json::Number::from_str("3").unwrap()),
5260 ]);
5261 assert_eq!(value, expected);
5262 }
5263
5264 #[test]
5265 fn test_cst_to_serde_value_object() {
5266 let root = build_cst(
5267 r#"{
5268 "name": "Alice",
5269 "age": 30,
5270 "active": true
5271 }"#,
5272 );
5273 let value = root.to_serde_value().unwrap();
5274
5275 let mut expected_map = serde_json::map::Map::new();
5276 expected_map.insert("name".to_string(), SerdeValue::String("Alice".to_string()));
5277 expected_map.insert(
5278 "age".to_string(),
5279 SerdeValue::Number(serde_json::Number::from_str("30").unwrap()),
5280 );
5281 expected_map.insert("active".to_string(), SerdeValue::Bool(true));
5282
5283 assert_eq!(value, SerdeValue::Object(expected_map));
5284 }
5285
5286 #[test]
5287 fn test_cst_to_serde_value_object_with_comments() {
5288 let root = build_cst(
5289 r#"{
5290 // This is a name
5291 "name": "Bob",
5292 /* age field */
5293 "age": 25
5294 }"#,
5295 );
5296 let value = root.to_serde_value().unwrap();
5297
5298 let mut expected_map = serde_json::map::Map::new();
5299 expected_map.insert("name".to_string(), SerdeValue::String("Bob".to_string()));
5300 expected_map.insert(
5301 "age".to_string(),
5302 SerdeValue::Number(serde_json::Number::from_str("25").unwrap()),
5303 );
5304
5305 assert_eq!(value, SerdeValue::Object(expected_map));
5306 }
5307
5308 #[test]
5309 fn test_cst_to_serde_value_nested() {
5310 let root = build_cst(
5311 r#"{
5312 "person": {
5313 "name": "Charlie",
5314 "hobbies": ["reading", "gaming"]
5315 },
5316 "count": 42
5317 }"#,
5318 );
5319 let value = root.to_serde_value().unwrap();
5320
5321 let mut hobbies = Vec::new();
5322 hobbies.push(SerdeValue::String("reading".to_string()));
5323 hobbies.push(SerdeValue::String("gaming".to_string()));
5324
5325 let mut person_map = serde_json::map::Map::new();
5326 person_map.insert("name".to_string(), SerdeValue::String("Charlie".to_string()));
5327 person_map.insert("hobbies".to_string(), SerdeValue::Array(hobbies));
5328
5329 let mut expected_map = serde_json::map::Map::new();
5330 expected_map.insert("person".to_string(), SerdeValue::Object(person_map));
5331 expected_map.insert(
5332 "count".to_string(),
5333 SerdeValue::Number(serde_json::Number::from_str("42").unwrap()),
5334 );
5335
5336 assert_eq!(value, SerdeValue::Object(expected_map));
5337 }
5338
5339 #[test]
5340 fn test_cst_to_serde_value_with_trailing_comma() {
5341 let root = build_cst(
5342 r#"{
5343 "a": 1,
5344 "b": 2,
5345 }"#,
5346 );
5347 let value = root.to_serde_value().unwrap();
5348
5349 let mut expected_map = serde_json::map::Map::new();
5350 expected_map.insert(
5351 "a".to_string(),
5352 SerdeValue::Number(serde_json::Number::from_str("1").unwrap()),
5353 );
5354 expected_map.insert(
5355 "b".to_string(),
5356 SerdeValue::Number(serde_json::Number::from_str("2").unwrap()),
5357 );
5358
5359 assert_eq!(value, SerdeValue::Object(expected_map));
5360 }
5361
5362 #[test]
5363 fn test_cst_to_serde_value_empty_structures() {
5364 let root = build_cst(r#"{}"#);
5365 let value = root.to_serde_value().unwrap();
5366 assert_eq!(value, SerdeValue::Object(serde_json::map::Map::new()));
5367
5368 let root = build_cst(r#"[]"#);
5369 let value = root.to_serde_value().unwrap();
5370 assert_eq!(value, SerdeValue::Array(Vec::new()));
5371 }
5372
5373 #[test]
5374 fn test_cst_to_serde_value_scientific_notation() {
5375 let root = build_cst(r#"0.3e+025"#);
5376 let value = root.to_serde_value().unwrap();
5377 assert_eq!(
5378 value,
5379 SerdeValue::Number(serde_json::Number::from_str("0.3e+025").unwrap())
5380 );
5381 }
5382
5383 #[test]
5384 fn test_cst_node_to_serde_value() {
5385 let root = build_cst(r#"{ "test": 123 }"#);
5386 let value_node = root.value().unwrap();
5387 let json_value = value_node.to_serde_value().unwrap();
5388
5389 let mut expected_map = serde_json::map::Map::new();
5390 expected_map.insert(
5391 "test".to_string(),
5392 SerdeValue::Number(serde_json::Number::from_str("123").unwrap()),
5393 );
5394
5395 assert_eq!(json_value, SerdeValue::Object(expected_map));
5396 }
5397
5398 #[test]
5399 fn test_cst_object_prop_to_serde_value() {
5400 let root = build_cst(r#"{ "key": [1, 2, 3] }"#);
5401 let obj = root.value().unwrap().as_object().unwrap();
5402 let prop = obj.get("key").unwrap();
5403 let prop_value = prop.to_serde_value().unwrap();
5404
5405 let expected = SerdeValue::Array(vec![
5406 SerdeValue::Number(serde_json::Number::from_str("1").unwrap()),
5407 SerdeValue::Number(serde_json::Number::from_str("2").unwrap()),
5408 SerdeValue::Number(serde_json::Number::from_str("3").unwrap()),
5409 ]);
5410
5411 assert_eq!(prop_value, expected);
5412 }
5413 }
5414
5415 #[test]
5416 fn new_escaped_handles_backslashes() {
5417 let cst = build_cst(r#"{"key": "old"}"#);
5418 let root_obj = cst.object_value().unwrap();
5419 let prop = root_obj.get("key").unwrap();
5420 prop.set_value(json!("/.github/workflows/lint\\.yaml$/"));
5422 assert_eq!(cst.to_string(), r#"{"key": "/.github/workflows/lint\\.yaml$/"}"#,);
5423 let decoded = root_obj
5425 .get("key")
5426 .unwrap()
5427 .value()
5428 .unwrap()
5429 .as_string_lit()
5430 .unwrap()
5431 .decoded_value()
5432 .unwrap();
5433 assert_eq!(decoded, "/.github/workflows/lint\\.yaml$/");
5434 }
5435
5436 #[test]
5437 fn new_escaped_handles_control_characters() {
5438 let cst = build_cst(r#"{}"#);
5439 let root_obj = cst.object_value_or_create().unwrap();
5440
5441 root_obj.append("tab", json!("hello\tworld"));
5442 root_obj.append("newline", json!("hello\nworld"));
5443 root_obj.append("cr", json!("hello\rworld"));
5444 root_obj.append("backspace", json!("hello\u{08}world"));
5445 root_obj.append("formfeed", json!("hello\u{0c}world"));
5446
5447 let text = cst.to_string();
5448 assert!(text.contains(r#""hello\tworld""#), "tab not escaped: {}", text);
5449 assert!(text.contains(r#""hello\nworld""#), "newline not escaped: {}", text);
5450 assert!(text.contains(r#""hello\rworld""#), "cr not escaped: {}", text);
5451 assert!(text.contains(r#""hello\bworld""#), "backspace not escaped: {}", text);
5452 assert!(text.contains(r#""hello\fworld""#), "formfeed not escaped: {}", text);
5453
5454 for (key, expected) in [
5456 ("tab", "hello\tworld"),
5457 ("newline", "hello\nworld"),
5458 ("cr", "hello\rworld"),
5459 ("backspace", "hello\u{08}world"),
5460 ("formfeed", "hello\u{0c}world"),
5461 ] {
5462 let decoded = root_obj
5463 .get(key)
5464 .unwrap()
5465 .value()
5466 .unwrap()
5467 .as_string_lit()
5468 .unwrap()
5469 .decoded_value()
5470 .unwrap();
5471 assert_eq!(decoded, expected, "roundtrip failed for key: {}", key);
5472 }
5473 }
5474
5475 #[test]
5476 fn new_escaped_handles_quotes_and_backslashes_together() {
5477 let cst = build_cst(r#"{}"#);
5478 let root_obj = cst.object_value_or_create().unwrap();
5479
5480 root_obj.append("mixed", json!("say \"hello\\world\""));
5481
5482 let text = cst.to_string();
5483 assert!(
5484 text.contains(r#""say \"hello\\world\"""#),
5485 "mixed escaping failed: {}",
5486 text
5487 );
5488
5489 let decoded = root_obj
5490 .get("mixed")
5491 .unwrap()
5492 .value()
5493 .unwrap()
5494 .as_string_lit()
5495 .unwrap()
5496 .decoded_value()
5497 .unwrap();
5498 assert_eq!(decoded, "say \"hello\\world\"");
5499 }
5500
5501 #[test]
5502 fn new_escaped_in_array_values() {
5503 let cst = build_cst(r#"{"items": []}"#);
5504 let root_obj = cst.object_value().unwrap();
5505 let arr = root_obj.array_value("items").unwrap();
5506
5507 arr.append(json!("path\\to\\file"));
5508 arr.append(json!("line1\nline2"));
5509
5510 let text = cst.to_string();
5511 assert!(
5512 text.contains(r#""path\\to\\file""#),
5513 "backslash in array element: {}",
5514 text
5515 );
5516 assert!(text.contains(r#""line1\nline2""#), "newline in array element: {}", text);
5517 }
5518
5519 #[test]
5520 fn new_escaped_property_name_with_special_chars() {
5521 let cst = build_cst(r#"{}"#);
5522 let root_obj = cst.object_value_or_create().unwrap();
5523
5524 root_obj.append("key\\with\\backslash", json!("value"));
5525
5526 let text = cst.to_string();
5527 assert!(
5528 text.contains(r#""key\\with\\backslash""#),
5529 "property name escaping failed: {}",
5530 text
5531 );
5532
5533 let decoded = root_obj
5534 .properties()
5535 .first()
5536 .unwrap()
5537 .name()
5538 .unwrap()
5539 .decoded_value()
5540 .unwrap();
5541 assert_eq!(decoded, "key\\with\\backslash");
5542 }
5543
5544 #[test]
5545 fn lone_carriage_return_ends_line_comment() {
5546 #[track_caller]
5548 fn run_test(json: &str, edit: impl Fn(&CstRootNode)) {
5549 let lf_cst = build_cst(json);
5550 edit(&lf_cst);
5551 let cr_cst = build_cst(&json.replace('\n', "\r"));
5552 assert_eq!(cr_cst.newline_kind(), CstNewlineKind::CarriageReturn);
5553 edit(&cr_cst);
5554 assert_eq!(cr_cst.to_string(), lf_cst.to_string().replace('\n', "\r"));
5555 }
5556
5557 run_test("[ // note\n]", |cst| {
5558 cst.array_value().unwrap().append(json!(3));
5559 });
5560 run_test("[\n 1 // one\n]", |cst| {
5561 cst.array_value().unwrap().append(json!(3));
5562 });
5563 run_test("{\n \"b\": 1, // bee\n \"a\": 2\n}", |cst| {
5564 cst
5565 .object_value()
5566 .unwrap()
5567 .sort_properties()
5568 .by_key(|prop| prop.decoded_name());
5569 });
5570 }
5571}