1use pochoir_common::Spanned;
2use pochoir_template_engine::{Escaping, TemplateBlock};
3use selectors::{
4 context::{MatchingForInvalidation, NeedsSelectorFlags, SelectorCaches},
5 matching,
6 parser::SelectorList,
7};
8use std::{borrow::Cow, fmt};
9
10use super::{build_selector_list, selection::InnerSelector, Tree, TreeNode, TreeRefId};
11use crate::{Error, Node, OwnedTree, ParsedNode, Result};
12
13#[derive(Clone, Copy)]
15pub struct TreeRef<'a, 'b> {
16 pub id: TreeRefId,
18
19 pub tree: &'b Tree<'a>,
21}
22
23impl<'a, 'b> TreeRef<'a, 'b> {
24 #[allow(clippy::panic)]
25 fn inner(&self) -> &TreeNode<'a> {
26 self.tree.nodes.get(&self.id).unwrap_or_else(|| {
27 panic!(
28 "failed to find the current node (id {:?}) in the tree",
29 self.id
30 )
31 })
32 }
33
34 pub fn id(&self) -> TreeRefId {
35 self.id
36 }
37
38 pub fn spanned_data(&self) -> &ParsedNode<'a> {
45 &self.inner().data
46 }
47
48 pub fn data(&self) -> &Node<'a> {
54 &self.inner().data
55 }
56
57 #[must_use]
59 pub fn parent(&self) -> Self {
60 Self {
61 id: self.inner().parent,
62 tree: self.tree,
63 }
64 }
65
66 pub fn closest(&self, selector: &str) -> Option<Self> {
73 let mut tree_ref = *self;
74 let selector_list = build_selector_list(selector).ok()?;
75
76 loop {
77 if tree_ref.is_matching(&selector_list) {
78 return Some(tree_ref);
79 } else if tree_ref.id == TreeRefId::Root {
80 return None;
81 }
82
83 tree_ref = tree_ref.parent();
84 }
85 }
86
87 pub fn prev_sibling(&self) -> Option<Self> {
89 let parent = self.parent();
90 let mut children = parent.children().peekable();
91
92 let mut id = None;
93 while let Some(c) = children.next() {
94 if children.peek().is_some_and(|c| c.id == self.id) {
95 id = Some(c.id);
96 break;
97 }
98 }
99
100 id.map(|id| Self {
101 id,
102 tree: self.tree,
103 })
104 }
105
106 pub fn next_sibling(&self) -> Option<Self> {
108 let parent = self.parent();
109 let mut children = parent.children().peekable();
110
111 let mut id = None;
112 while let Some(c) = children.next() {
113 if c.id == self.id {
114 id = children.peek().map(|c| c.id);
115 break;
116 }
117 }
118
119 id.map(|id| Self {
120 id,
121 tree: self.tree,
122 })
123 }
124
125 pub fn children<'c>(&'c self) -> impl Iterator<Item = TreeRef<'a, 'b>> + 'c {
127 self.inner().children.iter().map(|id| self.tree.get(*id))
128 }
129
130 pub fn children_id(&self) -> Vec<TreeRefId> {
132 self.inner().children.clone()
133 }
134
135 pub fn select<'c>(
147 &self,
148 selector: &'c str,
149 ) -> std::result::Result<Option<TreeRef<'_, '_>>, crate::error::SelectorParseError<'c>> {
150 let selector_list = build_selector_list(selector)?;
151 Ok(self
152 .traverse_depth()
153 .find(|tree_ref| tree_ref.is_matching(&selector_list)))
154 }
155
156 pub fn select_all(&self, selector: &str) -> Vec<TreeRef<'_, '_>> {
162 if let Ok(selector_list) = build_selector_list(selector) {
163 self.traverse_depth()
164 .filter(|tree_ref| tree_ref.is_matching(&selector_list))
165 .collect()
166 } else {
167 vec![]
168 }
169 }
170
171 pub fn name(&self) -> Result<Cow<'a, str>> {
179 if let Node::Element(ref name, _) = self.data() {
180 Ok(name.clone())
181 } else {
182 Err(Spanned::new(Error::BadNodeType {
183 expected: "Element",
184 found: self.data().node_type(),
185 }))
186 }
187 }
188
189 pub fn text(&self) -> Cow<'a, str> {
202 match self.data() {
203 Node::Element(_, _) => {
204 let children = self.children();
205 Cow::Owned(children.into_iter().map(|child| child.text()).collect())
206 }
207 Node::TemplateBlock(block) => Cow::Owned(match block {
208 TemplateBlock::RawText(t) => t.to_string(),
209 TemplateBlock::Expr(t, is_escaped) => {
210 if *is_escaped {
211 format!("{{{{{t}}}}}")
212 } else {
213 format!("{{!{t}!}}")
214 }
215 }
216 TemplateBlock::Stmt(t) => format!("{{%{t}%}}"),
217 }),
218 _ => Cow::Borrowed(""),
219 }
220 }
221
222 pub fn attr(&self, name: &str) -> Result<Option<String>> {
239 if let Node::Element(_, ref attrs) = self.data() {
240 Ok(attrs.get(Cow::Borrowed(name)).map(|a| {
241 a.iter()
242 .map(|b| match &**b {
243 TemplateBlock::RawText(t) => t.to_string(),
244 TemplateBlock::Expr(t, is_escaped) => {
245 if *is_escaped {
246 format!("{{{{{t}}}}}")
247 } else {
248 format!("{{!{t}!}}")
249 }
250 }
251 TemplateBlock::Stmt(t) => format!("{{%{t}%}}"),
252 })
253 .collect::<String>()
254 }))
255 } else {
256 Err(Spanned::new(Error::BadNodeType {
257 expected: "Element",
258 found: self.data().node_type(),
259 }))
260 }
261 }
262
263 pub fn attr_spanned(&self, name: &str) -> Result<Option<Vec<Spanned<TemplateBlock<'_>>>>> {
273 if let Node::Element(_, ref attrs) = self.data() {
274 Ok(attrs.get(Cow::Borrowed(name)).cloned())
275 } else {
276 Err(Spanned::new(Error::BadNodeType {
277 expected: "Element",
278 found: self.data().node_type(),
279 }))
280 }
281 }
282
283 pub fn attrs(&self) -> Result<impl Iterator<Item = (&Cow<'_, str>, String)>> {
296 if let Node::Element(_, ref attrs) = self.data() {
297 Ok(attrs.iter().map(|(k, v)| {
298 (
299 &**k,
300 v.iter()
301 .map(|b| match &**b {
302 TemplateBlock::RawText(t) => t.to_string(),
303 TemplateBlock::Expr(t, is_escaped) => {
304 if *is_escaped {
305 format!("{{{{{t}}}}}")
306 } else {
307 format!("{{!{t}!}}")
308 }
309 }
310 TemplateBlock::Stmt(t) => format!("{{%{t}%}}"),
311 })
312 .collect::<String>(),
313 )
314 }))
315 } else {
316 Err(Spanned::new(Error::BadNodeType {
317 expected: "Element",
318 found: self.data().node_type(),
319 }))
320 }
321 }
322
323 pub fn attrs_spanned(&self) -> Result<impl Iterator<Item = &crate::Attr<'_>>> {
331 if let Node::Element(_, ref attrs) = self.data() {
332 Ok(attrs.iter())
333 } else {
334 Err(Spanned::new(Error::BadNodeType {
335 expected: "Element",
336 found: self.data().node_type(),
337 }))
338 }
339 }
340
341 pub fn sub_tree(&self) -> Tree<'a> {
342 let mut tree = Tree::new(self.tree.file_path());
343
344 tree.next_id = self.tree.next_id;
346
347 for tree_ref in self.traverse_depth() {
348 let parent_id = if tree_ref.parent().id() == self.id() {
349 TreeRefId::Root
350 } else {
351 tree_ref.parent().id()
352 };
353
354 tree.insert_with_id(
355 tree_ref.id(),
356 parent_id,
357 tree_ref.children_id(),
358 tree_ref.spanned_data().clone(),
359 );
360
361 if parent_id == TreeRefId::Root {
362 tree.get_mut(TreeRefId::Root)
363 .inner_mut()
364 .children
365 .push(tree_ref.id());
366 }
367 }
368 tree
369 }
370
371 pub fn traverse_breadth(&self) -> impl Iterator<Item = TreeRef<'a, '_>> {
372 let parent = self.tree.get(self.id);
373
374 super::traverse::TraverseBreadthIter {
375 children: parent.children().collect(),
376 index: 0,
377 }
378 }
379
380 pub fn traverse_depth(&self) -> impl Iterator<Item = TreeRef<'a, '_>> {
381 let mut queue: Vec<TreeRef> = self.tree.get(self.id).children().collect();
382 queue.reverse();
383
384 super::traverse::TraverseDepthIter { queue }
385 }
386
387 pub fn is_matching(&self, selector_list: &SelectorList<InnerSelector>) -> bool {
388 let mut nth_index_cache = SelectorCaches::default();
389 let mut ctx = matching::MatchingContext::new(
390 matching::MatchingMode::Normal,
391 None,
392 &mut nth_index_cache,
393 matching::QuirksMode::NoQuirks,
394 NeedsSelectorFlags::No,
395 MatchingForInvalidation::No,
396 );
397
398 matching::matches_selector_list(selector_list, self, &mut ctx)
399 }
400}
401
402impl PartialEq for TreeRef<'_, '_> {
403 fn eq(&self, other: &Self) -> bool {
404 self.id == other.id
405 }
406}
407
408impl fmt::Debug for TreeRef<'_, '_> {
409 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
410 f.debug_struct("TreeRef")
411 .field("id", &self.id)
412 .field("__inner_node", &self.data())
413 .finish()
414 }
415}
416
417pub struct TreeRefMut<'a, 'b> {
419 pub id: TreeRefId,
421
422 pub tree: &'b mut Tree<'a>,
424}
425
426impl<'a, 'b> TreeRefMut<'a, 'b> {
427 #[allow(clippy::panic)]
428 fn inner(&self) -> &TreeNode<'a> {
429 self.tree.nodes.get(&self.id).unwrap_or_else(|| {
430 panic!(
431 "failed to find the current node (id {:?}) in the tree (mutable)",
432 self.id
433 )
434 })
435 }
436
437 #[allow(clippy::panic)]
438 fn inner_mut(&mut self) -> &mut TreeNode<'a> {
439 self.tree.nodes.get_mut(&self.id).unwrap_or_else(|| {
440 panic!(
441 "failed to find the current node (id {:?}) in the tree (mutable)",
442 self.id
443 )
444 })
445 }
446
447 pub fn id(&self) -> TreeRefId {
448 self.id
449 }
450
451 pub fn as_ref(&self) -> TreeRef<'a, '_> {
452 TreeRef {
453 id: self.id,
454 tree: self.tree,
455 }
456 }
457
458 pub fn data(&mut self) -> &mut Node<'a> {
464 &mut self.inner_mut().data
465 }
466
467 pub fn spanned_data(&mut self) -> &mut ParsedNode<'a> {
474 &mut self.inner_mut().data
475 }
476
477 pub fn parent(&mut self) -> TreeRefMut<'a, '_> {
479 TreeRefMut {
480 id: self.inner().parent,
481 tree: self.tree,
482 }
483 }
484
485 pub fn prev_sibling(&'b mut self) -> Option<Self> {
487 let parent = self.as_ref().parent();
488 let mut children = parent.children().peekable();
489
490 let mut id = None;
491 while let Some(c) = children.next() {
492 if children.peek().is_some_and(|c| c.id == self.id) {
493 id = Some(c.id);
494 break;
495 }
496 }
497
498 drop(children);
499 id.map(|id| Self {
500 id,
501 tree: self.tree,
502 })
503 }
504
505 pub fn next_sibling(&'b mut self) -> Option<Self> {
507 let parent = self.as_ref().parent();
508 let mut children = parent.children().peekable();
509
510 let mut id = None;
511 while let Some(c) = children.next() {
512 if c.id == self.id {
513 id = children.peek().map(|c| c.id);
514 break;
515 }
516 }
517
518 drop(children);
519 id.map(|id| Self {
520 id,
521 tree: self.tree,
522 })
523 }
524
525 pub fn set_text<T: Into<Cow<'a, str>>>(&mut self, new_text: T, escaping: Escaping) {
537 match self.as_ref().data() {
538 Node::Element(..) => {
539 let children = self.as_ref().children_id();
541
542 for child in children {
543 self.tree.get_mut(child).remove();
544 }
545
546 let new_text_escaped = escaping.escape(new_text.into());
548
549 self.tree.insert(
551 self.id,
552 Spanned::new(Node::TemplateBlock(TemplateBlock::RawText(
553 new_text_escaped,
554 ))),
555 );
556 }
557 Node::TemplateBlock(_) => {
558 if let Node::TemplateBlock(TemplateBlock::RawText(ref mut t)) = self.data() {
559 *t = new_text.into();
560 }
561 }
562 _ => (),
563 }
564 }
565
566 pub fn set_attr<A: Into<Cow<'a, str>>, B: Into<Cow<'a, str>>>(
575 &mut self,
576 key: A,
577 val: B,
578 escaping: Escaping,
579 ) {
580 if let Node::Element(_, ref mut attrs) = self.tree.get_mut(self.id).data() {
581 attrs.insert(
582 key.into(),
583 vec![Spanned::new(TemplateBlock::RawText(
584 escaping.escape(val.into()),
585 ))],
586 );
587 }
588 }
589
590 pub fn remove_attr<'c, A: Into<Cow<'c, str>>>(&mut self, key: A) {
594 if let Node::Element(_, ref mut attrs) = self.tree.get_mut(self.id).data() {
595 attrs.remove(key.into());
596 }
597 }
598
599 pub fn replace_node(self, tree: &Tree<'a>) {
608 let current_index = self
610 .as_ref()
611 .parent()
612 .inner()
613 .children
614 .iter()
615 .position(|id| *id == self.id)
616 .expect("failed to find the node in its parent children");
617
618 let offset = self.tree.next_id();
619
620 let parent_id = self.as_ref().parent().id();
622
623 let mut inserted_nodes = 0;
624 let mut max_offset_node = offset;
625
626 for tree_ref in tree.traverse_depth() {
627 let is_root_node = tree_ref.parent().id() == TreeRefId::Root;
628 let children = tree_ref.children_id().iter().map(|c| *c + offset).collect();
629
630 self.tree.insert_with_id(
631 tree_ref.id + offset,
632 if is_root_node {
633 parent_id
634 } else {
635 tree_ref.parent().id() + offset
636 },
637 children,
638 tree_ref.spanned_data().clone(),
639 );
640
641 if tree_ref.id + offset > max_offset_node {
642 max_offset_node = tree_ref.id + offset;
643 }
644
645 if is_root_node {
646 self.tree
647 .get_mut(parent_id)
648 .inner_mut()
649 .children
650 .insert(current_index + inserted_nodes, tree_ref.id() + offset);
651
652 inserted_nodes += 1;
653 }
654 }
655
656 self.tree.next_id = max_offset_node + 1;
657
658 self.remove();
659 }
660
661 pub fn prepend_children(&mut self, tree: &Tree<'a>) {
663 let offset = self.tree.next_id();
664 let mut inserted_nodes = 0;
665 let mut max_offset_node = offset;
666
667 for tree_ref in tree.traverse_depth() {
668 let is_root_node = tree_ref.parent().id() == TreeRefId::Root;
669 let children = tree_ref.children_id().iter().map(|c| *c + offset).collect();
670
671 self.tree.insert_with_id(
672 tree_ref.id + offset,
673 if is_root_node {
674 self.id()
675 } else {
676 tree_ref.parent().id() + offset
677 },
678 children,
679 tree_ref.spanned_data().clone(),
680 );
681
682 if tree_ref.id + offset > max_offset_node {
683 max_offset_node = tree_ref.id + offset;
684 }
685
686 if is_root_node {
687 self.inner_mut()
688 .children
689 .insert(inserted_nodes, tree_ref.id() + offset);
690
691 inserted_nodes += 1;
692 }
693 }
694
695 self.tree.next_id = max_offset_node + 1;
696 }
697
698 pub fn append_children(&mut self, tree: &Tree<'a>) {
700 let offset = self.tree.next_id();
701 let mut max_offset_node = offset;
702
703 for tree_ref in tree.traverse_depth() {
704 let is_root_node = tree_ref.parent().id() == TreeRefId::Root;
705 let children = tree_ref.children_id().iter().map(|c| *c + offset).collect();
706
707 self.tree.insert_with_id(
708 tree_ref.id + offset,
709 if is_root_node {
710 self.id()
711 } else {
712 tree_ref.parent().id() + offset
713 },
714 children,
715 tree_ref.spanned_data().clone(),
716 );
717
718 if tree_ref.id + offset > max_offset_node {
719 max_offset_node = tree_ref.id + offset;
720 }
721
722 if is_root_node {
723 self.inner_mut().children.push(tree_ref.id() + offset);
724 }
725 }
726
727 self.tree.next_id = max_offset_node + 1;
728 }
729
730 pub fn replace_node_owned(self, tree: &OwnedTree) {
739 let current_index = self
741 .as_ref()
742 .parent()
743 .inner()
744 .children
745 .iter()
746 .position(|id| *id == self.id)
747 .expect("failed to find the node in its parent children");
748
749 let offset = self.tree.next_id();
750
751 let parent_id = self.as_ref().parent().id();
753
754 let mut inserted_nodes = 0;
755 let mut max_offset_node = offset;
756
757 for tree_ref in tree.get_tree().traverse_depth() {
758 let is_root_node = tree_ref.parent().id() == TreeRefId::Root;
759 let children = tree_ref.children_id().iter().map(|c| *c + offset).collect();
760
761 self.tree.insert_with_id(
762 tree_ref.id + offset,
763 if is_root_node {
764 parent_id
765 } else {
766 tree_ref.parent().id() + offset
767 },
768 children,
769 tree_ref
770 .spanned_data()
771 .clone()
772 .map_spanned(Node::deep_clone),
773 );
774
775 if tree_ref.id + offset > max_offset_node {
776 max_offset_node = tree_ref.id + offset;
777 }
778
779 if is_root_node {
780 self.tree
781 .get_mut(parent_id)
782 .inner_mut()
783 .children
784 .insert(current_index + inserted_nodes, tree_ref.id() + offset);
785
786 inserted_nodes += 1;
787 }
788 }
789
790 self.tree.next_id = max_offset_node + 1;
791
792 self.remove();
793 }
794
795 pub fn prepend_children_owned(&mut self, tree: &OwnedTree) {
797 let offset = self.tree.next_id();
798 let mut inserted_nodes = 0;
799 let mut max_offset_node = offset;
800
801 for tree_ref in tree.get_tree().traverse_depth() {
802 let is_root_node = tree_ref.parent().id() == TreeRefId::Root;
803 let children = tree_ref.children_id().iter().map(|c| *c + offset).collect();
804
805 self.tree.insert_with_id(
806 tree_ref.id + offset,
807 if is_root_node {
808 self.id()
809 } else {
810 tree_ref.parent().id() + offset
811 },
812 children,
813 tree_ref
814 .spanned_data()
815 .clone()
816 .map_spanned(Node::deep_clone),
817 );
818
819 if tree_ref.id + offset > max_offset_node {
820 max_offset_node = tree_ref.id + offset;
821 }
822
823 if is_root_node {
824 self.inner_mut()
825 .children
826 .insert(inserted_nodes, tree_ref.id() + offset);
827
828 inserted_nodes += 1;
829 }
830 }
831
832 self.tree.next_id = max_offset_node + 1;
833 }
834
835 pub fn append_children_owned(&mut self, tree: &OwnedTree) {
837 let offset = self.tree.next_id();
838 let mut max_offset_node = offset;
839
840 for tree_ref in tree.get_tree().traverse_depth() {
841 let is_root_node = tree_ref.parent().id() == TreeRefId::Root;
842 let children = tree_ref.children_id().iter().map(|c| *c + offset).collect();
843
844 self.tree.insert_with_id(
845 tree_ref.id + offset,
846 if is_root_node {
847 self.id()
848 } else {
849 tree_ref.parent().id() + offset
850 },
851 children,
852 tree_ref
853 .spanned_data()
854 .clone()
855 .map_spanned(Node::deep_clone),
856 );
857
858 if tree_ref.id + offset > max_offset_node {
859 max_offset_node = tree_ref.id + offset;
860 }
861
862 if is_root_node {
863 self.inner_mut().children.push(tree_ref.id() + offset);
864 }
865 }
866
867 self.tree.next_id = max_offset_node + 1;
868 }
869
870 pub fn replace_html<T: Into<Cow<'a, str>>>(self, file_path: &str, html: T) -> Result<()> {
876 let html = html.into();
877
878 if let Cow::Borrowed(html) = html {
879 let tree = crate::parse(file_path, html)?;
880 self.replace_node(&tree);
881 } else if let Cow::Owned(html) = html {
882 let tree = crate::parse_owned(file_path, &html)?;
883 self.replace_node_owned(&tree);
884 }
885 Ok(())
886 }
887
888 pub fn prepend_html<T: Into<Cow<'a, str>>>(&mut self, file_path: &str, html: T) -> Result<()> {
894 let html = html.into();
895
896 if let Cow::Borrowed(html) = html {
897 let tree = crate::parse(file_path, html)?;
898 self.prepend_children(&tree);
899 } else if let Cow::Owned(html) = html {
900 let tree = crate::parse_owned(file_path, &html)?;
901 self.prepend_children_owned(&tree);
902 }
903 Ok(())
904 }
905
906 pub fn append_html<T: Into<Cow<'a, str>>>(&mut self, file_path: &str, html: T) -> Result<()> {
912 let html = html.into();
913
914 if let Cow::Borrowed(html) = html {
915 let tree = crate::parse(file_path, html)?;
916 self.append_children(&tree);
917 } else if let Cow::Owned(html) = html {
918 let tree = crate::parse_owned(file_path, &html)?;
919 self.append_children_owned(&tree);
920 }
921
922 Ok(())
923 }
924
925 pub fn remove(self) {
934 let node = &mut self.tree.get_mut(self.id);
936 let parent = &mut node.parent();
937 let parent_children = &mut parent.inner_mut().children;
938 let index = parent_children
939 .iter()
940 .position(|c| c == &self.id)
941 .expect("failed to find node in parent children");
942 parent_children.remove(index);
943
944 let node = self.tree.get(self.id);
946 let children = node.inner().children.clone();
947
948 for child in children {
949 self.tree.get_mut(child).remove();
950 }
951
952 self.tree.nodes.remove(&self.id);
954 }
955}
956
957impl PartialEq for TreeRefMut<'_, '_> {
958 fn eq(&self, other: &Self) -> bool {
959 self.id == other.id
960 }
961}
962
963impl fmt::Debug for TreeRefMut<'_, '_> {
964 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
965 f.debug_struct("TreeRefMut")
966 .field("id", &self.id)
967 .field("__inner_node", &self.as_ref().data())
968 .finish()
969 }
970}