Skip to main content

jsonc_parser/cst/
mod.rs

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