Skip to main content

jsonc_parser/cst/
mod.rs

1//! CST for manipulating JSONC.
2//!
3//! Unlike the AST, this keeps every comment and every piece of whitespace, so a document can be
4//! edited and written back out with everything the author wrote still in place.
5//!
6//! # Example
7//!
8//! ```
9//! use jsonc_parser::cst::CstRootNode;
10//! use jsonc_parser::ParseOptions;
11//! use jsonc_parser::json;
12//!
13//! let json_text = r#"{
14//!   // comment
15//!   "data": 123
16//! }"#;
17//!
18//! let root = CstRootNode::parse(json_text, &ParseOptions::default()).unwrap();
19//! let root_obj = root.object_value_or_set();
20//!
21//! root_obj.get("data").unwrap().set_value(json!({
22//!   "nested": true
23//! }));
24//! root_obj.append("new_key", json!([456, 789, false]));
25//!
26//! assert_eq!(root.to_string(), r#"{
27//!   // comment
28//!   "data": {
29//!     "nested": true
30//!   },
31//!   "new_key": [456, 789, false]
32//! }"#);
33//! ```
34//!
35
36use 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    /// Gets the root node.
59    ///
60    /// Returns `None` if this node has become disconnected from
61    /// the tree by being removed.
62    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    /// Parent of the node.
77    ///
78    /// Returns `None` if this node has become disconnected from
79    /// the tree by being removed.
80    pub fn parent(&self) -> Option<CstContainerNode> {
81      self.parent_info().map(|p| p.parent.as_container_node())
82    }
83
84    /// An iterator of ancestors of this node.
85    pub fn ancestors(&self) -> impl Iterator<Item = CstContainerNode> {
86      AncestorIterator::new(self.clone().into())
87    }
88
89    /// Current child index of the node within the children of the
90    /// parent node.
91    pub fn child_index(&self) -> usize {
92      self.parent_info().map(|p| p.child_index).unwrap_or(0)
93    }
94
95    /// Node that comes before this one that shares the same parent.
96    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    /// Siblings coming before this node. This does not
108    /// include cousins.
109    pub fn previous_siblings(&self) -> impl Iterator<Item = CstNode> {
110      PreviousSiblingIterator::new(self.clone().into())
111    }
112
113    /// Node that comes after this one that shares the same parent.
114    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    /// Siblings coming after this node. This does not
123    /// include cousins.
124    pub fn next_siblings(&self) -> impl Iterator<Item = CstNode> {
125      NextSiblingIterator::new(self.clone().into())
126    }
127
128    /// Returns the indentation text if it can be determined.
129    pub fn indent_text(&self) -> Option<String> {
130      indent_text(&self.clone().into())
131    }
132
133    /// Whether a blank line separates this node, and the comments written above it, from
134    /// whatever came before them.
135    pub fn has_blank_line_before(&self) -> bool {
136      has_blank_line_before(&self.clone().into())
137    }
138
139    /// Gets the trailing comma token of the node, if it exists.
140    pub fn trailing_comma(&self) -> Option<CstToken> {
141      find_trailing_comma(&self.clone().into())
142    }
143
144    /// Infers if the node or appropriate ancestor uses trailing commas.
145    pub fn uses_trailing_commas(&self) -> bool {
146      uses_trailing_commas(self.clone().into())
147    }
148  };
149}
150
151/// Whether a blank line separates the node, and the comments written above it, from what came
152/// before them.
153fn 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          // skip over
176        }
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      /// Children of the current node.
222      pub fn children(&self) -> Vec<CstNode> {
223        self.0.borrow().value.clone()
224      }
225
226      /// Children of the current node excluding comments, whitespace, newlines, and tokens.
227      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      /// Gets the child at the specified index.
239      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          // update the index of the remaining children
251          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    // It's much better to panic here to let the developer know an ancestor has been
294    // lost due to being dropped because if we did something like returning None then
295    // it might create strange bugs that are hard to track down.
296    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/// All the different kinds of nodes that can appear in the CST.
327#[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  /// Gets if this node is comments, whitespace, newlines, or a non-literal token (ex. brace, colon).
338  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  /// Comments that become before this one on the same line.
354  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  /// Comments that come after this one on the same line.
365  ///
366  /// Only returns owned trailing comments on the same line and not if owned by the next node.
367  pub fn trailing_comments_same_line(&self) -> impl Iterator<Item = CstComment> {
368    // ensure the trailing comments are owned
369    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  /// If this node is a newline.
389  pub fn is_newline(&self) -> bool {
390    matches!(self, CstNode::Leaf(CstLeafNode::Newline(_)))
391  }
392
393  /// If this node is a comma.
394  pub fn is_comma(&self) -> bool {
395    match self {
396      CstNode::Leaf(CstLeafNode::Token(t)) => t.value() == ',',
397      _ => false,
398    }
399  }
400
401  /// If this node is a comment.
402  pub fn is_comment(&self) -> bool {
403    matches!(self, CstNode::Leaf(CstLeafNode::Comment(_)))
404  }
405
406  /// If this node is a token.
407  pub fn is_token(&self) -> bool {
408    matches!(self, CstNode::Leaf(CstLeafNode::Token(_)))
409  }
410
411  /// If this node is whitespace.
412  pub fn is_whitespace(&self) -> bool {
413    matches!(self, CstNode::Leaf(CstLeafNode::Whitespace(_)))
414  }
415
416  /// Token char of the node if it's a token.
417  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  /// Children of this node.
425  pub fn children(&self) -> Vec<CstNode> {
426    match self {
427      CstNode::Container(n) => n.children(),
428      CstNode::Leaf(_) => Vec::new(),
429    }
430  }
431
432  /// Children of the current node excluding comments, whitespace, newlines, and tokens.
433  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  /// Child at the specified index.
441  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  /// Gets the array element index of this node if its parent is an array.
449  ///
450  /// Returns `None` when the parent is not an array.
451  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  /// Node if it's the root node.
458  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  /// Node if it's an object.
466  pub fn as_object(&self) -> Option<CstObject> {
467    match self {
468      // doesn't return a reference so this is easier to use
469      CstNode::Container(CstContainerNode::Object(node)) => Some(node.clone()),
470      _ => None,
471    }
472  }
473
474  /// Node if it's an array.
475  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  /// Node if it's an object property.
483  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  /// Node if it's a boolean literal.
491  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  /// Node if it's a null keyword.
499  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  /// Node if it's a number literal.
507  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  /// Node if it's a string literal.
515  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  /// Node if it's a word literal.
523  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  /// Node if it's a token.
531  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  /// Node if it's a newline.
539  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  /// Node if it's whitespace.
547  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  /// Node if it's a comment.
555  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  /// Removes the node from the JSON.
563  ///
564  /// Note: Removing certain nodes may cause syntax errors.
565  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  /// Removes the node from the tree without making adjustments to any siblings.
587  fn remove_raw(self) {
588    let Some(parent_info) = self.parent_info() else {
589      return; // already removed
590    };
591    parent_info
592      .parent
593      .as_container_node()
594      .remove_child_set_no_parent(parent_info.child_index);
595  }
596
597  /// Converts a CST node to a `serde_json::Value`.
598  ///
599  /// This method extracts the actual value from the CST node, ignoring
600  /// trivia (comments, whitespace, etc.).
601  ///
602  /// Returns `None` if the node is trivia or cannot be converted to a value.
603  ///
604  /// # Example
605  ///
606  /// ```
607  /// use jsonc_parser::cst::CstRootNode;
608  /// use jsonc_parser::ParseOptions;
609  ///
610  /// let json_text = r#"{ "test": 5 } // comment"#;
611  /// let root = CstRootNode::parse(json_text, &ParseOptions::default()).unwrap();
612  ///
613  /// if let Some(value_node) = root.value() {
614  ///   let json_value = value_node.to_serde_value().unwrap();
615  ///   println!("{}", json_value);
616  /// }
617  /// ```
618  #[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/// Enumeration of a node that has children.
643#[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  /// If this is the root node.
656  pub fn is_root(&self) -> bool {
657    matches!(self, CstContainerNode::Root(_))
658  }
659
660  /// If this is an array node.
661  pub fn is_array(&self) -> bool {
662    matches!(self, CstContainerNode::Array(_))
663  }
664
665  /// If this is an object node.
666  pub fn is_object(&self) -> bool {
667    matches!(self, CstContainerNode::Object(_))
668  }
669
670  /// If this is an object property node.
671  pub fn is_object_prop(&self) -> bool {
672    matches!(self, CstContainerNode::ObjectProp(_))
673  }
674
675  /// Node if it's the root node.
676  pub fn as_root(&self) -> Option<CstRootNode> {
677    match self {
678      CstContainerNode::Root(node) => Some(node.clone()),
679      _ => None,
680    }
681  }
682
683  /// Node if it's an array.
684  pub fn as_array(&self) -> Option<CstArray> {
685    match self {
686      CstContainerNode::Array(node) => Some(node.clone()),
687      _ => None,
688    }
689  }
690
691  /// Node if it's an object.
692  pub fn as_object(&self) -> Option<CstObject> {
693    match self {
694      CstContainerNode::Object(node) => Some(node.clone()),
695      _ => None,
696    }
697  }
698
699  /// Node if it's an object property.
700  pub fn as_object_prop(&self) -> Option<CstObjectProp> {
701    match self {
702      CstContainerNode::ObjectProp(node) => Some(node.clone()),
703      _ => None,
704    }
705  }
706
707  /// Children of the node.
708  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  /// Children of the current node excluding comments, whitespace, newlines, and tokens.
718  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  /// Child at the specified index.
728  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  /// Removes the node from the JSON.
747  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  /// Replaces every child of this container, reparenting the new children.
790  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    // a child that isn't in the new list has left the tree, so it loses its parent
799    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    // update the child index of all the nodes
830    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  /// Converts a CST container node to a `serde_json::Value`.
959  ///
960  /// Returns `None` if the node cannot be converted to a value.
961  #[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/// Enumeration of a node that has no children.
990#[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  /// Removes the node from the JSON.
1008  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  /// Converts a CST leaf node to a `serde_json::Value`.
1051  ///
1052  /// Returns `None` if the node is trivia or cannot be converted to a value.
1053  #[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/// Mode to use for trailing commas.
1092#[derive(Default, Debug, Clone, Copy)]
1093pub enum TrailingCommaMode {
1094  /// Never use trailing commas.
1095  #[default]
1096  Never,
1097  /// Use trailing commas when the object is on multiple lines.
1098  IfMultiline,
1099}
1100
1101type CstRootNodeInner = RefCell<CstChildrenInner>;
1102
1103/// Root node in the file.
1104///
1105/// The root node contains one value, whitespace, and comments.
1106#[derive(Debug, Clone)]
1107pub struct CstRootNode(Rc<CstRootNodeInner>);
1108
1109impl_container_methods!(CstRootNode, Root);
1110
1111impl CstRootNode {
1112  /// Parses the text into a CST.
1113  ///
1114  /// WARNING: You MUST not drop the root node for the duration of using the CST
1115  /// or a panic could occur in certain scenarios. This is because the CST uses weak
1116  /// references for ancestors and if the root node is dropped then the weak reference
1117  /// will be lost and the CST will panic to prevent bugs when a descendant node
1118  /// attempts to access an ancestor that was dropped.
1119  ///
1120  /// ```
1121  /// use jsonc_parser::cst::CstRootNode;
1122  /// use jsonc_parser::ParseOptions;
1123  /// use jsonc_parser::json;
1124  ///
1125  /// let json_text = r#"{
1126  ///   // comment
1127  ///   "data": 123
1128  /// }"#;
1129  ///
1130  /// let root = CstRootNode::parse(json_text, &ParseOptions::default()).unwrap();
1131  /// let root_obj = root.object_value_or_set();
1132  ///
1133  /// root_obj.get("data").unwrap().set_value(json!({
1134  ///   "nested": true
1135  /// }));
1136  /// root_obj.append("new_key", json!([456, 789, false]));
1137  ///
1138  /// assert_eq!(root.to_string(), r#"{
1139  ///   // comment
1140  ///   "data": {
1141  ///     "nested": true
1142  ///   },
1143  ///   "new_key": [456, 789, false]
1144  /// }"#);
1145  /// ```
1146  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  /// Computes the single indentation text of the file.
1166  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  /// Newline kind used within the JSON text.
1187  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  /// Gets the root value found in the file.
1202  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  /// Sets potentially replacing the root value found in the JSON document.
1212  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        // insert a newline if the last node before is a comment
1232        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        // insert a trailing newline
1236        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  /// Gets the root value if its an object.
1250  pub fn object_value(&self) -> Option<CstObject> {
1251    self.value()?.as_object()
1252  }
1253
1254  /// Gets or creates the root value as an object, returns `Some` if successful
1255  /// or `None` if the root value already exists and is not an object.
1256  ///
1257  /// Note: Use `.object_value_or_set()` to overwrite the root value when
1258  /// it's not an object.
1259  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  /// Gets the root value if it's an object or sets the root value as an object.
1271  ///
1272  /// Note: Use `.object_value_or_create()` to not overwrite the root value
1273  /// when it's not an object.
1274  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  /// Gets the value if its an array.
1285  pub fn array_value(&self) -> Option<CstArray> {
1286    self.value()?.as_array()
1287  }
1288
1289  /// Gets or creates the root value as an object, returns `Some` if successful
1290  /// or `None` if the root value already exists and is not an object.
1291  ///
1292  /// Note: Use `.array_value_or_set()` to overwrite the root value when
1293  /// it's not an array.
1294  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  /// Gets the root value if it's an object or sets the root value as an object.
1306  ///
1307  /// Note: Use `.array_value_or_create()` to not overwrite the root value
1308  /// when it's not an object.
1309  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  /// Ensures this object's values use trailing commas.
1320  ///
1321  /// Note: This does not cause future values to use trailing commas.
1322  /// That will always be determined based on whether the file uses
1323  /// trailing commas or not, so it's probably best to do this last.
1324  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  /// Clears all the children from the root node making it empty.
1340  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  /// Converts the root CST node to a `serde_json::Value`.
1348  ///
1349  /// Returns `None` if the root has no value node.
1350  #[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/// Text surrounded in double quotes (ex. `"my string"`).
1366#[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  /// Sets the raw value of the string INCLUDING SURROUNDING QUOTES.
1399  pub fn set_raw_value(&self, value: String) {
1400    self.0.borrow_mut().value = value;
1401  }
1402
1403  /// Gets the raw unescaped value including quotes.
1404  pub fn raw_value(&self) -> String {
1405    self.0.borrow().value.clone()
1406  }
1407
1408  /// Gets the decoded string value.
1409  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  /// Replaces this node with a new value.
1417  pub fn replace_with(self, replacement: CstInputValue) -> Option<CstNode> {
1418    replace_with(self.into(), InsertValue::Value(replacement))
1419  }
1420
1421  /// Removes the node from the JSON.
1422  pub fn remove(self) {
1423    remove_comma_separated(self.into())
1424  }
1425
1426  /// Converts a CST string literal to a `serde_json::Value`.
1427  #[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/// Property key that is missing quotes (ex. `prop: 4`).
1440#[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  /// Sets the raw value of the word literal.
1451  pub fn set_raw_value(&self, value: String) {
1452    self.0.borrow_mut().value = value;
1453  }
1454
1455  /// Replaces this node with a new value.
1456  pub fn replace_with(self, replacement: CstInputValue) -> Option<CstNode> {
1457    replace_with(self.into(), InsertValue::Value(replacement))
1458  }
1459
1460  /// Removes the node from the JSON.
1461  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  /// Sets the raw string value of the number literal.
1483  pub fn set_raw_value(&self, value: String) {
1484    self.0.borrow_mut().value = value;
1485  }
1486
1487  /// Replaces this node with a new value.
1488  pub fn replace_with(self, replacement: CstInputValue) -> Option<CstNode> {
1489    replace_with(self.into(), InsertValue::Value(replacement))
1490  }
1491
1492  /// Removes the node from the JSON.
1493  pub fn remove(self) {
1494    remove_comma_separated(self.into())
1495  }
1496
1497  /// Converts a CST number literal to a `serde_json::Value`.
1498  #[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    // check if this is a hexadecimal literal (0x or 0X prefix)
1504    let num_str = raw.trim_start_matches(['-', '+']);
1505    if num_str.len() > 2 && (num_str.starts_with("0x") || num_str.starts_with("0X")) {
1506      // parse hexadecimal and convert to decimal
1507      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      // standard decimal number - strip leading + if present (serde_json doesn't accept it)
1521      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        // if the number is invalid, return it as a string (same behavior as AST conversion)
1525        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/// Boolean (`true` or `false`).
1538#[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  /// Gets the value of the boolean literal.
1549  pub fn value(&self) -> bool {
1550    self.0.borrow().value
1551  }
1552
1553  /// Sets the value of the boolean literal.
1554  pub fn set_value(&self, value: bool) {
1555    self.0.borrow_mut().value = value;
1556  }
1557
1558  /// Replaces this node with a new value.
1559  pub fn replace_with(self, replacement: CstInputValue) -> Option<CstNode> {
1560    replace_with(self.into(), InsertValue::Value(replacement))
1561  }
1562
1563  /// Removes the node from the JSON.
1564  pub fn remove(self) {
1565    remove_comma_separated(self.into())
1566  }
1567
1568  /// Converts a CST boolean literal to a `serde_json::Value`.
1569  #[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/// Null keyword (`null`).
1586#[derive(Debug, Clone)]
1587pub struct CstNullKeyword(Rc<RefCell<CstValueInner<()>>>);
1588
1589impl CstNullKeyword {
1590  fn new() -> Self {
1591    Self(CstValueInner::new(()))
1592  }
1593
1594  /// Replaces this node with a new value.
1595  pub fn replace_with(self, replacement: CstInputValue) -> Option<CstNode> {
1596    replace_with(self.into(), InsertValue::Value(replacement))
1597  }
1598
1599  /// Removes the node from the JSON.
1600  pub fn remove(self) {
1601    remove_comma_separated(self.into())
1602  }
1603
1604  /// Converts a CST null keyword to a `serde_json::Value`.
1605  #[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/// Object literal that may contain properties (ex. `{}`, `{ "prop": 4 }`).
1622#[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  /// Array property by name.
1642  ///
1643  /// Returns `None` if the property doesn't exist or is not an array.
1644  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  /// Ensures a property exists with an array value returning the array.
1652  ///
1653  /// Returns `None` if the property value exists, but is not an array.
1654  ///
1655  /// Note: Use `.array_value_or_set(..)` to overwrite an existing
1656  /// non-array property value.
1657  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  /// Ensures a property exists with an array value returning the array.
1671  ///
1672  /// Note: Use `.array_value_or_create(..)` to not overwrite an existing
1673  /// non-array property value.
1674  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  /// Object property by name.
1702  ///
1703  /// Returns `None` if the property doesn't exist or is not an object.
1704  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  /// Ensures a property exists with an object value returning the object.
1712  ///
1713  /// Returns `None` if the property value exists, but is not an object.
1714  ///
1715  /// Note: Use `.object_value_or_set(..)` to overwrite an existing
1716  /// non-array property value.
1717  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  /// Ensures a property exists with an object value returning the object.
1731  ///
1732  /// Note: Use `.object_value_or_create(..)` to not overwrite an existing
1733  /// non-object property value.
1734  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  /// Property by name.
1762  ///
1763  /// Returns `None` if the property doesn't exist.
1764  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  /// Properties of the object.
1782  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  /// Appends a property to the object.
1796  ///
1797  /// Returns the inserted object property.
1798  pub fn append(&self, prop_name: &str, value: CstInputValue) -> CstObjectProp {
1799    self.insert_or_append(None, prop_name, value)
1800  }
1801
1802  /// Inserts a property at the specified index.
1803  ///
1804  /// Returns the inserted object property.
1805  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  /// Sorts the properties of the object.
1822  ///
1823  /// What was written with a property travels with it: the comments and blank lines above it, and
1824  /// a comment written after it on the same line. Whatever precedes the close brace, and whatever
1825  /// shares the open brace's line, belongs to no property and stays where it is. Each property
1826  /// gains or loses a comma to suit its new position, and whether the object ends with a trailing
1827  /// comma is preserved.
1828  ///
1829  /// A blank line under the open brace travels with the property it was written above, and one
1830  /// that would end up there instead is dropped, since a gap there reads as belonging to the
1831  /// object. A line comment that would otherwise comment out what now follows it gains a line
1832  /// break, which can make a single line object span several.
1833  ///
1834  /// Nothing moves until [`PropertySort::by`] or [`PropertySort::by_key`] says how to order them.
1835  ///
1836  /// # Example
1837  ///
1838  /// ```
1839  /// use jsonc_parser::ParseOptions;
1840  /// use jsonc_parser::cst::CstRootNode;
1841  ///
1842  /// let json_text = r#"{
1843  ///   "b": 2, // written about b
1844  ///   // written about a
1845  ///   "a": 1
1846  /// }"#;
1847  ///
1848  /// let root = CstRootNode::parse(json_text, &ParseOptions::default()).unwrap();
1849  /// let root_obj = root.object_value().unwrap();
1850  /// root_obj.sort_properties().by_key(|prop| prop.decoded_name());
1851  ///
1852  /// assert_eq!(root.to_string(), r#"{
1853  ///   // written about a
1854  ///   "a": 1,
1855  ///   "b": 2 // written about b
1856  /// }"#);
1857  /// ```
1858  pub fn sort_properties(&self) -> PropertySort<'_> {
1859    PropertySort {
1860      object: self,
1861      options: SortOptions::default(),
1862    }
1863  }
1864
1865  /// Replaces this node with a new value.
1866  pub fn replace_with(self, replacement: CstInputValue) -> Option<CstNode> {
1867    replace_with(self.into(), InsertValue::Value(replacement))
1868  }
1869
1870  /// Ensures this object and all its descendants use trailing commas.
1871  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  /// Ensures the object spans multiple lines.
1880  pub fn ensure_multiline(&self) {
1881    ensure_multiline(&self.clone().into());
1882  }
1883
1884  /// Removes the node from the JSON.
1885  pub fn remove(self) {
1886    remove_comma_separated(self.into())
1887  }
1888
1889  /// Converts a CST object to a `serde_json::Value`.
1890  #[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/// Property in an object (ex. `"prop": 5`).
1914#[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  /// Name of the object property.
1927  ///
1928  /// Returns `None` if the name doesn't exist.
1929  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          // someone may have manipulated this object such that this is no longer there
1936        }
1937      }
1938    }
1939    None
1940  }
1941
1942  /// Name of the object property with any escapes in it resolved.
1943  ///
1944  /// Returns `None` if the name doesn't exist or can't be decoded.
1945  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  /// Value of the object property.
1986  ///
1987  /// Returns `None` if the value doesn't exist.
1988  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    // first, skip over the colon token
1995    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    // now find the value
2004    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            // ignore
2014          }
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  /// Gets the value if its an object.
2027  pub fn object_value(&self) -> Option<CstObject> {
2028    self.value()?.as_object()
2029  }
2030
2031  /// Gets the value if it's an object or sets the value as an object.
2032  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  /// Gets the value if its an array.
2043  pub fn array_value(&self) -> Option<CstArray> {
2044    self.value()?.as_array()
2045  }
2046
2047  /// Gets the value if it's an object or sets the value as an object.
2048  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  /// Sibling object property coming before this one.
2059  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  /// Sibling object property coming after this one.
2069  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  /// Replaces this node with a new value.
2079  pub fn replace_with(self, key: &str, replacement: CstInputValue) -> Option<CstNode> {
2080    replace_with(self.into(), InsertValue::Property(key, replacement))
2081  }
2082
2083  /// Removes the node from the JSON.
2084  pub fn remove(self) {
2085    remove_comma_separated(self.into())
2086  }
2087
2088  /// Converts a CST object property to a `serde_json::Value`.
2089  ///
2090  /// Returns the value of the property, or `None` if it has no value.
2091  #[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/// An object property name that may or may not be in quotes (ex. `"prop"` in `"prop": 5`).
2107#[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  /// Object property name if it's a string literal.
2118  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  /// Object property name if it's a word literal (no quotes).
2126  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  /// Decoded value of the string.
2134  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/// Represents an array that may contain elements (ex. `[]`, `[1, 2, 3]`).
2161#[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  /// Elements of the array.
2181  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  /// Appends an element to the end of the array.
2205  ///
2206  /// Returns the appended node.
2207  pub fn append(&self, value: CstInputValue) -> CstNode {
2208    self.insert_or_append(None, value)
2209  }
2210
2211  /// Inserts an element at the specified index.
2212  ///
2213  /// Returns the inserted node.
2214  pub fn insert(&self, index: usize, value: CstInputValue) -> CstNode {
2215    self.insert_or_append(Some(index), value)
2216  }
2217
2218  /// Sorts the elements of the array.
2219  ///
2220  /// Behaves like [`CstObject::sort_properties`], moving what was written with an element along
2221  /// with it. Nothing moves until [`ElementSort::by`] or [`ElementSort::by_key`] says how to
2222  /// order them.
2223  ///
2224  /// # Example
2225  ///
2226  /// ```
2227  /// use jsonc_parser::ParseOptions;
2228  /// use jsonc_parser::cst::CstRootNode;
2229  ///
2230  /// let json_text = r#"[
2231  ///   "b", // written about b
2232  ///   // written about a
2233  ///   "a"
2234  /// ]"#;
2235  ///
2236  /// let root = CstRootNode::parse(json_text, &ParseOptions::default()).unwrap();
2237  /// let array = root.array_value().unwrap();
2238  /// array.sort_elements().by_key(|element| element.to_string());
2239  ///
2240  /// assert_eq!(root.to_string(), r#"[
2241  ///   // written about a
2242  ///   "a",
2243  ///   "b" // written about b
2244  /// ]"#);
2245  /// ```
2246  pub fn sort_elements(&self) -> ElementSort<'_> {
2247    ElementSort {
2248      array: self,
2249      options: SortOptions::default(),
2250    }
2251  }
2252
2253  /// Ensures the array spans multiple lines.
2254  pub fn ensure_multiline(&self) {
2255    ensure_multiline(&self.clone().into());
2256  }
2257
2258  /// Ensures this array and all its descendants use trailing commas.
2259  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  /// Replaces this node with a new value.
2273  pub fn replace_with(self, replacement: CstInputValue) -> Option<CstNode> {
2274    replace_with(self.into(), InsertValue::Value(replacement))
2275  }
2276
2277  /// Removes the node from the JSON.
2278  pub fn remove(self) {
2279    remove_comma_separated(self.into())
2280  }
2281
2282  /// Converts a CST array to a `serde_json::Value`.
2283  #[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/// Insigificant token found in the file (ex. colon, comma, brace, etc.).
2304#[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  /// Sets the char value of the token.
2315  pub fn set_value(&self, value: char) {
2316    self.0.borrow_mut().value = value;
2317  }
2318
2319  /// Char value of the token.
2320  pub fn value(&self) -> char {
2321    self.0.borrow().value
2322  }
2323
2324  /// Removes the node from the JSON.
2325  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/// Blank space excluding newlines.
2337#[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  /// Sets the whitespace value.
2348  pub fn set_value(&self, value: String) {
2349    self.0.borrow_mut().value = value;
2350  }
2351
2352  /// Whitespace value of the node.
2353  pub fn value(&self) -> String {
2354    self.0.borrow().value.clone()
2355  }
2356
2357  /// Removes the node from the JSON.
2358  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/// Kind of newline.
2370#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
2371pub enum CstNewlineKind {
2372  #[default]
2373  LineFeed,
2374  CarriageReturnLineFeed,
2375  CarriageReturn,
2376}
2377
2378/// Newline character (Lf, crlf, or cr).
2379#[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  /// Whether this is a line feed (LF), carriage return line feed (CRLF), or carriage return (CR).
2390  pub fn kind(&self) -> CstNewlineKind {
2391    self.0.borrow().value
2392  }
2393
2394  /// Sets the newline kind.
2395  pub fn set_kind(&self, kind: CstNewlineKind) {
2396    self.0.borrow_mut().value = kind;
2397  }
2398
2399  /// Removes the node from the JSON.
2400  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)] // better to be explicit
2409      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  /// Whether this is a line comment.
2427  pub fn is_line_comment(&self) -> bool {
2428    self.0.borrow().value.starts_with("//")
2429  }
2430
2431  /// Sets the raw value of the comment.
2432  ///
2433  /// This SHOULD include `//` or be surrounded in `/* ... */` or
2434  /// else you'll be inserting a syntax error.
2435  pub fn set_raw_value(&self, value: String) {
2436    self.0.borrow_mut().value = value;
2437  }
2438
2439  /// Raw value of the comment including `//` or `/* ... */`.
2440  pub fn raw_value(&self) -> String {
2441    self.0.borrow().value.clone()
2442  }
2443
2444  /// Removes the node from the JSON.
2445  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(); // move past the \n
2619      } 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/// A sort of an object's properties, waiting to be told how to order them.
2653///
2654/// Built by [`CstObject::sort_properties`].
2655#[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  /// Leaves a comment that heads a group of properties where it was written.
2663  ///
2664  /// A comment with a blank line above it reads as a heading for the properties beneath it rather
2665  /// than as a description of the first of them, so it stays put and the properties sort past it.
2666  /// Without this, every comment above a property travels with that property, which carries a
2667  /// heading off to wherever its first property happens to land.
2668  ///
2669  /// The blank line itself stays too, as does a blank line with no comment under it.
2670  ///
2671  /// # Example
2672  ///
2673  /// ```
2674  /// use jsonc_parser::ParseOptions;
2675  /// use jsonc_parser::cst::CstRootNode;
2676  ///
2677  /// let json_text = r#"{
2678  ///   "prop": 1,
2679  ///
2680  ///   // section
2681  ///   "prop2": 2,
2682  ///   "prop1": 1
2683  /// }"#;
2684  ///
2685  /// let root = CstRootNode::parse(json_text, &ParseOptions::default()).unwrap();
2686  /// let root_obj = root.object_value().unwrap();
2687  /// root_obj
2688  ///   .sort_properties()
2689  ///   .pin_comment_headers()
2690  ///   .by_key(|prop| prop.decoded_name());
2691  ///
2692  /// assert_eq!(root.to_string(), r#"{
2693  ///   "prop": 1,
2694  ///
2695  ///   // section
2696  ///   "prop1": 1,
2697  ///   "prop2": 2
2698  /// }"#);
2699  /// ```
2700  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  /// Decides for each property how much of what was written above it is a heading for what
2706  /// follows rather than part of the property.
2707  ///
2708  /// `rule` is handed the property and the comments written above it, in the order they appear,
2709  /// and returns how many of them, counting from the top, stay where they were written. The rest
2710  /// travel with the property, as does the blank line under whatever stayed.
2711  ///
2712  /// Returning `comments.len()` pins everything above the property and `0` pins nothing, so
2713  /// [`PropertySort::pin_comment_headers`] is `if prop.has_blank_line_before() { comments.len() }
2714  /// else { 0 }`. A count in between splits a block that is partly a heading and partly a note
2715  /// about the property itself.
2716  ///
2717  /// The rule is only consulted where a header could be written, which is a property on a line of
2718  /// its own; it is not called for an object written on one line.
2719  ///
2720  /// The rule must not change the object's children. Doing so leaves the sort with nothing safe to
2721  /// write back, so it gives up and leaves the object as the rule left it.
2722  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  /// Sorts each run of properties between blank lines on its own, so that no property crosses one.
2731  ///
2732  /// A blank line, and whatever was written under it, is the boundary between two groups, and a
2733  /// boundary stays where it is. A rule set by [`PropertySort::pin_comment_headers_with`] still
2734  /// decides what travels with the properties inside each group.
2735  ///
2736  /// # Example
2737  ///
2738  /// ```
2739  /// use jsonc_parser::ParseOptions;
2740  /// use jsonc_parser::cst::CstRootNode;
2741  ///
2742  /// let json_text = r#"{
2743  ///   "m": 1,
2744  ///
2745  ///   // section
2746  ///   "z": 2,
2747  ///   "a": 3
2748  /// }"#;
2749  ///
2750  /// let root = CstRootNode::parse(json_text, &ParseOptions::default()).unwrap();
2751  /// let root_obj = root.object_value().unwrap();
2752  /// root_obj
2753  ///   .sort_properties()
2754  ///   .within_groups()
2755  ///   .by_key(|prop| prop.decoded_name());
2756  ///
2757  /// // "m" stays above the blank line and only "z" and "a" trade places
2758  /// assert_eq!(root.to_string(), r#"{
2759  ///   "m": 1,
2760  ///
2761  ///   // section
2762  ///   "a": 3,
2763  ///   "z": 2
2764  /// }"#);
2765  /// ```
2766  pub fn within_groups(mut self) -> Self {
2767    self.options.within_groups = true;
2768    self
2769  }
2770
2771  /// Sorts the properties with the given comparator.
2772  ///
2773  /// The sort is stable, so properties that compare equal keep the order they were written in. The
2774  /// comparator must describe a total order, as the sort may panic otherwise, and it must not
2775  /// change the object's children; see [`PropertySort::pin_comment_headers_with`].
2776  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          // an object holds properties, so this only happens if the tree has been manipulated into
2783          // holding something else, in which case leaving the order alone is the safe answer
2784          _ => Ordering::Equal,
2785        }
2786      })
2787    });
2788  }
2789
2790  /// Sorts the properties by a key, which is worked out once per property.
2791  ///
2792  /// A child that isn't a property, which is only possible if the tree has been manipulated into
2793  /// holding something else, has no key and sorts above every property. Behaves like
2794  /// [`PropertySort::by`] in every other respect.
2795  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/// A sort of an array's elements, waiting to be told how to order them.
2804///
2805/// Built by [`CstArray::sort_elements`].
2806#[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  /// Leaves a comment that heads a group of elements where it was written.
2814  ///
2815  /// Behaves like [`PropertySort::pin_comment_headers`].
2816  pub fn pin_comment_headers(self) -> Self {
2817    self.pin_comment_headers_with(blank_line_header_rule)
2818  }
2819
2820  /// Decides for each element how much of what was written above it is a heading for what follows
2821  /// rather than part of the element.
2822  ///
2823  /// Behaves like [`PropertySort::pin_comment_headers_with`].
2824  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  /// Sorts each run of elements between blank lines on its own, so that no element crosses one.
2830  ///
2831  /// Behaves like [`PropertySort::within_groups`].
2832  pub fn within_groups(mut self) -> Self {
2833    self.options.within_groups = true;
2834    self
2835  }
2836
2837  /// Sorts the elements with the given comparator.
2838  ///
2839  /// Behaves like [`PropertySort::by`].
2840  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  /// Sorts the elements by a key, which is worked out once per element.
2848  ///
2849  /// Behaves like [`PropertySort::by_key`].
2850  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
2858/// Decides how many of the comments written above an element stay where they are when it moves.
2859type HeaderRule<'a> = Box<dyn FnMut(&CstNode, &[CstComment]) -> usize + 'a>;
2860
2861/// What a sort does with the trivia it moves past, set through [`PropertySort`] and [`ElementSort`].
2862#[derive(Default)]
2863struct SortOptions<'a> {
2864  header_rule: Option<HeaderRule<'a>>,
2865  within_groups: bool,
2866}
2867
2868impl SortOptions<'_> {
2869  /// How many of `comments` stay where they were written rather than travelling with `element`.
2870  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
2878/// The rule [`PropertySort::pin_comment_headers`] and [`ElementSort::pin_comment_headers`] use: a
2879/// comment with a blank line above it heads what follows rather than describing the first of them.
2880fn 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
2888/// What sits between two elements and stays where it is, because it positions whatever comes next
2889/// rather than belonging to either element.
2890///
2891/// Both parts are stretches of the container's own children, which moving elements around only
2892/// ever copies, so they're held as ranges rather than as lists of their own.
2893struct Separator {
2894  /// The line break that ended the previous element line, whatever of the trivia under it was
2895  /// written as a header for what follows, and on a single line the space between two elements.
2896  before: Range<usize>,
2897  /// The indentation directly in front of the element.
2898  indent: Range<usize>,
2899}
2900
2901/// An element of a comma separated container along with the trivia that travels with it.
2902///
2903/// Held as ranges for the same reason as [`Separator`].
2904struct SortableGroup {
2905  /// Where the element was written, so that a sort changing nothing can leave the tree alone.
2906  index: usize,
2907  /// Whether a blank line separates this element from the one before it, which is what divides a
2908  /// container into groups.
2909  starts_group: bool,
2910  /// What was written before the element and belongs to it: its own comments and indentation.
2911  leading: Range<usize>,
2912  element: CstNode,
2913  /// Whatever separates the element from its comma, the comma, and any comment written after that
2914  /// on the same line.
2915  trailing: Range<usize>,
2916  /// Where the element's comma sits, if it was written with one.
2917  comma: Option<usize>,
2918}
2919
2920/// Reorders the elements of an object or array, moving what was written with each element along
2921/// with it and leaving the separators between them where they are.
2922///
2923/// `sort` is handed the elements of one group at a time, in the order they were written, and is
2924/// expected to sort them stably. Without [`SortOptions::within_groups`] there is a single group
2925/// holding everything.
2926fn 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  // the surrounding tokens are what the elements sit between, so there's nothing to sort without them
2933  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  // Split the region into the groups that move and the separators that stay put. Each group is
2939  // preceded by exactly one separator, so the two line up.
2940  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(&region[index]) {
2946      index += 1;
2947    }
2948    if index == region.len() {
2949      // what follows the last element belongs to no element and stays where it is
2950      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, &region[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  // whether the author ended the container with a comma, which the new last element takes over
2976  let ends_with_comma = groups[groups.len() - 1].comma.is_some();
2977  if options.within_groups {
2978    // a blank line divides the container, and a divider is not something an element sorts past
2979    for group in groups.chunk_by_mut(|_, next| !next.starts_group) {
2980      sort(group);
2981    }
2982  } else {
2983    sort(&mut groups);
2984  }
2985  // Changing the container while the sort runs would leave the ranges worked out above pointing
2986  // at children that have moved, so writing them back would undo the change and detach whatever
2987  // the caller is holding. A child that was removed or replaced no longer answers to its slot.
2988  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  // a blank line here reads as a gap under the open token rather than as something written with
3005  // the element that follows, so it doesn't travel with whatever sorted to the top
3006  let first_leading = &mut groups[0].leading;
3007  first_leading.start += leading_blank_line_len(&region[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(&region[separator.before]);
3014    new_children.extend_from_slice(&region[group.leading]);
3015    new_children.extend_from_slice(&region[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(&region[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
3030/// Whether the node is something an object or array holds rather than the punctuation and trivia
3031/// written around it.
3032fn is_sortable_element(node: &CstNode) -> bool {
3033  !node.is_trivia() && !node.is_token()
3034}
3035
3036/// How much of the start of a run is blank lines, counting a line of nothing but whitespace as one.
3037///
3038/// Stops at the first line holding anything, so the indentation in front of a comment is left for
3039/// the comment rather than counted as a blank line of its own.
3040fn 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
3058/// Whether a run of trivia leaves a line empty, which is what marks a group boundary and what
3059/// tells a comment heading a group from one describing the element beneath it.
3060///
3061/// Reads the same either way round, so the run may be walked forwards or backwards.
3062fn 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
3077/// Splits what was written between two elements into the separator, which stays where it is, and
3078/// the trivia belonging to the element that follows.
3079///
3080/// The separator is the line break that ended the previous element's line together with the
3081/// indentation under it, or on a single line the whitespace between the two elements. Both
3082/// position whatever comes next, so they belong to the slot rather than to either element. What
3083/// sits between them came with the element that follows and travels with it, except for however
3084/// much of it the sort's header rule says was written as a header for what comes next.
3085fn 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 = &region[run.clone()];
3093  let Some(newline) = nodes.iter().position(|n| n.is_newline()) else {
3094    // nothing indents anything on a single line, so all that is here is the space between the two
3095    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    // the blank line and whatever was written under it are the boundary between two groups, and a
3113    // boundary is not something an element sorts past, so none of it travels
3114    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
3128/// How much of what was written above an element was written as a header for it rather than as
3129/// part of it, and so stays where it is when the element moves.
3130///
3131/// The header runs up to the line the first comment that isn't part of it begins on, so that the
3132/// blank line under a header stays with the header where it reads.
3133fn header_len(leading: &[CstNode], element: &CstNode, options: &mut SortOptions<'_>) -> usize {
3134  // the common sort sets no rule at all, and then nothing above an element ever stays
3135  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  // A blank line is how the container was laid out rather than something written with the element,
3150  // so it stays put whenever the caller is deciding what travels, even when no comment does.
3151  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  // back up to the start of that comment's line, so that a header never ends part way along one
3163  // and leaves what follows glued to it
3164  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
3171/// The end of the run after an element that was written with it: whatever separates the element
3172/// from its comma, the comma itself, and any comment written after that on the same line.
3173///
3174/// The comma comes along wherever the author put it, including on a later line, so that it can
3175/// never be mistaken for something belonging to the element that follows.
3176fn 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  // a comment after that was written with the element too, but only when nothing else shares its line
3187  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
3199/// Whether the rest of the line holds nothing but whitespace and comments, which is what decides
3200/// whether a comment there was written with what precedes it or with what follows.
3201fn 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
3209/// Writes out what followed the element, with its comma added or dropped to suit its new position.
3210fn 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      // the space that offset the comma has nothing left to offset
3220      let end = if comma > trailing.start && region[comma - 1].is_whitespace() {
3221        comma - 1
3222      } else {
3223        comma
3224      };
3225      out.extend_from_slice(&region[trailing.start..end]);
3226      out.extend_from_slice(&region[comma + 1..trailing.end]);
3227    }
3228    None if wants_comma => {
3229      out.push(CstToken::new(',').into());
3230      out.extend_from_slice(&region[trailing]);
3231    }
3232    _ => out.extend_from_slice(&region[trailing]),
3233  }
3234}
3235
3236/// Puts back the line break a line comment needs in order to end where it did.
3237///
3238/// A line comment runs to the end of its line, so moving one can leave it in front of what used to
3239/// come earlier, commenting out the next element or the closing token.
3240fn 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            // keep going
3271          }
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  // remove up to the trailing comma
3302  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  // remove up to the newline
3319  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 // default to false
3429}
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    // handle last element
3596    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    // handle children
3608    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    // try to find the first newline
3624    for child in children.by_ref() {
3625      if child.is_whitespace() {
3626        // keep searching
3627      } else if child.is_newline() {
3628        break; // found
3629      } else {
3630        return; // stop, no leading blank lines
3631      }
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; // should never happen because this should only be called for array and object
3654  }
3655
3656  // remove blank lines from the front and back
3657  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  // insert a newline at the start of every part
3677  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      // insert a newline
3686      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      // current node
3693      index += 1;
3694
3695      // consume the next tokens until the next comma
3696      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  // insert the last newline
3716  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  // try to discover the single indent level by looking at the root node's children
3787  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  // assume two space indentation
3799  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  // pre-emptively store the next ancestor in case
3808  // the currently returned sibling is removed
3809  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  // pre-emptively store the next sibling in case
3832  // the currently returned sibling is removed
3833  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  // pre-emptively store the previous sibling in case
3856  // the currently returned sibling is removed
3857  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      // this is fine... people doing stupid things
4055      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    // inserting before first prop
4088    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    // inserting before first prop with leading comment
4102    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    // inserting after last prop with trailing comment
4118    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    // maintain trailing comma
4136    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    // insert when is on a single line
4150    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    // insert when is on a single line with trailing comma
4162    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    // only comment
4298    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    // blank line
4315    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    // regression test for https://github.com/dprint/jsonc-parser/issues/78
4334    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    // existing
4436    {
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    // empty file
4442    {
4443      let cst = build_cst(r#""#);
4444      cst.object_value_or_create().unwrap();
4445      assert_eq!(cst.to_string(), "{}\n");
4446    }
4447    // comment
4448    {
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    // comment and newline
4454    {
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    // empty
4464    {
4465      let cst = build_cst(r#"[]"#);
4466      cst.value().unwrap().as_array().unwrap().ensure_multiline();
4467      assert_eq!(cst.to_string(), "[\n]");
4468    }
4469    // whitespace only
4470    {
4471      let cst = build_cst(r#"[   ]"#);
4472      cst.value().unwrap().as_array().unwrap().ensure_multiline();
4473      assert_eq!(cst.to_string(), "[\n]");
4474    }
4475    // comments only
4476    {
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    // elements
4482    {
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    // elements deep
4495    {
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    // \r\n newlines
4535    {
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    // empty
4545    {
4546      let cst = build_cst(r#"{}"#);
4547      cst.value().unwrap().as_object().unwrap().ensure_multiline();
4548      assert_eq!(cst.to_string(), "{\n}");
4549    }
4550    // whitespace only
4551    {
4552      let cst = build_cst(r#"{   }"#);
4553      cst.value().unwrap().as_object().unwrap().ensure_multiline();
4554      assert_eq!(cst.to_string(), "{\n}");
4555    }
4556    // comments only
4557    {
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    // elements
4563    {
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    // elements deep
4576    {
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    // empty object
4628    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    // single-line object
4646    run_test(r#"{"a": 1}"#, TrailingCommaMode::Never, r#"{"a": 1}"#);
4647    run_test(r#"{"a": 1}"#, TrailingCommaMode::IfMultiline, r#"{"a": 1}"#);
4648    // multiline object
4649    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    // but is strict when strict
4803    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      // the result is still the same json, and sorting it again changes nothing
4823      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    // a single line object keeps the spacing that separates its properties
4831    run_test("{ \"b\": 2, \"a\": 1 }", "{ \"a\": 1, \"b\": 2 }");
4832    run_test("{\"b\":2,\"a\":1}", "{\"a\":1,\"b\":2}");
4833    // the trailing comma the object was written with belongs to whatever ends up last
4834    run_test("{\n  \"b\": 2,\n  \"a\": 1,\n}", "{\n  \"a\": 1,\n  \"b\": 2,\n}");
4835    // nothing to do
4836    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    // values are moved as they were written, not reformatted
4840    run_test(
4841      "{\n  \"b\": { \"z\": 1 },\n  \"a\": [3,   1]\n}",
4842      "{\n  \"a\": [3,   1],\n  \"b\": { \"z\": 1 }\n}",
4843    );
4844    // word (unquoted) names sort by the same name the parser reads
4845    run_test("{\n  b: 2,\n  a: 1\n}", "{\n  a: 1,\n  b: 2\n}");
4846    // an escape is decoded to find the name, and left as written when the property moves
4847    run_test(
4848      "{\n  \"b\": 2,\n  \"\\u0061\": 1\n}",
4849      "{\n  \"\\u0061\": 1,\n  \"b\": 2\n}",
4850    );
4851    // properties sharing a name keep the order they were written in
4852    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    // a comma is added where the new order needs one, even if the author left it out
4857    run_test("{\n  \"b\": 2\n  \"a\": 1\n}", "{\n  \"a\": 1,\n  \"b\": 2\n}");
4858    // a comma written at the start of a line belongs to the property above it
4859    run_test("{\n  \"b\": 2\n  , \"a\": 1\n}", "{\n  \"a\": 1, \"b\": 2\n\n}");
4860    // the space that offset a removed comma goes with it
4861    run_test("{ \"b\": 2 , \"a\": 1 }", "{ \"a\": 1, \"b\": 2 }");
4862    // properties keep their indentation when they change lines
4863    run_test("{\n  \"b\": 2, \"a\": 1\n}", "{\n  \"a\": 1, \"b\": 2\n}");
4864    // carriage returns survive the move
4865    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    // a comment above a property was written with it and travels with it
4886    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    // so does a comment written after it on the same line, which loses the comma it sat behind
4891    run_test(
4892      "{\n  \"b\": 2, // about b\n  \"a\": 1\n}",
4893      "{\n  \"a\": 1,\n  \"b\": 2 // about b\n}",
4894    );
4895    // and gains one when it moves off the end
4896    run_test(
4897      "{\n  \"b\": 2,\n  \"a\": 1 // about a\n}",
4898      "{\n  \"a\": 1, // about a\n  \"b\": 2\n}",
4899    );
4900    // a comment on the open brace line belongs to no property and stays where it is
4901    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    // as does one written under the last property
4906    run_test(
4907      "{\n  \"b\": 2,\n  \"a\": 1\n  // dangling\n}",
4908      "{\n  \"a\": 1,\n  \"b\": 2\n  // dangling\n}",
4909    );
4910    // a comment between two properties on one line was written above the second of them
4911    run_test(
4912      "{ \"b\": 2, /* between */ \"a\": 1 }",
4913      "{ /* between */ \"a\": 1, \"b\": 2 }",
4914    );
4915    // a block comment above a property travels like a line comment does
4916    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    // a blank line above a property travels with it
4921    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    // but one that ends up under the open brace reads as a gap rather than as part of a property
4926    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    // a comment under a blank line heads what follows, so the properties sort past it
4944    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    // but a comment written flush against its property still describes it and travels with it
4949    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    // the two can sit in the same object
4954    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    // a blank line with no comment under it stays where it is as well
4959    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    // every heading stays over its own group
4964    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    // a block comment heads a group the same way
4969    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    // an object with no blank lines sorts exactly as it does without the option
4974    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    // a blank line divides the object and nothing sorts across it
4992    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    // every group sorts on its own
4997    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    // the trailing comma still belongs to whatever ends the object
5002    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    // a group of one has nothing to sort
5007    run_test("{\n  \"b\": 2,\n\n  \"a\": 1\n}", "{\n  \"b\": 2,\n\n  \"a\": 1\n}");
5008    // an object with no blank line is one group
5009    run_test("{\n  \"b\": 2,\n  \"a\": 1\n}", "{\n  \"a\": 1,\n  \"b\": 2\n}");
5010    // a comment directly under the blank line is part of the boundary and stays with it
5011    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    // but one written further down the group belongs to its property and travels with it
5016    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      // only the first comment above a property heads its group; the rest are its own
5029      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    // the first comment heads the group and the second describes the property under it
5038    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    // a blank line between the header and the note keeps the blank with the header
5043    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      // removing a property leaves the sort with nothing safe to write back
5059      if prop.decoded_name().as_deref() == Some("b") {
5060        prop.clone().remove();
5061      }
5062      prop.decoded_name()
5063    });
5064
5065    // the removal stands, but nothing was reordered on top of it
5066    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      // a replacement leaves the child count alone, so only checking that would miss it
5081      if name.as_deref() == Some("b") {
5082        prop.clone().replace_with("zzz", json!(9));
5083      }
5084      name
5085    });
5086
5087    // the replacement stands and nothing was reordered on top of it
5088    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      // without the line break the comment would swallow whatever follows it
5100      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    // a line comment that would swallow the property after it gains a line break
5107    run_test(
5108      "{\"b\": 2, \"a\": 1 // about a\n}",
5109      "{\"a\": 1, // about a\n \"b\": 2\n}",
5110    );
5111    // and one that would swallow the close brace gains one too
5112    run_test(
5113      "{ \"b\": 2, // about b\n  \"a\": 1 }",
5114      "{ \"a\": 1,\n  \"b\": 2 // about b\n }",
5115    );
5116    // a block comment needs no such help
5117    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    // the handle taken before the sort still points at the same property in its new place
5131    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    // and the property that moved can still be edited afterwards
5142    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    // the trailing comma the array was written with belongs to whatever ends up last
5163    run_test("[\n  3,\n  1,\n]", "[\n  1,\n  3,\n]");
5164    // a comment above an element travels with it
5165    run_test("[\n  // about 3\n  3,\n  1\n]", "[\n  1,\n  // about 3\n  3\n]");
5166    // as does one written after it on the same line
5167    run_test("[\n  3, // about 3\n  1\n]", "[\n  1,\n  3 // about 3\n]");
5168    // a line comment that would swallow the close bracket gains a line break
5169    run_test("[2, // about 2\n1]", "[1,\n2 // about 2\n]");
5170    // a blank line above an element travels with it
5171    run_test("[\n  3,\n\n  1\n]", "[\n  1,\n  3\n]");
5172    // nothing to do
5173    run_test("[]", "[]");
5174    run_test("[1]", "[1]");
5175    // an array sorts before an object by text, so these are already in order
5176    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    // String containing a backslash: /.github/workflows/lint\.yaml$/
5421    prop.set_value(json!("/.github/workflows/lint\\.yaml$/"));
5422    assert_eq!(cst.to_string(), r#"{"key": "/.github/workflows/lint\\.yaml$/"}"#,);
5423    // Verify decoded value roundtrips correctly
5424    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    // Verify decoded values roundtrip correctly
5455    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    // a lone \r ends a line comment, so edits should behave the same as with \n
5547    #[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}