1use std::{cell::RefCell, rc::Rc};
2
3use wasm_bindgen::prelude::*;
4
5#[derive(Clone, Debug)]
6#[wasm_bindgen(js_name = "MarkdownDoc")]
7pub struct WasmMarkdownDoc {
8 inner: Rc<RefCell<wowlab_common::markdown::Doc>>,
9}
10
11#[wasm_bindgen(js_class = "MarkdownDoc")]
12impl WasmMarkdownDoc {
13 #[wasm_bindgen(constructor)]
14 #[must_use]
15 pub fn new() -> Self {
16 Self {
17 inner: Rc::new(RefCell::new(wowlab_common::markdown::Doc::new())),
18 }
19 }
20
21 pub fn line(&self, text: &str) {
22 update_doc(&self.inner, |doc| doc.line(text));
23 }
24
25 pub fn blank(&self) {
26 update_doc(&self.inner, wowlab_common::markdown::Doc::blank);
27 }
28
29 pub fn heading(&self, level: u8, text: &str) {
30 update_doc(&self.inner, |doc| doc.heading(level, text));
31 }
32
33 pub fn h1(&self, text: &str) {
34 update_doc(&self.inner, |doc| doc.h1(text));
35 }
36
37 pub fn h2(&self, text: &str) {
38 update_doc(&self.inner, |doc| doc.h2(text));
39 }
40
41 pub fn h3(&self, text: &str) {
42 update_doc(&self.inner, |doc| doc.h3(text));
43 }
44
45 pub fn bullet(&self, text: &str) {
46 update_doc(&self.inner, |doc| doc.bullet(text));
47 }
48
49 #[wasm_bindgen(js_name = "kvBullet")]
50 pub fn kv_bullet(&self, key: &str, value: &str) {
51 update_doc(&self.inner, |doc| doc.kv_bullet(key, value));
52 }
53
54 pub fn def(&self, term: &str, desc: &str) {
55 update_doc(&self.inner, |doc| doc.def(term, desc));
56 }
57
58 #[wasm_bindgen(js_name = "defDetail")]
59 pub fn def_detail(&self, term: &str, detail: &str, desc: &str) {
60 update_doc(&self.inner, |doc| doc.def_detail(term, detail, desc));
61 }
62
63 #[wasm_bindgen(js_name = "codeBlock")]
64 pub fn code_block(&self, language: &str, content: &str) {
65 update_doc(&self.inner, |doc| doc.code_block(language, content));
66 }
67
68 pub fn raw(&self, text: &str) {
69 update_doc(&self.inner, |doc| doc.raw(text.to_string()));
70 }
71
72 #[must_use]
73 pub fn build(&self) -> String {
74 std::mem::take(&mut *self.inner.borrow_mut()).build()
75 }
76}
77
78impl Default for WasmMarkdownDoc {
79 fn default() -> Self {
80 Self::new()
81 }
82}
83
84#[derive(Clone, Debug)]
85#[wasm_bindgen(js_name = "MarkdownTable")]
86pub struct WasmMarkdownTable {
87 inner: Rc<RefCell<wowlab_common::markdown::Table>>,
88}
89
90#[wasm_bindgen(js_class = "MarkdownTable")]
91impl WasmMarkdownTable {
92 #[wasm_bindgen(constructor)]
93 #[must_use]
94 pub fn new() -> Self {
95 Self {
96 inner: Rc::new(RefCell::new(wowlab_common::markdown::Table::new())),
97 }
98 }
99
100 pub fn headers(&self, headers: Vec<String>) {
101 update_table(&self.inner, |table| table.headers(headers));
102 }
103
104 pub fn row(&self, values: Vec<String>) {
105 update_table(&self.inner, |table| table.row(values));
106 }
107
108 #[wasm_bindgen(js_name = "buildMarkdown")]
109 #[must_use]
110 pub fn build_markdown(&self) -> String {
111 std::mem::take(&mut *self.inner.borrow_mut()).build_markdown()
112 }
113
114 #[wasm_bindgen(js_name = "buildPlain")]
115 #[must_use]
116 pub fn build_plain(&self) -> String {
117 std::mem::take(&mut *self.inner.borrow_mut()).build_plain()
118 }
119}
120
121impl Default for WasmMarkdownTable {
122 fn default() -> Self {
123 Self::new()
124 }
125}
126
127fn update_doc(
128 doc: &RefCell<wowlab_common::markdown::Doc>,
129 update: impl FnOnce(wowlab_common::markdown::Doc) -> wowlab_common::markdown::Doc,
130) {
131 let current = std::mem::take(&mut *doc.borrow_mut());
132
133 *doc.borrow_mut() = update(current);
134}
135
136fn update_table(
137 table: &RefCell<wowlab_common::markdown::Table>,
138 update: impl FnOnce(wowlab_common::markdown::Table) -> wowlab_common::markdown::Table,
139) {
140 let current = std::mem::take(&mut *table.borrow_mut());
141
142 *table.borrow_mut() = update(current);
143}