1use crate::utils;
2use std::{borrow::Cow, collections::HashMap, convert::TryFrom};
3use vimwiki::{
4 self as v,
5 vendor::{chrono, uriparse},
6 ToHtmlString,
7};
8use wasm_bindgen::prelude::*;
9
10#[wasm_bindgen]
12pub struct Page(v::Page<'static>);
13
14#[wasm_bindgen]
15impl Page {
16 pub fn element_at(&self, idx: usize) -> Option<BlockElement> {
18 self.0.elements.get(idx).map(|x| {
19 BlockElement(v::Located::new(
20 x.to_borrowed().into_owned(),
21 x.region(),
22 ))
23 })
24 }
25
26 #[wasm_bindgen(getter)]
28 pub fn element_cnt(&self) -> usize {
29 self.0.elements.len()
30 }
31}
32
33#[wasm_bindgen]
35pub struct Element(v::Located<v::Element<'static>>);
36
37#[wasm_bindgen]
38impl Element {
39 pub fn is_block(&self) -> bool {
41 matches!(self.0.as_inner(), v::Element::Block(_))
42 }
43
44 pub fn into_block(self) -> Option<BlockElement> {
46 let region = self.0.region();
47 match self.0.into_inner() {
48 v::Element::Block(x) => {
49 Some(BlockElement(v::Located::new(x, region)))
50 }
51 _ => None,
52 }
53 }
54
55 pub fn is_inline(&self) -> bool {
57 matches!(self.0.as_inner(), v::Element::Inline(_))
58 }
59
60 pub fn into_inline(self) -> Option<InlineElement> {
62 let region = self.0.region();
63 match self.0.into_inner() {
64 v::Element::Inline(x) => {
65 Some(InlineElement(v::Located::new(x, region)))
66 }
67 _ => None,
68 }
69 }
70
71 pub fn is_inline_block(&self) -> bool {
73 matches!(self.0.as_inner(), v::Element::InlineBlock(_))
74 }
75
76 pub fn into_inline_block(self) -> Option<InlineBlockElement> {
78 let region = self.0.region();
79 match self.0.into_inner() {
80 v::Element::InlineBlock(x) => {
81 Some(InlineBlockElement(v::Located::new(x, region)))
82 }
83 _ => None,
84 }
85 }
86}
87
88#[wasm_bindgen]
90pub struct BlockElement(v::Located<v::BlockElement<'static>>);
91
92#[wasm_bindgen]
93impl BlockElement {
94 pub fn is_blockquote(&self) -> bool {
96 matches!(self.0.as_inner(), v::BlockElement::Blockquote(_))
97 }
98
99 pub fn into_blockquote(self) -> Option<Blockquote> {
101 let region = self.0.region();
102 match self.0.into_inner() {
103 v::BlockElement::Blockquote(x) => {
104 Some(Blockquote(v::Located::new(x, region)))
105 }
106 _ => None,
107 }
108 }
109
110 pub fn is_code_block(&self) -> bool {
112 matches!(self.0.as_inner(), v::BlockElement::CodeBlock(_))
113 }
114
115 pub fn into_code_block(self) -> Option<CodeBlock> {
117 let region = self.0.region();
118 match self.0.into_inner() {
119 v::BlockElement::CodeBlock(x) => {
120 Some(CodeBlock(v::Located::new(x, region)))
121 }
122 _ => None,
123 }
124 }
125
126 pub fn is_math(&self) -> bool {
128 matches!(self.0.as_inner(), v::BlockElement::Math(_))
129 }
130
131 pub fn into_math_block(self) -> Option<MathBlock> {
133 let region = self.0.region();
134 match self.0.into_inner() {
135 v::BlockElement::Math(x) => {
136 Some(MathBlock(v::Located::new(x, region)))
137 }
138 _ => None,
139 }
140 }
141
142 pub fn is_definition_list(&self) -> bool {
144 matches!(self.0.as_inner(), v::BlockElement::DefinitionList(_))
145 }
146
147 pub fn into_definition_list(self) -> Option<DefinitionList> {
149 let region = self.0.region();
150 match self.0.into_inner() {
151 v::BlockElement::DefinitionList(x) => {
152 Some(DefinitionList(v::Located::new(x, region)))
153 }
154 _ => None,
155 }
156 }
157
158 pub fn is_divider(&self) -> bool {
160 matches!(self.0.as_inner(), v::BlockElement::Divider(_))
161 }
162
163 pub fn into_divider(self) -> Option<Divider> {
165 let region = self.0.region();
166 match self.0.into_inner() {
167 v::BlockElement::Divider(x) => {
168 Some(Divider(v::Located::new(x, region)))
169 }
170 _ => None,
171 }
172 }
173
174 pub fn is_header(&self) -> bool {
176 matches!(self.0.as_inner(), v::BlockElement::Header(_))
177 }
178
179 pub fn into_header(self) -> Option<Header> {
181 let region = self.0.region();
182 match self.0.into_inner() {
183 v::BlockElement::Header(x) => {
184 Some(Header(v::Located::new(x, region)))
185 }
186 _ => None,
187 }
188 }
189
190 pub fn is_list(&self) -> bool {
192 matches!(self.0.as_inner(), v::BlockElement::List(_))
193 }
194
195 pub fn into_list(self) -> Option<List> {
197 let region = self.0.region();
198 match self.0.into_inner() {
199 v::BlockElement::List(x) => Some(List(v::Located::new(x, region))),
200 _ => None,
201 }
202 }
203
204 pub fn is_paragraph(&self) -> bool {
206 matches!(self.0.as_inner(), v::BlockElement::Paragraph(_))
207 }
208
209 pub fn into_paragraph(self) -> Option<Paragraph> {
211 let region = self.0.region();
212 match self.0.into_inner() {
213 v::BlockElement::Paragraph(x) => {
214 Some(Paragraph(v::Located::new(x, region)))
215 }
216 _ => None,
217 }
218 }
219
220 pub fn is_placeholder(&self) -> bool {
222 matches!(self.0.as_inner(), v::BlockElement::Placeholder(_))
223 }
224
225 pub fn into_placeholder(self) -> Option<Placeholder> {
227 let region = self.0.region();
228 match self.0.into_inner() {
229 v::BlockElement::Placeholder(x) => {
230 Some(Placeholder(v::Located::new(x, region)))
231 }
232 _ => None,
233 }
234 }
235
236 pub fn is_table(&self) -> bool {
238 matches!(self.0.as_inner(), v::BlockElement::Table(_))
239 }
240
241 pub fn into_table(self) -> Option<Table> {
243 let region = self.0.region();
244 match self.0.into_inner() {
245 v::BlockElement::Table(x) => {
246 Some(Table(v::Located::new(x, region)))
247 }
248 _ => None,
249 }
250 }
251}
252
253#[wasm_bindgen]
255pub struct InlineBlockElement(v::Located<v::InlineBlockElement<'static>>);
256
257#[wasm_bindgen]
258impl InlineBlockElement {
259 pub fn is_list_item(&self) -> bool {
261 matches!(self.0.as_inner(), v::InlineBlockElement::ListItem(_))
262 }
263
264 pub fn into_list_item(self) -> Option<ListItem> {
266 let region = self.0.region();
267 match self.0.into_inner() {
268 v::InlineBlockElement::ListItem(x) => {
269 Some(ListItem(v::Located::new(x, region)))
270 }
271 _ => None,
272 }
273 }
274
275 pub fn is_term(&self) -> bool {
277 matches!(self.0.as_inner(), v::InlineBlockElement::Term(_))
278 }
279
280 pub fn into_term(self) -> Option<InlineElementContainer> {
282 match self.0.into_inner() {
283 v::InlineBlockElement::Term(x) => {
284 Some(InlineElementContainer(x.into()))
285 }
286 _ => None,
287 }
288 }
289
290 pub fn is_definition(&self) -> bool {
292 matches!(self.0.as_inner(), v::InlineBlockElement::Definition(_))
293 }
294
295 pub fn into_definition(self) -> Option<InlineElementContainer> {
297 match self.0.into_inner() {
298 v::InlineBlockElement::Definition(x) => {
299 Some(InlineElementContainer(x.into()))
300 }
301 _ => None,
302 }
303 }
304}
305
306#[wasm_bindgen]
308pub struct InlineElement(v::Located<v::InlineElement<'static>>);
309
310#[wasm_bindgen]
311impl InlineElement {
312 pub fn is_text(&self) -> bool {
314 matches!(self.0.as_inner(), v::InlineElement::Text(_))
315 }
316
317 pub fn into_text(self) -> Option<Text> {
319 let region = self.0.region();
320 match self.0.into_inner() {
321 v::InlineElement::Text(x) => Some(Text(v::Located::new(x, region))),
322 _ => None,
323 }
324 }
325
326 pub fn is_decorated_text(&self) -> bool {
328 matches!(self.0.as_inner(), v::InlineElement::DecoratedText(_))
329 }
330
331 pub fn into_decorated_text(self) -> Option<DecoratedText> {
333 let region = self.0.region();
334 match self.0.into_inner() {
335 v::InlineElement::DecoratedText(x) => {
336 Some(DecoratedText(v::Located::new(x, region)))
337 }
338 _ => None,
339 }
340 }
341
342 pub fn is_keyword(&self) -> bool {
344 matches!(self.0.as_inner(), v::InlineElement::Keyword(_))
345 }
346
347 pub fn into_keyword(self) -> Option<Keyword> {
349 match self.0.into_inner() {
350 v::InlineElement::Keyword(x) => Some(Keyword::from(x)),
351 _ => None,
352 }
353 }
354
355 pub fn is_link(&self) -> bool {
357 matches!(self.0.as_inner(), v::InlineElement::Link(_))
358 }
359
360 pub fn into_link(self) -> Option<Link> {
362 let region = self.0.region();
363 match self.0.into_inner() {
364 v::InlineElement::Link(x) => Some(Link(v::Located::new(x, region))),
365 _ => None,
366 }
367 }
368
369 pub fn is_tags(&self) -> bool {
371 matches!(self.0.as_inner(), v::InlineElement::Tags(_))
372 }
373
374 pub fn into_tags(self) -> Option<Tags> {
376 let region = self.0.region();
377 match self.0.into_inner() {
378 v::InlineElement::Tags(x) => Some(Tags(v::Located::new(x, region))),
379 _ => None,
380 }
381 }
382
383 pub fn is_inline_code(&self) -> bool {
385 matches!(self.0.as_inner(), v::InlineElement::Code(_))
386 }
387
388 pub fn into_inline_code(self) -> Option<CodeInline> {
390 let region = self.0.region();
391 match self.0.into_inner() {
392 v::InlineElement::Code(x) => {
393 Some(CodeInline(v::Located::new(x, region)))
394 }
395 _ => None,
396 }
397 }
398
399 pub fn is_inline_math(&self) -> bool {
401 matches!(self.0.as_inner(), v::InlineElement::Math(_))
402 }
403
404 pub fn into_inline_math(self) -> Option<MathInline> {
406 let region = self.0.region();
407 match self.0.into_inner() {
408 v::InlineElement::Math(x) => {
409 Some(MathInline(v::Located::new(x, region)))
410 }
411 _ => None,
412 }
413 }
414
415 pub fn is_comment(&self) -> bool {
417 matches!(self.0.as_inner(), v::InlineElement::Comment(_))
418 }
419
420 pub fn into_comment(self) -> Option<Comment> {
422 let region = self.0.region();
423 match self.0.into_inner() {
424 v::InlineElement::Comment(x) => {
425 Some(Comment(v::Located::new(x, region)))
426 }
427 _ => None,
428 }
429 }
430}
431
432#[wasm_bindgen]
434pub struct InlineElementContainer(v::InlineElementContainer<'static>);
435
436#[wasm_bindgen]
437impl InlineElementContainer {
438 pub fn element_at(&self, idx: usize) -> Option<InlineElement> {
440 self.0.get(idx).map(|x| {
441 InlineElement(v::Located::new(
442 x.to_borrowed().into_owned(),
443 x.region(),
444 ))
445 })
446 }
447
448 #[wasm_bindgen(getter)]
450 pub fn element_cnt(&self) -> usize {
451 self.0.len()
452 }
453
454 pub fn to_str(&self) -> String {
456 self.0.to_string()
457 }
458}
459
460#[wasm_bindgen]
462pub struct Blockquote(v::Located<v::Blockquote<'static>>);
463
464#[wasm_bindgen]
465impl Blockquote {
466 pub fn line_at(&self, idx: usize) -> Option<String> {
468 self.0.lines.get(idx).map(ToString::to_string)
469 }
470
471 #[wasm_bindgen(getter)]
473 pub fn line_cnt(&self) -> usize {
474 self.0.lines.len()
475 }
476}
477
478#[wasm_bindgen]
480pub struct CodeBlock(v::Located<v::CodeBlock<'static>>);
481
482#[wasm_bindgen]
483impl CodeBlock {
484 #[wasm_bindgen(getter)]
486 pub fn language(&self) -> Option<String> {
487 self.0.language.as_ref().map(ToString::to_string)
488 }
489
490 #[wasm_bindgen(getter)]
492 pub fn metadata(&self) -> Option<js_sys::Object> {
493 let arr = js_sys::Array::new();
494
495 for (key, value) in self.0.metadata.iter() {
496 let tuple = js_sys::Array::new();
497 tuple.push(&JsValue::from_str(key));
498 tuple.push(&JsValue::from_str(value));
499
500 arr.push(&tuple);
501 }
502
503 js_sys::Object::from_entries(&arr).ok()
504 }
505
506 pub fn line_at(&self, idx: usize) -> Option<String> {
508 self.0.lines.get(idx).map(ToString::to_string)
509 }
510
511 #[wasm_bindgen(getter)]
513 pub fn line_cnt(&self) -> usize {
514 self.0.lines.len()
515 }
516}
517
518#[wasm_bindgen]
520pub struct DefinitionList(v::Located<v::DefinitionList<'static>>);
521
522#[wasm_bindgen]
523impl DefinitionList {
524 #[wasm_bindgen(getter)]
526 pub fn terms(&self) -> Vec<JsValue> {
527 self.0
528 .terms()
529 .map(ToString::to_string)
530 .map(|x| JsValue::from_str(&x))
531 .collect()
532 }
533
534 pub fn get_def(&self, term: &str) -> Option<InlineElementContainer> {
536 self.0.get(term).map(|x| {
537 InlineElementContainer(
538 x.iter()
539 .map(|x| x.as_inner().as_inner().to_borrowed().into_owned())
540 .collect::<v::InlineElementContainer>(),
541 )
542 })
543 }
544
545 #[wasm_bindgen(getter)]
547 pub fn term_cnt(&self) -> usize {
548 self.0.terms().count()
549 }
550
551 #[wasm_bindgen(getter)]
553 pub fn def_cnt(&self) -> usize {
554 self.0.definitions().count()
555 }
556}
557
558#[wasm_bindgen]
560pub struct Divider(v::Located<v::Divider>);
561
562#[wasm_bindgen]
564pub struct Header(v::Located<v::Header<'static>>);
565
566#[wasm_bindgen]
567impl Header {
568 #[wasm_bindgen(getter)]
570 pub fn level(&self) -> usize {
571 self.0.level
572 }
573
574 #[wasm_bindgen(getter)]
576 pub fn content(&self) -> InlineElementContainer {
577 InlineElementContainer(self.0.content.to_borrowed().into_owned())
578 }
579
580 #[wasm_bindgen(getter)]
582 pub fn centered(&self) -> bool {
583 self.0.centered
584 }
585
586 pub fn to_str(&self) -> String {
588 self.0.content.to_string()
589 }
590}
591
592#[wasm_bindgen]
594pub struct List(v::Located<v::List<'static>>);
595
596#[wasm_bindgen]
597impl List {
598 pub fn item_at(&self, idx: usize) -> Option<ListItem> {
600 self.0.items.get(idx).map(|x| {
601 ListItem(v::Located::new(x.to_borrowed().into_owned(), x.region()))
602 })
603 }
604
605 #[wasm_bindgen(getter)]
607 pub fn item_cnt(&self) -> usize {
608 self.0.len()
609 }
610}
611
612#[wasm_bindgen]
614pub struct ListItem(v::Located<v::ListItem<'static>>);
615
616#[wasm_bindgen]
617impl ListItem {
618 #[wasm_bindgen(getter)]
620 pub fn pos(&self) -> usize {
621 self.0.pos
622 }
623
624 #[wasm_bindgen(getter)]
626 pub fn contents(&self) -> ListItemContents {
627 ListItemContents(self.0.contents.to_borrowed().into_owned())
628 }
629
630 #[wasm_bindgen(getter)]
632 pub fn prefix(&self) -> String {
633 self.0.ty.to_prefix(self.0.pos, self.0.suffix)
634 }
635
636 #[wasm_bindgen(getter)]
638 pub fn suffix(&self) -> ListItemSuffix {
639 ListItemSuffix::from(self.0.suffix)
640 }
641
642 #[wasm_bindgen(getter)]
644 pub fn attributes(&self) -> ListItemAttributes {
645 ListItemAttributes(self.0.attributes)
646 }
647
648 pub fn is_ordered(&self) -> bool {
650 self.0.ty.is_ordered()
651 }
652
653 pub fn is_unordered(&self) -> bool {
655 self.0.ty.is_unordered()
656 }
657}
658
659#[wasm_bindgen]
661pub struct ListItemContents(v::ListItemContents<'static>);
662
663#[wasm_bindgen]
664impl ListItemContents {
665 pub fn content_at(&self, idx: usize) -> Option<ListItemContent> {
667 self.0.get(idx).map(|x| {
668 ListItemContent(v::Located::new(
669 x.to_borrowed().into_owned(),
670 x.region(),
671 ))
672 })
673 }
674
675 #[wasm_bindgen(getter)]
677 pub fn content_cnt(&self) -> usize {
678 self.0.len()
679 }
680}
681
682#[wasm_bindgen]
684pub struct ListItemContent(v::Located<v::ListItemContent<'static>>);
685
686#[wasm_bindgen]
687impl ListItemContent {
688 pub fn into_list(self) -> Option<List> {
690 let region = self.0.region();
691 match self.0.into_inner() {
692 v::ListItemContent::List(x) => {
693 Some(List(v::Located::new(x, region)))
694 }
695 _ => None,
696 }
697 }
698
699 pub fn into_inline_container(self) -> Option<InlineElementContainer> {
701 match self.0.into_inner() {
702 v::ListItemContent::InlineContent(x) => {
703 Some(InlineElementContainer(x))
704 }
705 _ => None,
706 }
707 }
708
709 pub fn is_list(&self) -> bool {
711 matches!(self.0.as_inner(), v::ListItemContent::List(_))
712 }
713
714 pub fn is_inline_container(&self) -> bool {
716 matches!(self.0.as_inner(), v::ListItemContent::InlineContent(_))
717 }
718}
719
720#[wasm_bindgen]
722pub struct ListItemAttributes(v::ListItemAttributes);
723
724#[wasm_bindgen]
725impl ListItemAttributes {
726 #[wasm_bindgen(getter)]
728 pub fn todo_status(&self) -> Option<ListItemTodoStatus> {
729 self.0
730 .todo_status
731 .as_ref()
732 .copied()
733 .map(ListItemTodoStatus::from)
734 }
735
736 pub fn is_todo_incomplete(&self) -> bool {
737 matches!(self.0.todo_status, Some(v::ListItemTodoStatus::Incomplete))
738 }
739
740 pub fn is_todo_partially_complete_1(&self) -> bool {
741 matches!(
742 self.0.todo_status,
743 Some(v::ListItemTodoStatus::PartiallyComplete1)
744 )
745 }
746
747 pub fn is_todo_partially_complete_2(&self) -> bool {
748 matches!(
749 self.0.todo_status,
750 Some(v::ListItemTodoStatus::PartiallyComplete2)
751 )
752 }
753
754 pub fn is_todo_partially_complete_3(&self) -> bool {
755 matches!(
756 self.0.todo_status,
757 Some(v::ListItemTodoStatus::PartiallyComplete3)
758 )
759 }
760
761 pub fn is_todo_complete(&self) -> bool {
762 matches!(self.0.todo_status, Some(v::ListItemTodoStatus::Complete))
763 }
764
765 pub fn is_todo_rejected(&self) -> bool {
766 matches!(self.0.todo_status, Some(v::ListItemTodoStatus::Rejected))
767 }
768}
769
770#[wasm_bindgen]
772pub enum ListItemTodoStatus {
773 Incomplete = "incomplete",
774 PartiallyComplete1 = "partially_complete_1",
775 PartiallyComplete2 = "partially_complete_2",
776 PartiallyComplete3 = "partially_complete_3",
777 Complete = "complete",
778 Rejected = "rejected",
779}
780
781impl ListItemTodoStatus {
782 pub fn to_vimwiki(&self) -> Option<v::ListItemTodoStatus> {
783 match self {
784 Self::Incomplete => Some(v::ListItemTodoStatus::Incomplete),
785 Self::PartiallyComplete1 => {
786 Some(v::ListItemTodoStatus::PartiallyComplete1)
787 }
788 Self::PartiallyComplete2 => {
789 Some(v::ListItemTodoStatus::PartiallyComplete2)
790 }
791 Self::PartiallyComplete3 => {
792 Some(v::ListItemTodoStatus::PartiallyComplete3)
793 }
794 Self::Complete => Some(v::ListItemTodoStatus::Complete),
795 Self::Rejected => Some(v::ListItemTodoStatus::Rejected),
796 _ => None,
797 }
798 }
799}
800
801impl From<v::ListItemTodoStatus> for ListItemTodoStatus {
802 fn from(x: v::ListItemTodoStatus) -> Self {
803 match x {
804 v::ListItemTodoStatus::Incomplete => Self::Incomplete,
805 v::ListItemTodoStatus::PartiallyComplete1 => {
806 Self::PartiallyComplete1
807 }
808 v::ListItemTodoStatus::PartiallyComplete2 => {
809 Self::PartiallyComplete2
810 }
811 v::ListItemTodoStatus::PartiallyComplete3 => {
812 Self::PartiallyComplete3
813 }
814 v::ListItemTodoStatus::Complete => Self::Complete,
815 v::ListItemTodoStatus::Rejected => Self::Rejected,
816 }
817 }
818}
819
820#[wasm_bindgen]
821pub enum ListItemSuffix {
822 None = "none",
823 Period = "period",
824 Paren = "paren",
825}
826
827impl ListItemSuffix {
828 pub fn to_vimwiki(&self) -> Option<v::ListItemSuffix> {
829 match self {
830 Self::None => Some(v::ListItemSuffix::None),
831 Self::Period => Some(v::ListItemSuffix::Period),
832 Self::Paren => Some(v::ListItemSuffix::Paren),
833 _ => None,
834 }
835 }
836}
837
838impl From<v::ListItemSuffix> for ListItemSuffix {
839 fn from(x: v::ListItemSuffix) -> Self {
840 match x {
841 v::ListItemSuffix::None => Self::None,
842 v::ListItemSuffix::Period => Self::Period,
843 v::ListItemSuffix::Paren => Self::Paren,
844 }
845 }
846}
847
848#[wasm_bindgen]
850pub struct MathBlock(v::Located<v::MathBlock<'static>>);
851
852#[wasm_bindgen]
853impl MathBlock {
854 #[wasm_bindgen(getter)]
856 pub fn environment(&self) -> Option<String> {
857 self.0.environment.as_ref().map(ToString::to_string)
858 }
859
860 pub fn line_at(&self, idx: usize) -> Option<String> {
862 self.0.lines.get(idx).map(ToString::to_string)
863 }
864
865 #[wasm_bindgen(getter)]
867 pub fn line_cnt(&self) -> usize {
868 self.0.lines.len()
869 }
870}
871
872#[wasm_bindgen]
874pub struct Paragraph(v::Located<v::Paragraph<'static>>);
875
876#[wasm_bindgen]
877impl Paragraph {
878 pub fn line_at(&self, idx: usize) -> Option<InlineElementContainer> {
880 self.0
881 .lines
882 .get(idx)
883 .map(|x| InlineElementContainer(x.to_borrowed().into_owned()))
884 }
885
886 #[wasm_bindgen(getter)]
888 pub fn line_cnt(&self) -> usize {
889 self.0.lines.len()
890 }
891
892 pub fn to_str(&self) -> String {
894 self.0
895 .lines
896 .iter()
897 .map(ToString::to_string)
898 .collect::<Vec<String>>()
899 .join("\n")
900 }
901}
902
903#[wasm_bindgen]
905pub struct Placeholder(v::Located<v::Placeholder<'static>>);
906
907#[wasm_bindgen]
908impl Placeholder {
909 #[wasm_bindgen(getter)]
911 pub fn title(&self) -> Option<String> {
912 match self.0.as_inner() {
913 v::Placeholder::Title(x) => Some(x.to_string()),
914 _ => None,
915 }
916 }
917
918 #[wasm_bindgen(getter)]
920 pub fn template(&self) -> Option<String> {
921 match self.0.as_inner() {
922 v::Placeholder::Template(x) => Some(x.to_string()),
923 _ => None,
924 }
925 }
926
927 #[wasm_bindgen(getter)]
929 pub fn date(&self) -> Option<js_sys::Date> {
930 use chrono::Datelike;
931 match self.0.as_inner() {
932 v::Placeholder::Date(x) => {
933 Some(js_sys::Date::new_with_year_month_day(
934 x.year() as u32,
935 x.month() as i32,
936 x.day() as i32,
937 ))
938 }
939 _ => None,
940 }
941 }
942
943 #[wasm_bindgen(getter)]
945 pub fn other_name(&self) -> Option<String> {
946 match self.0.as_inner() {
947 v::Placeholder::Other { name, .. } => Some(name.to_string()),
948 _ => None,
949 }
950 }
951
952 #[wasm_bindgen(getter)]
954 pub fn other_value(&self) -> Option<String> {
955 match self.0.as_inner() {
956 v::Placeholder::Other { value, .. } => Some(value.to_string()),
957 _ => None,
958 }
959 }
960
961 pub fn is_no_html(&self) -> bool {
963 matches!(self.0.as_inner(), v::Placeholder::NoHtml)
964 }
965}
966
967#[wasm_bindgen]
969pub struct Table(v::Located<v::Table<'static>>);
970
971#[wasm_bindgen]
972impl Table {
973 #[wasm_bindgen(constructor)]
977 pub fn new(
978 cells: js_sys::Array,
979 centered: bool,
980 region: Option<Region>,
981 ) -> Result<Table, JsValue> {
982 Ok(Self(v::Located::new(
983 v::Table::new(
984 cells
985 .iter()
986 .map(js_sys::Array::try_from)
987 .enumerate()
988 .filter_map(|(row, res)| {
989 res.map(|arr| {
990 arr.iter()
991 .filter_map(|x| {
992 utils::cast_value::<Cell>(x, "Cell").ok()
993 })
994 .enumerate()
995 .map(|(col, x)| {
996 (v::CellPos { row, col }, x.0)
997 })
998 .collect::<Vec<(v::CellPos, v::Located<v::Cell>)>>()
999 })
1000 .ok()
1001 })
1002 .flatten(),
1003 centered,
1004 ),
1005 region.map(|x| x.0).unwrap_or_default(),
1006 )))
1007 }
1008
1009 pub fn cell_at(&self, row: usize, col: usize) -> Option<Cell> {
1011 self.0.get_cell(row, col).map(|x| {
1012 Cell(v::Located::new(x.to_borrowed().into_owned(), x.region()))
1013 })
1014 }
1015
1016 #[wasm_bindgen(getter)]
1018 pub fn row_cnt(&self) -> usize {
1019 self.0.row_cnt()
1020 }
1021
1022 #[wasm_bindgen(getter)]
1024 pub fn col_cnt(&self) -> usize {
1025 self.0.col_cnt()
1026 }
1027
1028 #[wasm_bindgen(getter)]
1030 pub fn centered(&self) -> bool {
1031 self.0.centered
1032 }
1033}
1034
1035#[wasm_bindgen]
1037pub struct Cell(v::Located<v::Cell<'static>>);
1038
1039#[wasm_bindgen]
1040impl Cell {
1041 #[wasm_bindgen(constructor)]
1043 pub fn new(txt: &str, region: Option<Region>) -> Result<Cell, JsValue> {
1044 Ok(Self(v::Located::new(
1045 v::Cell::Content(v::InlineElementContainer::new(vec![
1046 v::Located::from(v::InlineElement::Text(v::Text::from(txt))),
1047 ]))
1048 .into_owned(),
1049 region.map(|x| x.0).unwrap_or_default(),
1050 )))
1051 }
1052
1053 #[wasm_bindgen(getter)]
1055 pub fn content(&self) -> Option<InlineElementContainer> {
1056 self.0
1057 .get_content()
1058 .map(|x| InlineElementContainer(x.to_borrowed().into_owned()))
1059 }
1060
1061 pub fn is_span(&self) -> bool {
1063 self.0.is_span()
1064 }
1065
1066 pub fn is_span_from_above(&self) -> bool {
1068 self.0
1069 .get_span()
1070 .map(|x| matches!(x, v::CellSpan::FromAbove))
1071 .unwrap_or_default()
1072 }
1073
1074 pub fn is_span_from_left(&self) -> bool {
1076 self.0
1077 .get_span()
1078 .map(|x| matches!(x, v::CellSpan::FromLeft))
1079 .unwrap_or_default()
1080 }
1081
1082 pub fn is_align(&self) -> bool {
1084 self.0.is_align()
1085 }
1086
1087 pub fn is_align_left(&self) -> bool {
1089 self.0
1090 .get_align()
1091 .map(|x| matches!(x, v::ColumnAlign::Left))
1092 .unwrap_or_default()
1093 }
1094
1095 pub fn is_align_centered(&self) -> bool {
1097 self.0
1098 .get_align()
1099 .map(|x| matches!(x, v::ColumnAlign::Center))
1100 .unwrap_or_default()
1101 }
1102
1103 pub fn is_align_right(&self) -> bool {
1105 self.0
1106 .get_align()
1107 .map(|x| matches!(x, v::ColumnAlign::Right))
1108 .unwrap_or_default()
1109 }
1110
1111 pub fn to_str(&self) -> Option<String> {
1113 self.0.get_content().map(ToString::to_string)
1114 }
1115}
1116
1117#[wasm_bindgen]
1119pub struct DecoratedText(v::Located<v::DecoratedText<'static>>);
1120
1121#[wasm_bindgen]
1122impl DecoratedText {
1123 pub fn new_bold_text(txt: &str, region: Option<Region>) -> DecoratedText {
1125 Self(v::Located::new(
1126 v::DecoratedText::Bold(vec![v::Located::from(
1127 v::DecoratedTextContent::Text(v::Text::from(txt)),
1128 )])
1129 .into_owned(),
1130 region.map(|x| x.0).unwrap_or_default(),
1131 ))
1132 }
1133
1134 pub fn new_italic_text(txt: &str, region: Option<Region>) -> DecoratedText {
1136 Self(v::Located::new(
1137 v::DecoratedText::Italic(vec![v::Located::from(
1138 v::DecoratedTextContent::Text(v::Text::from(txt)),
1139 )])
1140 .into_owned(),
1141 region.map(|x| x.0).unwrap_or_default(),
1142 ))
1143 }
1144
1145 pub fn new_strikeout_text(
1147 txt: &str,
1148 region: Option<Region>,
1149 ) -> DecoratedText {
1150 Self(v::Located::new(
1151 v::DecoratedText::Strikeout(vec![v::Located::from(
1152 v::DecoratedTextContent::Text(v::Text::from(txt)),
1153 )])
1154 .into_owned(),
1155 region.map(|x| x.0).unwrap_or_default(),
1156 ))
1157 }
1158
1159 pub fn new_superscript_text(
1161 txt: &str,
1162 region: Option<Region>,
1163 ) -> DecoratedText {
1164 Self(v::Located::new(
1165 v::DecoratedText::Superscript(vec![v::Located::from(
1166 v::DecoratedTextContent::Text(v::Text::from(txt)),
1167 )])
1168 .into_owned(),
1169 region.map(|x| x.0).unwrap_or_default(),
1170 ))
1171 }
1172
1173 pub fn new_subscript_text(
1175 txt: &str,
1176 region: Option<Region>,
1177 ) -> DecoratedText {
1178 Self(v::Located::new(
1179 v::DecoratedText::Subscript(vec![v::Located::from(
1180 v::DecoratedTextContent::Text(v::Text::from(txt)),
1181 )])
1182 .into_owned(),
1183 region.map(|x| x.0).unwrap_or_default(),
1184 ))
1185 }
1186
1187 pub fn is_bold(&self) -> bool {
1189 matches!(self.0.as_inner(), v::DecoratedText::Bold(_))
1190 }
1191
1192 pub fn is_italic(&self) -> bool {
1194 matches!(self.0.as_inner(), v::DecoratedText::Italic(_))
1195 }
1196
1197 pub fn is_strikeout(&self) -> bool {
1199 matches!(self.0.as_inner(), v::DecoratedText::Strikeout(_))
1200 }
1201
1202 pub fn is_superscript(&self) -> bool {
1204 matches!(self.0.as_inner(), v::DecoratedText::Superscript(_))
1205 }
1206
1207 pub fn is_subscript(&self) -> bool {
1209 matches!(self.0.as_inner(), v::DecoratedText::Subscript(_))
1210 }
1211
1212 #[wasm_bindgen(getter)]
1214 pub fn contents(&self) -> DecoratedTextContents {
1215 DecoratedTextContents(
1216 self.0
1217 .iter()
1218 .map(|x| x.as_ref().map(|x| x.to_borrowed().into_owned()))
1219 .collect(),
1220 )
1221 }
1222
1223 pub fn to_str(&self) -> String {
1225 self.0.to_string()
1226 }
1227}
1228
1229#[wasm_bindgen]
1231pub struct DecoratedTextContents(
1232 Vec<v::Located<v::DecoratedTextContent<'static>>>,
1233);
1234
1235#[wasm_bindgen]
1236impl DecoratedTextContents {
1237 pub fn get(&self, idx: usize) -> Option<DecoratedTextContent> {
1239 self.0.get(idx).map(|x| {
1240 DecoratedTextContent(
1241 x.as_ref().map(|x| x.to_borrowed().into_owned()),
1242 )
1243 })
1244 }
1245
1246 pub fn is_empty(&self) -> bool {
1248 self.0.is_empty()
1249 }
1250
1251 #[wasm_bindgen(getter)]
1253 pub fn len(&self) -> usize {
1254 self.0.len()
1255 }
1256}
1257
1258#[wasm_bindgen]
1260pub struct DecoratedTextContent(v::Located<v::DecoratedTextContent<'static>>);
1261
1262#[wasm_bindgen]
1263impl DecoratedTextContent {
1264 pub fn to_str(&self) -> String {
1266 self.0.to_string()
1267 }
1268}
1269
1270#[wasm_bindgen]
1272pub enum Keyword {
1273 Todo = "TODO",
1274 Done = "DONE",
1275 Started = "STARTED",
1276 Fixme = "FIXME",
1277 Fixed = "FIXED",
1278 Xxx = "XXX",
1279}
1280
1281impl Keyword {
1282 pub fn to_vimwiki(&self) -> Option<v::Keyword> {
1284 match self {
1285 Keyword::Todo => Some(v::Keyword::Todo),
1286 Keyword::Done => Some(v::Keyword::Done),
1287 Keyword::Started => Some(v::Keyword::Started),
1288 Keyword::Fixme => Some(v::Keyword::Fixme),
1289 Keyword::Fixed => Some(v::Keyword::Fixed),
1290 Keyword::Xxx => Some(v::Keyword::Xxx),
1291 _ => None,
1292 }
1293 }
1294}
1295
1296impl From<v::Keyword> for Keyword {
1297 fn from(x: v::Keyword) -> Self {
1298 match x {
1299 v::Keyword::Todo => Self::Todo,
1300 v::Keyword::Done => Self::Done,
1301 v::Keyword::Started => Self::Started,
1302 v::Keyword::Fixme => Self::Fixme,
1303 v::Keyword::Fixed => Self::Fixed,
1304 v::Keyword::Xxx => Self::Xxx,
1305 }
1306 }
1307}
1308
1309#[wasm_bindgen]
1311pub struct Link(v::Located<v::Link<'static>>);
1312
1313#[wasm_bindgen]
1314impl Link {
1315 pub fn new_wiki_link(
1317 uri: &str,
1318 description: &str,
1319 region: Option<Region>,
1320 ) -> Result<Link, JsValue> {
1321 Ok(Self(v::Located::new(
1322 v::Link::new_wiki_link(
1323 uriparse::URIReference::try_from(uri)
1324 .map_err(|x| JsValue::from_str(x.to_string().as_str()))?,
1325 v::Description::try_from_uri_ref_str(description)
1326 .unwrap_or_else(|_| v::Description::from(description)),
1327 )
1328 .into_owned(),
1329 region.map(|x| x.0).unwrap_or_default(),
1330 )))
1331 }
1332
1333 pub fn new_indexed_interwiki_link(
1335 index: u32,
1336 uri: &str,
1337 description: &str,
1338 region: Option<Region>,
1339 ) -> Result<Link, JsValue> {
1340 Ok(Self(v::Located::new(
1341 v::Link::new_indexed_interwiki_link(
1342 index,
1343 uriparse::URIReference::try_from(uri)
1344 .map_err(|x| JsValue::from_str(x.to_string().as_str()))?,
1345 v::Description::try_from_uri_ref_str(description)
1346 .unwrap_or_else(|_| v::Description::from(description)),
1347 )
1348 .into_owned(),
1349 region.map(|x| x.0).unwrap_or_default(),
1350 )))
1351 }
1352
1353 pub fn new_named_interwiki_link(
1355 name: &str,
1356 uri: &str,
1357 description: &str,
1358 region: Option<Region>,
1359 ) -> Result<Link, JsValue> {
1360 Ok(Self(v::Located::new(
1361 v::Link::new_named_interwiki_link(
1362 name,
1363 uriparse::URIReference::try_from(uri)
1364 .map_err(|x| JsValue::from_str(x.to_string().as_str()))?,
1365 v::Description::try_from_uri_ref_str(description)
1366 .unwrap_or_else(|_| v::Description::from(description)),
1367 )
1368 .into_owned(),
1369 region.map(|x| x.0).unwrap_or_default(),
1370 )))
1371 }
1372
1373 pub fn new_diary_link(
1375 date: js_sys::Date,
1376 description: &str,
1377 anchor: &str,
1378 region: Option<Region>,
1379 ) -> Link {
1380 Self(v::Located::new(
1381 v::Link::new_diary_link(
1382 chrono::NaiveDate::from_ymd(
1383 date.get_utc_full_year() as i32,
1384 date.get_utc_month(),
1385 date.get_utc_date(),
1386 ),
1387 v::Description::try_from_uri_ref_str(description)
1388 .unwrap_or_else(|_| v::Description::from(description)),
1389 v::Anchor::from_uri_fragment(anchor),
1390 )
1391 .into_owned(),
1392 region.map(|x| x.0).unwrap_or_default(),
1393 ))
1394 }
1395
1396 pub fn new_raw_link(
1398 uri: &str,
1399 region: Option<Region>,
1400 ) -> Result<Link, JsValue> {
1401 Ok(Self(v::Located::new(
1402 v::Link::new_raw_link(
1403 uriparse::URIReference::try_from(uri)
1404 .map_err(|x| JsValue::from_str(x.to_string().as_str()))?,
1405 )
1406 .into_owned(),
1407 region.map(|x| x.0).unwrap_or_default(),
1408 )))
1409 }
1410
1411 pub fn new_transclusion_link(
1413 uri: &str,
1414 description: &str,
1415 properties: &js_sys::Object,
1416 region: Option<Region>,
1417 ) -> Result<Link, JsValue> {
1418 let uri = uriparse::URIReference::try_from(uri)
1419 .map_err(|x| JsValue::from_str(x.to_string().as_str()))?;
1420 let desc = v::Description::try_from_uri_ref_str(description)
1421 .unwrap_or_else(|_| v::Description::from(description));
1422 let props: HashMap<Cow<'_, str>, Cow<'_, str>> =
1423 js_sys::Object::entries(properties)
1424 .iter()
1425 .filter_map(|entry| {
1426 use wasm_bindgen::JsCast;
1427 entry.dyn_ref::<js_sys::Array>().and_then(|entry| {
1428 let key = js_sys::Array::get(entry, 0);
1429 let value = js_sys::Array::get(entry, 1);
1430
1431 key.as_string().and_then(|key| {
1432 value.as_string().map(|value| {
1433 (Cow::Owned(key), Cow::Owned(value))
1434 })
1435 })
1436 })
1437 })
1438 .collect();
1439
1440 Ok(Self(v::Located::new(
1441 v::Link::new_transclusion_link(uri, desc, props).into_owned(),
1442 region.map(|x| x.0).unwrap_or_default(),
1443 )))
1444 }
1445
1446 #[wasm_bindgen(getter)]
1448 pub fn uri(&self) -> String {
1449 self.0.data().uri_ref.to_string()
1450 }
1451
1452 #[wasm_bindgen(getter)]
1454 pub fn description(&self) -> Option<String> {
1455 self.0.description().map(ToString::to_string)
1456 }
1457
1458 #[wasm_bindgen(getter)]
1460 pub fn properties(&self) -> Option<js_sys::Object> {
1461 self.0.properties().and_then(|props| {
1462 let arr = js_sys::Array::new();
1463
1464 for (key, value) in props.iter() {
1465 let tuple = js_sys::Array::new();
1466 tuple.push(&JsValue::from_str(key.as_ref()));
1467 tuple.push(&JsValue::from_str(value.as_ref()));
1468
1469 arr.push(&tuple);
1470 }
1471
1472 js_sys::Object::from_entries(&arr).ok()
1473 })
1474 }
1475
1476 pub fn get_property(&self, name: &str) -> Option<String> {
1478 self.0
1479 .properties()
1480 .and_then(|p| p.get(&Cow::from(name)).map(ToString::to_string))
1481 }
1482
1483 #[wasm_bindgen(getter)]
1485 pub fn scheme(&self) -> Option<String> {
1486 self.0.scheme().map(ToString::to_string)
1487 }
1488
1489 #[wasm_bindgen(getter)]
1491 pub fn date(&self) -> Option<String> {
1492 self.0.date().map(|x| x.format("%Y-%m-%d").to_string())
1493 }
1494
1495 #[wasm_bindgen(getter)]
1497 pub fn wiki_index(&self) -> Option<u32> {
1498 self.0.index()
1499 }
1500
1501 #[wasm_bindgen(getter)]
1503 pub fn wiki_name(&self) -> Option<String> {
1504 self.0.name().map(ToString::to_string)
1505 }
1506}
1507
1508#[wasm_bindgen]
1510pub struct Tags(v::Located<v::Tags<'static>>);
1511
1512#[wasm_bindgen]
1513impl Tags {
1514 #[allow(clippy::boxed_local)]
1516 #[wasm_bindgen(constructor)]
1517 pub fn new(
1518 array: Box<[JsValue]>,
1519 region: Option<Region>,
1520 ) -> Result<Tags, JsValue> {
1521 let tags: v::Tags =
1522 array.iter().filter_map(|x| x.as_string()).collect();
1523
1524 Ok(Self(v::Located::new(
1525 tags,
1526 region.map(|x| x.0).unwrap_or_default(),
1527 )))
1528 }
1529
1530 pub fn tag_at(&self, idx: usize) -> Option<Tag> {
1532 self.0.get(idx).map(|x| Tag(x.as_borrowed().into_owned()))
1533 }
1534
1535 #[wasm_bindgen(getter)]
1537 pub fn tag_cnt(&self) -> usize {
1538 self.0.len()
1539 }
1540
1541 pub fn to_str(&self) -> String {
1543 self.0.to_string()
1544 }
1545}
1546
1547#[wasm_bindgen]
1549pub struct Tag(v::Tag<'static>);
1550
1551#[wasm_bindgen]
1552impl Tag {
1553 pub fn new(txt: &str) -> Self {
1555 Self(v::Tag::from(txt).into_owned())
1556 }
1557
1558 pub fn to_str(&self) -> String {
1560 self.0.to_string()
1561 }
1562}
1563
1564#[wasm_bindgen]
1566pub struct CodeInline(v::Located<v::CodeInline<'static>>);
1567
1568#[wasm_bindgen]
1569impl CodeInline {
1570 #[wasm_bindgen(constructor)]
1572 pub fn new(txt: &str, region: Option<Region>) -> Self {
1573 Self(v::Located::new(
1574 v::CodeInline::new(Cow::from(txt)).into_owned(),
1575 region.map(|x| x.0).unwrap_or_default(),
1576 ))
1577 }
1578
1579 pub fn to_str(&self) -> String {
1581 self.0.to_string()
1582 }
1583}
1584
1585#[wasm_bindgen]
1587pub struct MathInline(v::Located<v::MathInline<'static>>);
1588
1589#[wasm_bindgen]
1590impl MathInline {
1591 #[wasm_bindgen(constructor)]
1593 pub fn new(txt: &str, region: Option<Region>) -> Self {
1594 Self(v::Located::new(
1595 v::MathInline::new(Cow::from(txt)).into_owned(),
1596 region.map(|x| x.0).unwrap_or_default(),
1597 ))
1598 }
1599
1600 pub fn to_str(&self) -> String {
1602 self.0.to_string()
1603 }
1604}
1605
1606#[wasm_bindgen]
1608pub struct Comment(v::Located<v::Comment<'static>>);
1609
1610#[wasm_bindgen]
1611impl Comment {
1612 #[wasm_bindgen(constructor)]
1615 pub fn new(txt: &str, multiline: bool, region: Option<Region>) -> Self {
1616 if multiline {
1617 Self(v::Located::new(
1618 v::Comment::MultiLine(v::MultiLineComment::new(
1619 txt.split('\n').map(Cow::from).collect(),
1620 ))
1621 .into_owned(),
1622 region.map(|x| x.0).unwrap_or_default(),
1623 ))
1624 } else {
1625 Self(v::Located::new(
1626 v::Comment::Line(v::LineComment::new(Cow::from(txt)))
1627 .into_owned(),
1628 region.map(|x| x.0).unwrap_or_default(),
1629 ))
1630 }
1631 }
1632
1633 pub fn line_at(&self, idx: usize) -> Option<String> {
1635 match self.0.as_inner() {
1636 v::Comment::Line(x) if idx == 0 => Some(x.to_string()),
1637 v::Comment::MultiLine(x) => x.get(idx).map(ToString::to_string),
1638 _ => None,
1639 }
1640 }
1641
1642 #[wasm_bindgen(getter)]
1644 pub fn line_cnt(&self) -> usize {
1645 match self.0.as_inner() {
1646 v::Comment::Line(_) => 1,
1647 v::Comment::MultiLine(x) => x.len(),
1648 }
1649 }
1650
1651 pub fn to_str(&self) -> String {
1653 self.0.to_string()
1654 }
1655}
1656
1657#[wasm_bindgen]
1659pub struct Text(v::Located<v::Text<'static>>);
1660
1661#[wasm_bindgen]
1662impl Text {
1663 #[wasm_bindgen(constructor)]
1665 pub fn new(txt: &str, region: Option<Region>) -> Self {
1666 Self(v::Located::new(
1667 v::Text::new(Cow::from(txt)).into_owned(),
1668 region.map(|x| x.0).unwrap_or_default(),
1669 ))
1670 }
1671
1672 pub fn to_str(&self) -> String {
1674 self.0.to_string()
1675 }
1676}
1677
1678#[wasm_bindgen]
1680pub struct Region(v::Region);
1681
1682#[wasm_bindgen]
1683impl Region {
1684 #[wasm_bindgen(constructor)]
1686 pub fn new(offset: usize, len: usize, depth: u16) -> Self {
1687 Self(v::Region::new_at_depth(offset, len, depth))
1688 }
1689
1690 #[wasm_bindgen(getter)]
1692 pub fn offset(&self) -> usize {
1693 self.0.offset()
1694 }
1695
1696 pub fn is_empty(&self) -> bool {
1698 self.0.is_empty()
1699 }
1700
1701 #[wasm_bindgen(getter)]
1703 pub fn len(&self) -> usize {
1704 self.0.len()
1705 }
1706
1707 #[wasm_bindgen(getter)]
1709 pub fn depth(&self) -> u16 {
1710 self.0.depth()
1711 }
1712}
1713
1714macro_rules! impl_from {
1720 (-@$name:ident $($tail:tt)*) => {
1721 impl From<v::$name> for $name {
1722 fn from(x: v::$name) -> Self {
1723 Self(x)
1724 }
1725 }
1726
1727 impl_from!($($tail)*);
1728 };
1729 (-$name:ident $($tail:tt)*) => {
1730 impl From<v::$name<'static>> for $name {
1731 fn from(x: v::$name<'static>) -> Self {
1732 Self(x)
1733 }
1734 }
1735
1736 impl_from!($($tail)*);
1737 };
1738 (@$name:ident $($tail:tt)*) => {
1739 impl From<v::Located<v::$name>> for $name {
1740 fn from(x: v::Located<v::$name>) -> Self {
1741 Self(x)
1742 }
1743 }
1744
1745 impl_from!($($tail)*);
1746 };
1747 ($name:ident $($tail:tt)*) => {
1748 impl From<v::Located<v::$name<'static>>> for $name {
1749 fn from(x: v::Located<v::$name<'static>>) -> Self {
1750 Self(x)
1751 }
1752 }
1753
1754 impl_from!($($tail)*);
1755 };
1756 () => {};
1757}
1758
1759impl_from!(
1760 -Page Element BlockElement InlineBlockElement InlineElement Blockquote
1761 CodeBlock DefinitionList @Divider Header List MathBlock Paragraph Table
1762 DecoratedText Link Tags CodeInline MathInline Comment Text
1763 -InlineElementContainer DecoratedTextContent ListItem ListItemContent
1764 Placeholder -@Region
1765);
1766
1767macro_rules! impl_convert {
1769 (@$name:ident $($tail:tt)*) => {
1770 #[wasm_bindgen]
1771 impl $name {
1772 pub fn to_js(&self) -> JsValue {
1774 JsValue::from_serde(&self.0).unwrap()
1775 }
1776
1777 pub fn to_debug_str(&self) -> String {
1779 format!("{:?}", self.0)
1780 }
1781 }
1782
1783 impl_convert!($($tail)*);
1784 };
1785 ($name:ident $($tail:tt)*) => {
1786 #[wasm_bindgen]
1787 impl $name {
1788 pub fn to_html_str(&self, config: &JsValue) -> Result<String, JsValue> {
1790 let config: v::HtmlConfig = if !config.is_undefined() && !config.is_null() {
1793 config.into_serde().map_err(|x| JsValue::from(x.to_string()))?
1794 } else {
1795 Default::default()
1796 };
1797
1798 self.0
1799 .to_html_string(config)
1800 .map_err(|x| x.to_string().into())
1801 }
1802 }
1803
1804 impl_convert!(@$name $($tail)*);
1805 };
1806 () => {};
1807}
1808
1809impl_convert!(
1810 Page Element BlockElement InlineBlockElement InlineElement Blockquote
1811 CodeBlock DefinitionList Divider Header List MathBlock Paragraph Table
1812 DecoratedText Link Tags CodeInline MathInline Comment Text
1813 InlineElementContainer DecoratedTextContent ListItem ListItemContent
1814 Placeholder @Region
1815);
1816
1817macro_rules! impl_iter {
1818 ($name:ident $($tail:tt)*) => {
1819 #[wasm_bindgen]
1820 impl $name {
1821 #[wasm_bindgen(getter)]
1823 pub fn children(&self) -> js_sys::Array {
1824 use vimwiki::IntoChildren;
1825 self.0
1826 .to_borrowed()
1827 .into_children()
1828 .into_iter()
1829 .map(|x| v::Located::new(
1830 v::Element::from(x.to_borrowed().into_owned()),
1831 x.region(),
1832 ))
1833 .map(Element::from)
1834 .map(JsValue::from)
1835 .collect()
1836 }
1837
1838 #[wasm_bindgen(getter)]
1840 pub fn descendants(&self) -> js_sys::Array {
1841 use vimwiki::IntoChildren;
1842
1843 let mut elements = Vec::new();
1845
1846 let mut queue: Vec<v::Located<v::Element<'_>>> = self.0
1848 .to_borrowed()
1849 .into_children()
1850 .into_iter()
1851 .map(|x| x.as_ref().map(
1852 |x| v::Element::from(x.to_borrowed().into_owned())
1853 ))
1854 .collect();
1855
1856 while !queue.is_empty() {
1857 let next = queue.remove(0);
1858 let children: Vec<v::Located<v::Element<'_>>> = next
1859 .as_inner()
1860 .clone()
1861 .into_children()
1862 .into_iter()
1863 .map(|x| x.as_ref().map(
1864 |x| v::Element::from(x.to_borrowed().into_owned()),
1865 ))
1866 .collect();
1867 elements.push(next);
1868 queue.extend(children);
1869 }
1870
1871 elements
1873 .into_iter()
1874 .map(Element::from)
1875 .map(JsValue::from)
1876 .collect()
1877 }
1878 }
1879
1880 impl_iter!($($tail)*);
1881 };
1882 () => {};
1883}
1884
1885impl_iter!(
1886 Page Element BlockElement InlineBlockElement InlineElement
1887 DefinitionList Header List Paragraph Table
1888 DecoratedText InlineElementContainer DecoratedTextContent ListItem
1889);
1890
1891macro_rules! impl_region {
1892 ($name:ident $($tail:tt)*) => {
1893 #[wasm_bindgen]
1894 impl $name {
1895 #[wasm_bindgen(getter)]
1897 pub fn region(&self) -> Region {
1898 Region(self.0.region())
1899 }
1900 }
1901
1902 impl_region!($($tail)*);
1903 };
1904 () => {};
1905}
1906
1907impl_region!(
1908 Element BlockElement InlineBlockElement InlineElement
1909
1910 Blockquote CodeBlock DefinitionList Divider Header List MathBlock
1911 Paragraph Placeholder Table
1912
1913 DecoratedText Link Tags CodeInline MathInline Comment Text
1914 DecoratedTextContent ListItem ListItemContent
1915);