anytomd 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,201 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "[]"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Copyright [yyyy] [name of copyright owner]
190
+
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.
package/README.md ADDED
@@ -0,0 +1,481 @@
1
+ # anytomd
2
+
3
+ A pure Rust tool and library that converts various document formats into Markdown — designed for LLM consumption.
4
+
5
+ [![CI](https://github.com/developer0hye/anytomd-rs/actions/workflows/ci.yml/badge.svg)](https://github.com/developer0hye/anytomd-rs/actions/workflows/ci.yml)
6
+ [![Crates.io](https://img.shields.io/crates/v/anytomd.svg)](https://crates.io/crates/anytomd)
7
+ [![License](https://img.shields.io/crates/l/anytomd.svg)](LICENSE)
8
+
9
+ ## Why?
10
+
11
+ [MarkItDown](https://github.com/microsoft/markitdown) is a great Python library for converting documents to Markdown. But integrating Python into Rust applications means bundling a Python runtime (~50 MB), dealing with cross-platform compatibility issues, and managing dependency hell.
12
+
13
+ **anytomd** solves this with a single `cargo add anytomd` — zero external runtime, no C bindings, no subprocess calls. Just pure Rust.
14
+
15
+ ## Supported Formats
16
+
17
+ | Format | Extensions | Notes |
18
+ |--------|-----------|-------|
19
+ | DOCX | `.docx` | Headings, tables, lists, bold/italic, hyperlinks, images, text boxes |
20
+ | PPTX | `.pptx` | Slides, tables, speaker notes, images, group shapes |
21
+ | XLSX | `.xlsx` | Multi-sheet, date/time handling, images |
22
+ | XLS | `.xls` | Legacy Excel (via calamine) |
23
+ | HTML | `.html`, `.htm` | Full DOM: headings, tables, lists, links, blockquotes, code blocks |
24
+ | CSV | `.csv` | Converted to Markdown tables |
25
+ | Jupyter Notebook | `.ipynb` | Markdown cells preserved, code cells in fenced blocks with language detection |
26
+ | JSON | `.json` | Pretty-printed in fenced code blocks |
27
+ | XML | `.xml` | Pretty-printed in fenced code blocks |
28
+ | Images | `.png`, `.jpg`, `.gif`, `.webp`, `.bmp`, `.tiff`, `.svg`, `.heic`, `.avif` | Optional LLM-based alt text via `ImageDescriber` |
29
+ | Code | `.py`, `.rs`, `.js`, `.ts`, `.c`, `.cpp`, `.go`, `.java`, `.rb`, `.swift`, `.sh`, ... | Fenced code blocks with language identifier |
30
+ | Plain Text | `.txt`, `.md`, `.rst`, `.log`, `.toml`, `.yaml`, `.ini`, etc. | Passthrough with encoding detection (UTF-8, UTF-16, Windows-1252) |
31
+
32
+ **Note on PDF:** PDF conversion is intentionally out of scope. Gemini, ChatGPT, and Claude already provide native PDF support (with plan/model-specific limits), so anytomd focuses on formats that still benefit from dedicated Markdown conversion. Attempting to convert a PDF will return a descriptive `FormatNotSupported` error.
33
+
34
+ Format is auto-detected from magic bytes and file extension. ZIP-based formats (DOCX/PPTX/XLSX) are distinguished by inspecting internal archive structure.
35
+
36
+ ## Conversion Examples
37
+
38
+ ### CSV
39
+
40
+ A CSV file with multilingual data:
41
+
42
+ ```
43
+ Name,Age,City
44
+ Alice,30,Seoul
45
+ Bob,25,東京
46
+ Charlie,35,New York
47
+ 다영,28,서울
48
+ ```
49
+
50
+ **Output:**
51
+
52
+ ```markdown
53
+ | Name | Age | City |
54
+ |---|---|---|
55
+ | Alice | 30 | Seoul |
56
+ | Bob | 25 | 東京 |
57
+ | Charlie | 35 | New York |
58
+ | 다영 | 28 | 서울 |
59
+ ```
60
+
61
+ ### DOCX
62
+
63
+ A Word document with headings, links, Korean text, and emoji:
64
+
65
+ **Output:**
66
+
67
+ ```markdown
68
+ # Sample Document
69
+
70
+ This is a simple paragraph.
71
+
72
+ ## Section One
73
+
74
+ Visit [Example](https://example.com) for more info.
75
+
76
+ Korean: 한국어 테스트
77
+
78
+ Emoji: 🚀✨🌍
79
+
80
+ ### Subsection
81
+
82
+ Final paragraph with mixed content.
83
+ ```
84
+
85
+ ### PPTX
86
+
87
+ A PowerPoint presentation with slides, tables, speaker notes, and multilingual content:
88
+
89
+ **Output:**
90
+
91
+ ```markdown
92
+ ## Slide 1: Sample Presentation
93
+
94
+ Welcome to the presentation.
95
+
96
+ ---
97
+
98
+ ## Slide 2
99
+
100
+ Data Overview
101
+
102
+ | Name | Value | Status |
103
+ |---|---|---|
104
+ | Alpha | 100 | Active |
105
+ | Beta | 200 | Inactive |
106
+ | Gamma | 300 | Active |
107
+
108
+ > Note: Remember to explain the data table.
109
+
110
+ ---
111
+
112
+ ## Slide 3: Multilingual
113
+
114
+ 한국어 테스트
115
+ 🚀✨🌍
116
+
117
+ > Note: Test multilingual rendering.
118
+ ```
119
+
120
+ ## Installation
121
+
122
+ ### Rust (Cargo)
123
+
124
+ ```sh
125
+ cargo add anytomd
126
+ ```
127
+
128
+ ### npm (WASM)
129
+
130
+ ```sh
131
+ npm install anytomd
132
+ ```
133
+
134
+ ```js
135
+ import init, { convertBytes } from 'anytomd';
136
+
137
+ await init();
138
+
139
+ const response = await fetch('document.docx');
140
+ const bytes = new Uint8Array(await response.arrayBuffer());
141
+
142
+ const result = convertBytes(bytes, 'docx');
143
+ console.log(result.markdown);
144
+ ```
145
+
146
+ ### Feature Flags
147
+
148
+ | Feature | Dependencies | Description |
149
+ |---------|-------------|-------------|
150
+ | *(default)* | `async-gemini` | Async API + `AsyncGeminiDescriber` — all async features enabled out of the box |
151
+ | `async` | `futures-util` | Async API (`convert_file_async`, `convert_bytes_async`, `AsyncImageDescriber` trait) |
152
+ | `async-gemini` | `async` + `reqwest` | `AsyncGeminiDescriber` for concurrent image descriptions via Gemini |
153
+ | `wasm` | `wasm-bindgen`, `js-sys`, `wasm-bindgen-futures` | WebAssembly bindings (`convertBytes`, `convertBytesWithOptions`) for browser/edge use |
154
+ | `wasm` + `async-gemini` | *(combined)* | Adds `convertBytesWithGemini` for async Gemini-powered conversion in WASM |
155
+
156
+ Async features are included by default. To opt out:
157
+
158
+ ```toml
159
+ anytomd = { version = "1", default-features = false }
160
+ ```
161
+
162
+ ## WebAssembly (WASM)
163
+
164
+ anytomd compiles to `wasm32-unknown-unknown`, enabling client-side document conversion in browsers, Cloudflare Workers, Deno Deploy, and other edge runtimes. Documents never leave the user's device.
165
+
166
+ ### Build
167
+
168
+ ```sh
169
+ # Basic WASM build (sync conversion only)
170
+ wasm-pack build --target web --no-default-features --features wasm
171
+
172
+ # With Gemini async image descriptions
173
+ wasm-pack build --target web --no-default-features --features wasm,async-gemini
174
+ ```
175
+
176
+ ### Usage from JavaScript
177
+
178
+ ```js
179
+ import init, { convertBytes } from './pkg/anytomd.js';
180
+
181
+ await init();
182
+
183
+ const response = await fetch('document.docx');
184
+ const bytes = new Uint8Array(await response.arrayBuffer());
185
+
186
+ const result = convertBytes(bytes, 'docx');
187
+ console.log(result.markdown);
188
+ console.log(result.plainText);
189
+ console.log(result.title); // string or null
190
+ console.log(result.warnings); // string[]
191
+ ```
192
+
193
+ #### With Gemini Image Descriptions (requires `wasm` + `async-gemini` features)
194
+
195
+ ```js
196
+ import init, { convertBytesWithGemini } from './pkg/anytomd.js';
197
+
198
+ await init();
199
+
200
+ const response = await fetch('presentation.pptx');
201
+ const bytes = new Uint8Array(await response.arrayBuffer());
202
+
203
+ // Images are described concurrently via the Gemini API
204
+ const result = await convertBytesWithGemini(bytes, 'pptx', 'your-gemini-api-key');
205
+ console.log(result.markdown); // images have LLM-generated alt text
206
+ ```
207
+
208
+ ### WASM API Availability
209
+
210
+ | API | Native | WASM |
211
+ |-----|--------|------|
212
+ | `convert_bytes` / `convertBytes` | Yes | Yes |
213
+ | `convert_bytes_async` | Yes | Yes |
214
+ | `convert_file` / `convert_file_async` | Yes | No (no filesystem) |
215
+ | `GeminiDescriber` (sync) | Yes | No (uses `ureq`) |
216
+ | `AsyncGeminiDescriber` / `convertBytesWithGemini` | Yes | Yes (`wasm` + `async-gemini`) |
217
+
218
+ All 12 format converters work on WASM via `convert_bytes`.
219
+
220
+ ## CLI
221
+
222
+ ### Install
223
+
224
+ ```sh
225
+ cargo install anytomd
226
+ ```
227
+
228
+ ### Usage
229
+
230
+ ```sh
231
+ # Convert a single file
232
+ anytomd document.docx > output.md
233
+
234
+ # Convert multiple files (separated by <!-- source: path --> comments)
235
+ anytomd report.docx data.csv slides.pptx > combined.md
236
+
237
+ # Write output to a file
238
+ anytomd document.docx -o output.md
239
+
240
+ # Read from stdin (--format is required)
241
+ cat data.csv | anytomd --format csv
242
+
243
+ # Override format detection
244
+ anytomd --format html page.dat
245
+
246
+ # Strict mode: treat recoverable errors as hard errors
247
+ anytomd --strict document.docx
248
+
249
+ # Plain text output (Markdown formatting stripped)
250
+ anytomd --plain-text document.docx
251
+
252
+ # Plain text from stdin
253
+ echo "Name,Age" | anytomd --format csv --plain-text
254
+
255
+ # Auto image descriptions (just set GEMINI_API_KEY)
256
+ export GEMINI_API_KEY=your-key
257
+ anytomd presentation.pptx
258
+ ```
259
+
260
+ ### Exit Codes
261
+
262
+ | Code | Meaning |
263
+ |------|---------|
264
+ | 0 | Success |
265
+ | 1 | Conversion failure |
266
+ | 2 | Invalid arguments |
267
+
268
+ ## Quick Start (Library)
269
+
270
+ ```rust
271
+ use anytomd::{convert_file, convert_bytes, ConversionOptions};
272
+
273
+ // Convert a file (format auto-detected from extension and magic bytes)
274
+ let options = ConversionOptions::default();
275
+ let result = convert_file("document.docx", &options).unwrap();
276
+ println!("{}", result.markdown);
277
+
278
+ // Convert raw bytes with an explicit format
279
+ let csv_data = b"Name,Age\nAlice,30\nBob,25";
280
+ let result = convert_bytes(csv_data, "csv", &options).unwrap();
281
+ println!("{}", result.markdown);
282
+ ```
283
+
284
+ ### Plain Text Output
285
+
286
+ Every conversion produces both Markdown and plain text output. The plain text is extracted directly from the source document — no post-processing or markdown stripping — so source characters like `**kwargs` or `# comment` are preserved exactly.
287
+
288
+ ```rust
289
+ use anytomd::{convert_file, ConversionOptions};
290
+
291
+ let result = convert_file("document.docx", &ConversionOptions::default()).unwrap();
292
+
293
+ // Markdown output
294
+ println!("{}", result.markdown);
295
+
296
+ // Plain text output (no headings, bold, tables, code fences, etc.)
297
+ println!("{}", result.plain_text);
298
+ ```
299
+
300
+ ### Extracting Embedded Images
301
+
302
+ ```rust
303
+ use anytomd::{convert_file, ConversionOptions};
304
+
305
+ let options = ConversionOptions {
306
+ extract_images: true,
307
+ ..Default::default()
308
+ };
309
+ let result = convert_file("presentation.pptx", &options).unwrap();
310
+
311
+ for (filename, bytes) in &result.images {
312
+ std::fs::write(filename, bytes).unwrap();
313
+ }
314
+ ```
315
+
316
+ ### LLM-Based Image Descriptions
317
+
318
+ anytomd can generate alt text for images using any LLM backend via the `ImageDescriber` trait. A built-in Google Gemini implementation is included.
319
+
320
+ ```rust
321
+ use std::sync::Arc;
322
+ use anytomd::{convert_file, ConversionOptions, ImageDescriber, ConvertError};
323
+ use anytomd::gemini::GeminiDescriber;
324
+
325
+ // Option 1: Use the built-in Gemini describer
326
+ let describer = GeminiDescriber::from_env() // reads GEMINI_API_KEY
327
+ .unwrap()
328
+ .with_model("gemini-3-flash-preview".to_string());
329
+
330
+ let options = ConversionOptions {
331
+ image_describer: Some(Arc::new(describer)),
332
+ ..Default::default()
333
+ };
334
+ let result = convert_file("document.docx", &options).unwrap();
335
+ // Images now have LLM-generated alt text: ![A chart showing quarterly revenue](chart.png)
336
+
337
+ // Option 2: Implement your own describer for any backend
338
+ struct MyDescriber;
339
+
340
+ impl ImageDescriber for MyDescriber {
341
+ fn describe(
342
+ &self,
343
+ image_bytes: &[u8],
344
+ mime_type: &str,
345
+ prompt: &str,
346
+ ) -> Result<String, ConvertError> {
347
+ // Call your preferred LLM API here
348
+ Ok("description of the image".to_string())
349
+ }
350
+ }
351
+ ```
352
+
353
+ ### Async Image Descriptions
354
+
355
+ For documents with many images, the async API resolves all descriptions concurrently. Included by default since v0.11.0.
356
+
357
+ ```rust
358
+ use std::sync::Arc;
359
+ use anytomd::{convert_file_async, AsyncConversionOptions, AsyncImageDescriber, ConvertError};
360
+ use anytomd::gemini::AsyncGeminiDescriber;
361
+
362
+ #[tokio::main]
363
+ async fn main() {
364
+ let describer = AsyncGeminiDescriber::from_env().unwrap();
365
+
366
+ let options = AsyncConversionOptions {
367
+ async_image_describer: Some(Arc::new(describer)),
368
+ ..Default::default()
369
+ };
370
+
371
+ let result = convert_file_async("presentation.pptx", &options).await.unwrap();
372
+ println!("{}", result.markdown);
373
+ // All images described concurrently — significant speedup for multi-image documents
374
+ }
375
+ ```
376
+
377
+ The library has no `tokio` dependency — the caller provides the async runtime. Any runtime (`tokio`, `async-std`, etc.) works.
378
+
379
+ ## API
380
+
381
+ ### `convert_file`
382
+
383
+ ```rust
384
+ /// Convert a file at the given path to Markdown.
385
+ /// Format is auto-detected from magic bytes and file extension.
386
+ pub fn convert_file(
387
+ path: impl AsRef<Path>,
388
+ options: &ConversionOptions,
389
+ ) -> Result<ConversionResult, ConvertError>
390
+ ```
391
+
392
+ ### `convert_bytes`
393
+
394
+ ```rust
395
+ /// Convert raw bytes to Markdown with an explicit format extension.
396
+ pub fn convert_bytes(
397
+ data: &[u8],
398
+ extension: &str,
399
+ options: &ConversionOptions,
400
+ ) -> Result<ConversionResult, ConvertError>
401
+ ```
402
+
403
+ ### `convert_file_async`
404
+
405
+ Included by default (requires the `async` feature if default features are disabled).
406
+
407
+ ```rust
408
+ /// Convert a file at the given path to Markdown with async image description.
409
+ /// If an async_image_describer is set, all image descriptions are resolved concurrently.
410
+ pub async fn convert_file_async(
411
+ path: impl AsRef<Path>,
412
+ options: &AsyncConversionOptions,
413
+ ) -> Result<ConversionResult, ConvertError>
414
+ ```
415
+
416
+ ### `convert_bytes_async`
417
+
418
+ Included by default (requires the `async` feature if default features are disabled).
419
+
420
+ ```rust
421
+ /// Convert raw bytes to Markdown with async image description.
422
+ pub async fn convert_bytes_async(
423
+ data: &[u8],
424
+ extension: &str,
425
+ options: &AsyncConversionOptions,
426
+ ) -> Result<ConversionResult, ConvertError>
427
+ ```
428
+
429
+ ### `ConversionOptions`
430
+
431
+ | Field | Type | Default | Description |
432
+ |-------|------|---------|-------------|
433
+ | `extract_images` | `bool` | `false` | Extract embedded images into `result.images` |
434
+ | `max_total_image_bytes` | `usize` | 50 MB | Hard cap for total extracted image bytes |
435
+ | `max_input_bytes` | `usize` | 100 MB | Maximum input file size |
436
+ | `max_uncompressed_zip_bytes` | `usize` | 500 MB | ZIP bomb guard |
437
+ | `strict` | `bool` | `false` | Error on recoverable failures instead of warnings |
438
+ | `image_describer` | `Option<Arc<dyn ImageDescriber>>` | `None` | LLM backend for image alt text generation |
439
+
440
+ ### `ConversionResult`
441
+
442
+ ```rust
443
+ pub struct ConversionResult {
444
+ pub markdown: String, // The converted Markdown
445
+ pub plain_text: String, // Plain text (extracted directly, no markdown syntax)
446
+ pub title: Option<String>, // Document title, if detected
447
+ pub images: Vec<(String, Vec<u8>)>, // Extracted images (filename, bytes)
448
+ pub warnings: Vec<ConversionWarning>, // Recoverable issues encountered
449
+ }
450
+ ```
451
+
452
+ ### Error Handling
453
+
454
+ Conversion is **best-effort** by default. If a single element fails to parse (e.g., a corrupted table), it is skipped and a warning is added to `result.warnings`. The rest of the document is still converted.
455
+
456
+ Set `strict: true` in `ConversionOptions` to turn recoverable failures into errors instead.
457
+
458
+ Warning codes: `SkippedElement`, `UnsupportedFeature`, `ResourceLimitReached`, `MalformedSegment`.
459
+
460
+ ## Development
461
+
462
+ ### Build and Test
463
+
464
+ ```sh
465
+ cargo build && cargo test && cargo clippy -- -D warnings
466
+ ```
467
+
468
+ ### Docker
469
+
470
+ A Docker environment is available for reproducible Linux builds:
471
+
472
+ ```sh
473
+ docker compose run --rm verify # Full loop: fmt + clippy + test + release build
474
+ docker compose run --rm test # Run all tests
475
+ docker compose run --rm lint # clippy + fmt check
476
+ docker compose run --rm shell # Interactive bash
477
+ ```
478
+
479
+ ## License
480
+
481
+ Apache-2.0
package/anytomd.d.ts ADDED
@@ -0,0 +1,54 @@
1
+ /* tslint:disable */
2
+ /* eslint-disable */
3
+
4
+ /**
5
+ * Convert raw document bytes to Markdown from JavaScript.
6
+ *
7
+ * # Arguments
8
+ *
9
+ * * `data` - Raw file bytes as a `Uint8Array`
10
+ * * `extension` - File format extension (e.g., `"docx"`, `"csv"`, `"html"`)
11
+ *
12
+ * # Returns
13
+ *
14
+ * A JS object with fields: `markdown` (string), `plainText` (string),
15
+ * `title` (string or null), `warnings` (array of strings).
16
+ */
17
+ export function convertBytes(data: Uint8Array, extension: string): any;
18
+
19
+ /**
20
+ * Convert raw document bytes to Markdown with Gemini-powered image descriptions.
21
+ *
22
+ * This is an async function that creates an `AsyncGeminiDescriber` with the
23
+ * given API key and uses `convert_bytes_async` to resolve image descriptions
24
+ * concurrently via the Gemini API.
25
+ *
26
+ * # Arguments
27
+ *
28
+ * * `data` - Raw file bytes as a `Uint8Array`
29
+ * * `extension` - File format extension (e.g., `"docx"`, `"pptx"`, `"xlsx"`)
30
+ * * `api_key` - Google Gemini API key
31
+ * * `model` - Optional Gemini model name (defaults to `gemini-3-flash-preview`)
32
+ *
33
+ * # Returns
34
+ *
35
+ * A Promise that resolves to a JS object with fields: `markdown` (string),
36
+ * `plainText` (string), `title` (string or null), `warnings` (array of strings).
37
+ */
38
+ export function convertBytesWithGemini(data: Uint8Array, extension: string, api_key: string, model?: string | null): Promise<any>;
39
+
40
+ /**
41
+ * Convert raw document bytes to Markdown with options from JavaScript.
42
+ *
43
+ * # Arguments
44
+ *
45
+ * * `data` - Raw file bytes as a `Uint8Array`
46
+ * * `extension` - File format extension (e.g., `"docx"`, `"csv"`, `"html"`)
47
+ * * `strict` - If `true`, treat recoverable parse errors as hard errors
48
+ *
49
+ * # Returns
50
+ *
51
+ * A JS object with fields: `markdown` (string), `plainText` (string),
52
+ * `title` (string or null), `warnings` (array of strings).
53
+ */
54
+ export function convertBytesWithOptions(data: Uint8Array, extension: string, strict: boolean): any;
package/anytomd.js ADDED
@@ -0,0 +1,9 @@
1
+ /* @ts-self-types="./anytomd.d.ts" */
2
+
3
+ import * as wasm from "./anytomd_bg.wasm";
4
+ import { __wbg_set_wasm } from "./anytomd_bg.js";
5
+ __wbg_set_wasm(wasm);
6
+ wasm.__wbindgen_start();
7
+ export {
8
+ convertBytes, convertBytesWithGemini, convertBytesWithOptions
9
+ } from "./anytomd_bg.js";
package/anytomd_bg.js ADDED
@@ -0,0 +1,610 @@
1
+ /**
2
+ * Convert raw document bytes to Markdown from JavaScript.
3
+ *
4
+ * # Arguments
5
+ *
6
+ * * `data` - Raw file bytes as a `Uint8Array`
7
+ * * `extension` - File format extension (e.g., `"docx"`, `"csv"`, `"html"`)
8
+ *
9
+ * # Returns
10
+ *
11
+ * A JS object with fields: `markdown` (string), `plainText` (string),
12
+ * `title` (string or null), `warnings` (array of strings).
13
+ * @param {Uint8Array} data
14
+ * @param {string} extension
15
+ * @returns {any}
16
+ */
17
+ export function convertBytes(data, extension) {
18
+ const ptr0 = passArray8ToWasm0(data, wasm.__wbindgen_malloc);
19
+ const len0 = WASM_VECTOR_LEN;
20
+ const ptr1 = passStringToWasm0(extension, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
21
+ const len1 = WASM_VECTOR_LEN;
22
+ const ret = wasm.convertBytes(ptr0, len0, ptr1, len1);
23
+ if (ret[2]) {
24
+ throw takeFromExternrefTable0(ret[1]);
25
+ }
26
+ return takeFromExternrefTable0(ret[0]);
27
+ }
28
+
29
+ /**
30
+ * Convert raw document bytes to Markdown with Gemini-powered image descriptions.
31
+ *
32
+ * This is an async function that creates an `AsyncGeminiDescriber` with the
33
+ * given API key and uses `convert_bytes_async` to resolve image descriptions
34
+ * concurrently via the Gemini API.
35
+ *
36
+ * # Arguments
37
+ *
38
+ * * `data` - Raw file bytes as a `Uint8Array`
39
+ * * `extension` - File format extension (e.g., `"docx"`, `"pptx"`, `"xlsx"`)
40
+ * * `api_key` - Google Gemini API key
41
+ * * `model` - Optional Gemini model name (defaults to `gemini-3-flash-preview`)
42
+ *
43
+ * # Returns
44
+ *
45
+ * A Promise that resolves to a JS object with fields: `markdown` (string),
46
+ * `plainText` (string), `title` (string or null), `warnings` (array of strings).
47
+ * @param {Uint8Array} data
48
+ * @param {string} extension
49
+ * @param {string} api_key
50
+ * @param {string | null} [model]
51
+ * @returns {Promise<any>}
52
+ */
53
+ export function convertBytesWithGemini(data, extension, api_key, model) {
54
+ const ptr0 = passArray8ToWasm0(data, wasm.__wbindgen_malloc);
55
+ const len0 = WASM_VECTOR_LEN;
56
+ const ptr1 = passStringToWasm0(extension, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
57
+ const len1 = WASM_VECTOR_LEN;
58
+ const ptr2 = passStringToWasm0(api_key, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
59
+ const len2 = WASM_VECTOR_LEN;
60
+ var ptr3 = isLikeNone(model) ? 0 : passStringToWasm0(model, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
61
+ var len3 = WASM_VECTOR_LEN;
62
+ const ret = wasm.convertBytesWithGemini(ptr0, len0, ptr1, len1, ptr2, len2, ptr3, len3);
63
+ return ret;
64
+ }
65
+
66
+ /**
67
+ * Convert raw document bytes to Markdown with options from JavaScript.
68
+ *
69
+ * # Arguments
70
+ *
71
+ * * `data` - Raw file bytes as a `Uint8Array`
72
+ * * `extension` - File format extension (e.g., `"docx"`, `"csv"`, `"html"`)
73
+ * * `strict` - If `true`, treat recoverable parse errors as hard errors
74
+ *
75
+ * # Returns
76
+ *
77
+ * A JS object with fields: `markdown` (string), `plainText` (string),
78
+ * `title` (string or null), `warnings` (array of strings).
79
+ * @param {Uint8Array} data
80
+ * @param {string} extension
81
+ * @param {boolean} strict
82
+ * @returns {any}
83
+ */
84
+ export function convertBytesWithOptions(data, extension, strict) {
85
+ const ptr0 = passArray8ToWasm0(data, wasm.__wbindgen_malloc);
86
+ const len0 = WASM_VECTOR_LEN;
87
+ const ptr1 = passStringToWasm0(extension, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
88
+ const len1 = WASM_VECTOR_LEN;
89
+ const ret = wasm.convertBytesWithOptions(ptr0, len0, ptr1, len1, strict);
90
+ if (ret[2]) {
91
+ throw takeFromExternrefTable0(ret[1]);
92
+ }
93
+ return takeFromExternrefTable0(ret[0]);
94
+ }
95
+ export function __wbg_Error_ecbf49c1b9d07c30(arg0, arg1) {
96
+ const ret = Error(getStringFromWasm0(arg0, arg1));
97
+ return ret;
98
+ }
99
+ export function __wbg___wbindgen_debug_string_43c7ccb034739216(arg0, arg1) {
100
+ const ret = debugString(arg1);
101
+ const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
102
+ const len1 = WASM_VECTOR_LEN;
103
+ getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
104
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
105
+ }
106
+ export function __wbg___wbindgen_is_function_18bea6e84080c016(arg0) {
107
+ const ret = typeof(arg0) === 'function';
108
+ return ret;
109
+ }
110
+ export function __wbg___wbindgen_is_object_8d3fac158b36498d(arg0) {
111
+ const val = arg0;
112
+ const ret = typeof(val) === 'object' && val !== null;
113
+ return ret;
114
+ }
115
+ export function __wbg___wbindgen_is_undefined_4a711ea9d2e1ef93(arg0) {
116
+ const ret = arg0 === undefined;
117
+ return ret;
118
+ }
119
+ export function __wbg___wbindgen_string_get_d09f733449cbf7a2(arg0, arg1) {
120
+ const obj = arg1;
121
+ const ret = typeof(obj) === 'string' ? obj : undefined;
122
+ var ptr1 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
123
+ var len1 = WASM_VECTOR_LEN;
124
+ getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
125
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
126
+ }
127
+ export function __wbg___wbindgen_throw_df03e93053e0f4bc(arg0, arg1) {
128
+ throw new Error(getStringFromWasm0(arg0, arg1));
129
+ }
130
+ export function __wbg__wbg_cb_unref_9f02ce912168c354(arg0) {
131
+ arg0._wbg_cb_unref();
132
+ }
133
+ export function __wbg_abort_7100d741d811fdb2(arg0, arg1) {
134
+ arg0.abort(arg1);
135
+ }
136
+ export function __wbg_abort_bf4dbbb6563f9ad6(arg0) {
137
+ arg0.abort();
138
+ }
139
+ export function __wbg_append_057d2867b781cdc3() { return handleError(function (arg0, arg1, arg2, arg3, arg4) {
140
+ arg0.append(getStringFromWasm0(arg1, arg2), getStringFromWasm0(arg3, arg4));
141
+ }, arguments); }
142
+ export function __wbg_call_85e5437fa1ab109d() { return handleError(function (arg0, arg1, arg2) {
143
+ const ret = arg0.call(arg1, arg2);
144
+ return ret;
145
+ }, arguments); }
146
+ export function __wbg_call_df7a43aecab856a8() { return handleError(function (arg0, arg1) {
147
+ const ret = arg0.call(arg1);
148
+ return ret;
149
+ }, arguments); }
150
+ export function __wbg_clearTimeout_6b8d9a38b9263d65(arg0) {
151
+ const ret = clearTimeout(arg0);
152
+ return ret;
153
+ }
154
+ export function __wbg_done_0ad70482cae88a68(arg0) {
155
+ const ret = arg0.done;
156
+ return ret;
157
+ }
158
+ export function __wbg_fetch_8508e14acc7090e7(arg0, arg1) {
159
+ const ret = arg0.fetch(arg1);
160
+ return ret;
161
+ }
162
+ export function __wbg_fetch_9dad4fe911207b37(arg0) {
163
+ const ret = fetch(arg0);
164
+ return ret;
165
+ }
166
+ export function __wbg_get_6f5cf69c8f3f094a() { return handleError(function (arg0, arg1) {
167
+ const ret = Reflect.get(arg0, arg1);
168
+ return ret;
169
+ }, arguments); }
170
+ export function __wbg_has_393943c179c58bfe() { return handleError(function (arg0, arg1) {
171
+ const ret = Reflect.has(arg0, arg1);
172
+ return ret;
173
+ }, arguments); }
174
+ export function __wbg_headers_5960155bb72206d7(arg0) {
175
+ const ret = arg0.headers;
176
+ return ret;
177
+ }
178
+ export function __wbg_instanceof_Response_4d70bea95d48a514(arg0) {
179
+ let result;
180
+ try {
181
+ result = arg0 instanceof Response;
182
+ } catch (_) {
183
+ result = false;
184
+ }
185
+ const ret = result;
186
+ return ret;
187
+ }
188
+ export function __wbg_iterator_e77d2b7575cca5a7() {
189
+ const ret = Symbol.iterator;
190
+ return ret;
191
+ }
192
+ export function __wbg_new_62f131e968c83d75() {
193
+ const ret = new Object();
194
+ return ret;
195
+ }
196
+ export function __wbg_new_66075f8c2ea6575e() {
197
+ const ret = new Array();
198
+ return ret;
199
+ }
200
+ export function __wbg_new_a23ce0a01d189235() { return handleError(function () {
201
+ const ret = new Headers();
202
+ return ret;
203
+ }, arguments); }
204
+ export function __wbg_new_eb8f6841a0421871() { return handleError(function () {
205
+ const ret = new AbortController();
206
+ return ret;
207
+ }, arguments); }
208
+ export function __wbg_new_from_slice_e98c2bb0a59c32a0(arg0, arg1) {
209
+ const ret = new Uint8Array(getArrayU8FromWasm0(arg0, arg1));
210
+ return ret;
211
+ }
212
+ export function __wbg_new_typed_893dbec5fe999814(arg0, arg1) {
213
+ try {
214
+ var state0 = {a: arg0, b: arg1};
215
+ var cb0 = (arg0, arg1) => {
216
+ const a = state0.a;
217
+ state0.a = 0;
218
+ try {
219
+ return wasm_bindgen__convert__closures_____invoke__h2deb7db8ea6922c5(a, state0.b, arg0, arg1);
220
+ } finally {
221
+ state0.a = a;
222
+ }
223
+ };
224
+ const ret = new Promise(cb0);
225
+ return ret;
226
+ } finally {
227
+ state0.a = state0.b = 0;
228
+ }
229
+ }
230
+ export function __wbg_new_with_str_and_init_ccd7de5a7b7630b8() { return handleError(function (arg0, arg1, arg2) {
231
+ const ret = new Request(getStringFromWasm0(arg0, arg1), arg2);
232
+ return ret;
233
+ }, arguments); }
234
+ export function __wbg_next_5428439dfc1d0362() { return handleError(function (arg0) {
235
+ const ret = arg0.next();
236
+ return ret;
237
+ }, arguments); }
238
+ export function __wbg_next_d314789a105729f3(arg0) {
239
+ const ret = arg0.next;
240
+ return ret;
241
+ }
242
+ export function __wbg_push_960865cda81df836(arg0, arg1) {
243
+ const ret = arg0.push(arg1);
244
+ return ret;
245
+ }
246
+ export function __wbg_queueMicrotask_622e69f0935dfab2(arg0) {
247
+ const ret = arg0.queueMicrotask;
248
+ return ret;
249
+ }
250
+ export function __wbg_queueMicrotask_d0528786d26e067c(arg0) {
251
+ queueMicrotask(arg0);
252
+ }
253
+ export function __wbg_resolve_d170483d75a2c8a1(arg0) {
254
+ const ret = Promise.resolve(arg0);
255
+ return ret;
256
+ }
257
+ export function __wbg_setTimeout_f757f00851f76c42(arg0, arg1) {
258
+ const ret = setTimeout(arg0, arg1);
259
+ return ret;
260
+ }
261
+ export function __wbg_set_8326741805409e83() { return handleError(function (arg0, arg1, arg2) {
262
+ const ret = Reflect.set(arg0, arg1, arg2);
263
+ return ret;
264
+ }, arguments); }
265
+ export function __wbg_set_body_d3bfb0ba84038563(arg0, arg1) {
266
+ arg0.body = arg1;
267
+ }
268
+ export function __wbg_set_cache_d7fd96d5c85d5834(arg0, arg1) {
269
+ arg0.cache = __wbindgen_enum_RequestCache[arg1];
270
+ }
271
+ export function __wbg_set_credentials_75d65e7cc277aad0(arg0, arg1) {
272
+ arg0.credentials = __wbindgen_enum_RequestCredentials[arg1];
273
+ }
274
+ export function __wbg_set_headers_e4e56fe005f0b5c9(arg0, arg1) {
275
+ arg0.headers = arg1;
276
+ }
277
+ export function __wbg_set_method_e1291768ddb1e35e(arg0, arg1, arg2) {
278
+ arg0.method = getStringFromWasm0(arg1, arg2);
279
+ }
280
+ export function __wbg_set_mode_1fcb26983836e884(arg0, arg1) {
281
+ arg0.mode = __wbindgen_enum_RequestMode[arg1];
282
+ }
283
+ export function __wbg_set_signal_4e03877dd7f2cd34(arg0, arg1) {
284
+ arg0.signal = arg1;
285
+ }
286
+ export function __wbg_signal_065197e577ceaa9e(arg0) {
287
+ const ret = arg0.signal;
288
+ return ret;
289
+ }
290
+ export function __wbg_static_accessor_GLOBAL_THIS_6614f2f4998e3c4c() {
291
+ const ret = typeof globalThis === 'undefined' ? null : globalThis;
292
+ return isLikeNone(ret) ? 0 : addToExternrefTable0(ret);
293
+ }
294
+ export function __wbg_static_accessor_GLOBAL_d8e8a2fefe80bc1d() {
295
+ const ret = typeof global === 'undefined' ? null : global;
296
+ return isLikeNone(ret) ? 0 : addToExternrefTable0(ret);
297
+ }
298
+ export function __wbg_static_accessor_SELF_e29eaf7c465526b1() {
299
+ const ret = typeof self === 'undefined' ? null : self;
300
+ return isLikeNone(ret) ? 0 : addToExternrefTable0(ret);
301
+ }
302
+ export function __wbg_static_accessor_WINDOW_66e7ca3eef30585a() {
303
+ const ret = typeof window === 'undefined' ? null : window;
304
+ return isLikeNone(ret) ? 0 : addToExternrefTable0(ret);
305
+ }
306
+ export function __wbg_status_3a65028f4384d918(arg0) {
307
+ const ret = arg0.status;
308
+ return ret;
309
+ }
310
+ export function __wbg_stringify_c585a2d825a78689() { return handleError(function (arg0) {
311
+ const ret = JSON.stringify(arg0);
312
+ return ret;
313
+ }, arguments); }
314
+ export function __wbg_text_96bbece7b1823162() { return handleError(function (arg0) {
315
+ const ret = arg0.text();
316
+ return ret;
317
+ }, arguments); }
318
+ export function __wbg_then_1170ade08ea65bc7(arg0, arg1, arg2) {
319
+ const ret = arg0.then(arg1, arg2);
320
+ return ret;
321
+ }
322
+ export function __wbg_then_fdc17de424bf508a(arg0, arg1) {
323
+ const ret = arg0.then(arg1);
324
+ return ret;
325
+ }
326
+ export function __wbg_url_f73e822379c5f00c(arg0, arg1) {
327
+ const ret = arg1.url;
328
+ const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
329
+ const len1 = WASM_VECTOR_LEN;
330
+ getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
331
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
332
+ }
333
+ export function __wbg_value_414b42ce7b3eca22(arg0) {
334
+ const ret = arg0.value;
335
+ return ret;
336
+ }
337
+ export function __wbindgen_cast_0000000000000001(arg0, arg1) {
338
+ // Cast intrinsic for `Closure(Closure { dtor_idx: 180, function: Function { arguments: [], shim_idx: 181, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
339
+ const ret = makeMutClosure(arg0, arg1, wasm.wasm_bindgen__closure__destroy__h5f81f6b11f600e0f, wasm_bindgen__convert__closures_____invoke__hf70767533d8a8a0d);
340
+ return ret;
341
+ }
342
+ export function __wbindgen_cast_0000000000000002(arg0, arg1) {
343
+ // Cast intrinsic for `Closure(Closure { dtor_idx: 205, function: Function { arguments: [Externref], shim_idx: 206, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
344
+ const ret = makeMutClosure(arg0, arg1, wasm.wasm_bindgen__closure__destroy__hc635dc0582188d21, wasm_bindgen__convert__closures_____invoke__h889c317fc30b5049);
345
+ return ret;
346
+ }
347
+ export function __wbindgen_cast_0000000000000003(arg0, arg1) {
348
+ // Cast intrinsic for `Ref(String) -> Externref`.
349
+ const ret = getStringFromWasm0(arg0, arg1);
350
+ return ret;
351
+ }
352
+ export function __wbindgen_init_externref_table() {
353
+ const table = wasm.__wbindgen_externrefs;
354
+ const offset = table.grow(4);
355
+ table.set(0, undefined);
356
+ table.set(offset + 0, undefined);
357
+ table.set(offset + 1, null);
358
+ table.set(offset + 2, true);
359
+ table.set(offset + 3, false);
360
+ }
361
+ function wasm_bindgen__convert__closures_____invoke__hf70767533d8a8a0d(arg0, arg1) {
362
+ wasm.wasm_bindgen__convert__closures_____invoke__hf70767533d8a8a0d(arg0, arg1);
363
+ }
364
+
365
+ function wasm_bindgen__convert__closures_____invoke__h889c317fc30b5049(arg0, arg1, arg2) {
366
+ const ret = wasm.wasm_bindgen__convert__closures_____invoke__h889c317fc30b5049(arg0, arg1, arg2);
367
+ if (ret[1]) {
368
+ throw takeFromExternrefTable0(ret[0]);
369
+ }
370
+ }
371
+
372
+ function wasm_bindgen__convert__closures_____invoke__h2deb7db8ea6922c5(arg0, arg1, arg2, arg3) {
373
+ wasm.wasm_bindgen__convert__closures_____invoke__h2deb7db8ea6922c5(arg0, arg1, arg2, arg3);
374
+ }
375
+
376
+
377
+ const __wbindgen_enum_RequestCache = ["default", "no-store", "reload", "no-cache", "force-cache", "only-if-cached"];
378
+
379
+
380
+ const __wbindgen_enum_RequestCredentials = ["omit", "same-origin", "include"];
381
+
382
+
383
+ const __wbindgen_enum_RequestMode = ["same-origin", "no-cors", "cors", "navigate"];
384
+
385
+ function addToExternrefTable0(obj) {
386
+ const idx = wasm.__externref_table_alloc();
387
+ wasm.__wbindgen_externrefs.set(idx, obj);
388
+ return idx;
389
+ }
390
+
391
+ const CLOSURE_DTORS = (typeof FinalizationRegistry === 'undefined')
392
+ ? { register: () => {}, unregister: () => {} }
393
+ : new FinalizationRegistry(state => state.dtor(state.a, state.b));
394
+
395
+ function debugString(val) {
396
+ // primitive types
397
+ const type = typeof val;
398
+ if (type == 'number' || type == 'boolean' || val == null) {
399
+ return `${val}`;
400
+ }
401
+ if (type == 'string') {
402
+ return `"${val}"`;
403
+ }
404
+ if (type == 'symbol') {
405
+ const description = val.description;
406
+ if (description == null) {
407
+ return 'Symbol';
408
+ } else {
409
+ return `Symbol(${description})`;
410
+ }
411
+ }
412
+ if (type == 'function') {
413
+ const name = val.name;
414
+ if (typeof name == 'string' && name.length > 0) {
415
+ return `Function(${name})`;
416
+ } else {
417
+ return 'Function';
418
+ }
419
+ }
420
+ // objects
421
+ if (Array.isArray(val)) {
422
+ const length = val.length;
423
+ let debug = '[';
424
+ if (length > 0) {
425
+ debug += debugString(val[0]);
426
+ }
427
+ for(let i = 1; i < length; i++) {
428
+ debug += ', ' + debugString(val[i]);
429
+ }
430
+ debug += ']';
431
+ return debug;
432
+ }
433
+ // Test for built-in
434
+ const builtInMatches = /\[object ([^\]]+)\]/.exec(toString.call(val));
435
+ let className;
436
+ if (builtInMatches && builtInMatches.length > 1) {
437
+ className = builtInMatches[1];
438
+ } else {
439
+ // Failed to match the standard '[object ClassName]'
440
+ return toString.call(val);
441
+ }
442
+ if (className == 'Object') {
443
+ // we're a user defined class or Object
444
+ // JSON.stringify avoids problems with cycles, and is generally much
445
+ // easier than looping through ownProperties of `val`.
446
+ try {
447
+ return 'Object(' + JSON.stringify(val) + ')';
448
+ } catch (_) {
449
+ return 'Object';
450
+ }
451
+ }
452
+ // errors
453
+ if (val instanceof Error) {
454
+ return `${val.name}: ${val.message}\n${val.stack}`;
455
+ }
456
+ // TODO we could test for more things here, like `Set`s and `Map`s.
457
+ return className;
458
+ }
459
+
460
+ function getArrayU8FromWasm0(ptr, len) {
461
+ ptr = ptr >>> 0;
462
+ return getUint8ArrayMemory0().subarray(ptr / 1, ptr / 1 + len);
463
+ }
464
+
465
+ let cachedDataViewMemory0 = null;
466
+ function getDataViewMemory0() {
467
+ if (cachedDataViewMemory0 === null || cachedDataViewMemory0.buffer.detached === true || (cachedDataViewMemory0.buffer.detached === undefined && cachedDataViewMemory0.buffer !== wasm.memory.buffer)) {
468
+ cachedDataViewMemory0 = new DataView(wasm.memory.buffer);
469
+ }
470
+ return cachedDataViewMemory0;
471
+ }
472
+
473
+ function getStringFromWasm0(ptr, len) {
474
+ ptr = ptr >>> 0;
475
+ return decodeText(ptr, len);
476
+ }
477
+
478
+ let cachedUint8ArrayMemory0 = null;
479
+ function getUint8ArrayMemory0() {
480
+ if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) {
481
+ cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer);
482
+ }
483
+ return cachedUint8ArrayMemory0;
484
+ }
485
+
486
+ function handleError(f, args) {
487
+ try {
488
+ return f.apply(this, args);
489
+ } catch (e) {
490
+ const idx = addToExternrefTable0(e);
491
+ wasm.__wbindgen_exn_store(idx);
492
+ }
493
+ }
494
+
495
+ function isLikeNone(x) {
496
+ return x === undefined || x === null;
497
+ }
498
+
499
+ function makeMutClosure(arg0, arg1, dtor, f) {
500
+ const state = { a: arg0, b: arg1, cnt: 1, dtor };
501
+ const real = (...args) => {
502
+
503
+ // First up with a closure we increment the internal reference
504
+ // count. This ensures that the Rust closure environment won't
505
+ // be deallocated while we're invoking it.
506
+ state.cnt++;
507
+ const a = state.a;
508
+ state.a = 0;
509
+ try {
510
+ return f(a, state.b, ...args);
511
+ } finally {
512
+ state.a = a;
513
+ real._wbg_cb_unref();
514
+ }
515
+ };
516
+ real._wbg_cb_unref = () => {
517
+ if (--state.cnt === 0) {
518
+ state.dtor(state.a, state.b);
519
+ state.a = 0;
520
+ CLOSURE_DTORS.unregister(state);
521
+ }
522
+ };
523
+ CLOSURE_DTORS.register(real, state, state);
524
+ return real;
525
+ }
526
+
527
+ function passArray8ToWasm0(arg, malloc) {
528
+ const ptr = malloc(arg.length * 1, 1) >>> 0;
529
+ getUint8ArrayMemory0().set(arg, ptr / 1);
530
+ WASM_VECTOR_LEN = arg.length;
531
+ return ptr;
532
+ }
533
+
534
+ function passStringToWasm0(arg, malloc, realloc) {
535
+ if (realloc === undefined) {
536
+ const buf = cachedTextEncoder.encode(arg);
537
+ const ptr = malloc(buf.length, 1) >>> 0;
538
+ getUint8ArrayMemory0().subarray(ptr, ptr + buf.length).set(buf);
539
+ WASM_VECTOR_LEN = buf.length;
540
+ return ptr;
541
+ }
542
+
543
+ let len = arg.length;
544
+ let ptr = malloc(len, 1) >>> 0;
545
+
546
+ const mem = getUint8ArrayMemory0();
547
+
548
+ let offset = 0;
549
+
550
+ for (; offset < len; offset++) {
551
+ const code = arg.charCodeAt(offset);
552
+ if (code > 0x7F) break;
553
+ mem[ptr + offset] = code;
554
+ }
555
+ if (offset !== len) {
556
+ if (offset !== 0) {
557
+ arg = arg.slice(offset);
558
+ }
559
+ ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0;
560
+ const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len);
561
+ const ret = cachedTextEncoder.encodeInto(arg, view);
562
+
563
+ offset += ret.written;
564
+ ptr = realloc(ptr, len, offset, 1) >>> 0;
565
+ }
566
+
567
+ WASM_VECTOR_LEN = offset;
568
+ return ptr;
569
+ }
570
+
571
+ function takeFromExternrefTable0(idx) {
572
+ const value = wasm.__wbindgen_externrefs.get(idx);
573
+ wasm.__externref_table_dealloc(idx);
574
+ return value;
575
+ }
576
+
577
+ let cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
578
+ cachedTextDecoder.decode();
579
+ const MAX_SAFARI_DECODE_BYTES = 2146435072;
580
+ let numBytesDecoded = 0;
581
+ function decodeText(ptr, len) {
582
+ numBytesDecoded += len;
583
+ if (numBytesDecoded >= MAX_SAFARI_DECODE_BYTES) {
584
+ cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
585
+ cachedTextDecoder.decode();
586
+ numBytesDecoded = len;
587
+ }
588
+ return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len));
589
+ }
590
+
591
+ const cachedTextEncoder = new TextEncoder();
592
+
593
+ if (!('encodeInto' in cachedTextEncoder)) {
594
+ cachedTextEncoder.encodeInto = function (arg, view) {
595
+ const buf = cachedTextEncoder.encode(arg);
596
+ view.set(buf);
597
+ return {
598
+ read: arg.length,
599
+ written: buf.length
600
+ };
601
+ };
602
+ }
603
+
604
+ let WASM_VECTOR_LEN = 0;
605
+
606
+
607
+ let wasm;
608
+ export function __wbg_set_wasm(val) {
609
+ wasm = val;
610
+ }
Binary file
package/package.json ADDED
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "anytomd",
3
+ "type": "module",
4
+ "description": "Pure Rust library that converts various document formats into Markdown",
5
+ "version": "1.2.1",
6
+ "license": "Apache-2.0",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/developer0hye/anytomd-rs"
10
+ },
11
+ "files": [
12
+ "anytomd_bg.wasm",
13
+ "anytomd.js",
14
+ "anytomd_bg.js",
15
+ "anytomd.d.ts"
16
+ ],
17
+ "main": "anytomd.js",
18
+ "homepage": "https://github.com/developer0hye/anytomd-rs",
19
+ "types": "anytomd.d.ts",
20
+ "sideEffects": [
21
+ "./anytomd.js",
22
+ "./snippets/*"
23
+ ],
24
+ "keywords": [
25
+ "markdown",
26
+ "converter",
27
+ "document",
28
+ "llm"
29
+ ]
30
+ }