### anytomd - Quick Start (Rust)
Source: https://docs.rs/anytomd
Provides a quick start example in Rust demonstrating how to use the `anytomd` library to convert CSV data and a DOCX file to Markdown.
```rust
use anytomd::{convert_bytes, ConversionOptions};
// Convert raw bytes with an explicit format
let options = ConversionOptions::default();
let csv_data = b"Name,Age\nAlice,30\nBob,25";
let result = convert_bytes(csv_data, "csv", &options).unwrap();
println!("{}", result.markdown);
use anytomd::{convert_file, ConversionOptions};
let options = ConversionOptions::default();
let result = convert_file("document.docx", &options).unwrap();
println!("{}", result.markdown);
```
--------------------------------
### Quick Start Examples
Source: https://docs.rs/anytomd/1.2.1/anytomd
Provides basic usage examples for converting CSV data and DOCX files to Markdown.
```APIDOC
## Quick Start
### Convert Bytes (CSV Example)
```rust
use anytomd::{convert_bytes, ConversionOptions};
let options = ConversionOptions::default();
let csv_data = b"Name,Age\nAlice,30\nBob,25";
let result = convert_bytes(csv_data, "csv", &options).unwrap();
println!("{}", result.markdown);
```
### Convert File (DOCX Example)
```rust
use anytomd::{convert_file, ConversionOptions};
let options = ConversionOptions::default();
let result = convert_file("document.docx", &options).unwrap();
println!("{}", result.markdown);
```
```
--------------------------------
### Initialize GeminiDescriber
Source: https://docs.rs/anytomd/1.2.1/anytomd/converter/gemini/struct.GeminiDescriber.html
Examples for creating a new GeminiDescriber instance using a direct API key or the GEMINI_API_KEY environment variable.
```rust
use anytomd::gemini::GeminiDescriber;
let describer = GeminiDescriber::new("your-api-key".to_string());
// or from the GEMINI_API_KEY environment variable:
let describer = GeminiDescriber::from_env().unwrap();
```
--------------------------------
### Initialize PPTX Table Test
Source: https://docs.rs/anytomd/1.2.1/src/anytomd/converter/pptx.rs.html
Starts the definition of a test case for basic table structures in a PPTX slide.
```rust
#[test]
fn test_pptx_table_basic() {
let data = build_test_pptx(&[TestSlide {
title: Some("Data"),
```
--------------------------------
### AnytoMD Conversion Functions
Source: https://docs.rs/anytomd/1.2.1/index.html
Examples of how to use the `anytomd` library to convert document content to Markdown.
```APIDOC
## Convert Bytes to Markdown
### Description
Converts raw bytes of a document into Markdown format. Requires specifying the document's format explicitly.
### Method
`convert_bytes`
### Parameters
- `data` (bytes) - The raw byte content of the document.
- `format` (string) - The explicit format of the document (e.g., "csv", "docx").
- `options` (`ConversionOptions`) - Options to control the conversion process.
### Request Example
```rust
use anytomd::{convert_bytes, ConversionOptions};
let options = ConversionOptions::default();
let csv_data = b"Name,Age\nAlice,30\nBob,25";
let result = convert_bytes(csv_data, "csv", &options).unwrap();
println!("{}", result.markdown);
```
### Response
#### Success Response (200)
- `markdown` (string) - The converted Markdown content.
- `warnings` (array of `ConversionWarning`) - Any warnings encountered during conversion.
#### Response Example
```json
{
"markdown": "| Name | Age |\n|-------|-------|\n| Alice | 30 |\n| Bob | 25 |\n",
"warnings": []
}
```
## Convert File to Markdown
### Description
Converts the content of a file at a given path into Markdown format. The library attempts to detect the file type automatically.
### Method
`convert_file`
### Parameters
- `file_path` (string) - The path to the document file.
- `options` (`ConversionOptions`) - Options to control the conversion process.
### Request Example
```rust
use anytomd::{convert_file, ConversionOptions};
let options = ConversionOptions::default();
let result = convert_file("document.docx", &options).unwrap();
println!("{}", result.markdown);
```
### Response
#### Success Response (200)
- `markdown` (string) - The converted Markdown content.
- `warnings` (array of `ConversionWarning`) - Any warnings encountered during conversion.
#### Response Example
```json
{
"markdown": "# Document Title\n\nThis is the content of the document...",
"warnings": []
}
```
```
--------------------------------
### Resolve Relative Path Against Directory
Source: https://docs.rs/anytomd/1.2.1/src/anytomd/converter/ooxml_utils.rs.html
Resolves a target path relative to a base directory path within an OOXML package. It handles cases where the target is absolute (starts with '/') or relative, and normalizes the resulting path. For example, resolving '../media/image1.png' against 'xl/drawings' yields 'xl/media/image1.png'.
```rust
pub(crate) fn resolve_relative_path(base_dir: &str, target: &str) -> String {
let joined = if target.starts_with('/') || base_dir.is_empty() {
target.to_string()
} else {
format!("{base_dir}/{target}")
};
normalize_package_path(&joined)
}
```
--------------------------------
### Constructing DOCX Package Files
Source: https://docs.rs/anytomd/1.2.1/src/anytomd/converter/docx.rs.html
Demonstrates writing XML components and image data into a zip archive to form a valid DOCX structure.
```rust
let ct = r#""#;
zip.start_file("[Content_Types].xml", opts).unwrap();
zip.write_all(ct.as_bytes()).unwrap();
zip.start_file("_rels/.rels", opts).unwrap();
zip.write_all(
br#""#,
).unwrap();
zip.start_file("word/document.xml", opts).unwrap();
zip.write_all(document_xml.as_bytes()).unwrap();
zip.start_file("word/_rels/document.xml.rels", opts)
.unwrap();
zip.write_all(rels_xml.as_bytes()).unwrap();
for (path, data) in images {
zip.start_file(*path, opts).unwrap();
zip.write_all(data).unwrap();
}
let cursor = zip.finish().unwrap();
cursor.into_inner()
```
--------------------------------
### GeminiDescriber Initialization
Source: https://docs.rs/anytomd/1.2.1/anytomd/converter/gemini/struct.GeminiDescriber.html
Demonstrates how to create a new instance of GeminiDescriber, either with an API key or by reading from an environment variable.
```APIDOC
## GeminiDescriber Initialization
### Description
Provides methods to initialize the `GeminiDescriber`.
### Methods
#### `new(api_key: String) -> Self`
Create a new `GeminiDescriber` with the given API key.
#### `from_env() -> Result`
Create a new `GeminiDescriber` by reading the `GEMINI_API_KEY` environment variable.
### Request Example
```rust
use anytomd::gemini::GeminiDescriber;
// Using an API key
let describer = GeminiDescriber::new("your-api-key".to_string());
// Using environment variable
let describer = GeminiDescriber::from_env().unwrap();
```
```
--------------------------------
### Handle XML Start Events for Document Elements
Source: https://docs.rs/anytomd/1.2.1/src/anytomd/converter/docx.rs.html
Processes start tags for elements like hyperlinks, text runs, and drawing properties to extract attributes and update state.
```rust
let val = String::from_utf8_lossy(&attr.value).to_string();
// numId "0" means no numbering
if val != "0" {
current_num_id = Some(val);
}
}
}
}
"hyperlink" if in_paragraph => {
in_hyperlink = true;
hyperlink_runs.clear();
hyperlink_runs_plain.clear();
current_hyperlink_url = None;
for attr in e.attributes().flatten() {
let key = std::str::from_utf8(attr.key.as_ref()).unwrap_or("");
if key == "r:id" || key.ends_with(":id") {
let rid = String::from_utf8_lossy(&attr.value).to_string();
current_hyperlink_url =
resolve_hyperlink_url(&rid, relationships, &mut warnings);
}
}
}
"r" if in_paragraph => {
in_run = true;
current_run_bold = false;
current_run_italic = false;
}
"rPr" if in_run => {
in_run_properties = true;
}
"b" if in_run_properties => {
// Bold: or
// Check for explicit false
current_run_bold = !is_val_false(e);
}
"i" if in_run_properties => {
current_run_italic = !is_val_false(e);
}
"t" if in_run => {
in_text = true;
}
"drawing" if in_run => {
in_drawing = true;
current_image_alt = None;
current_image_rel_id = None;
}
"docPr" if in_drawing => {
//
for attr in e.attributes().flatten() {
let local_name = attr.key.local_name();
let k = std::str::from_utf8(local_name.as_ref()).unwrap_or("");
if k == "descr" {
let val = String::from_utf8_lossy(&attr.value).to_string();
if !val.is_empty() {
current_image_alt = Some(val);
}
}
}
}
"blip" if in_drawing => {
//
for attr in e.attributes().flatten() {
let key = std::str::from_utf8(attr.key.as_ref()).unwrap_or("");
if key == "r:embed" || key.ends_with(":embed") {
current_image_rel_id =
Some(String::from_utf8_lossy(&attr.value).to_string());
}
}
}
_ => {}
```
--------------------------------
### Handle Shape Start Event in Rust
Source: https://docs.rs/anytomd/1.2.1/src/anytomd/converter/pptx.rs.html
Parses the start of a shape element (), identifying placeholder types and text body context. Requires mutable references to state variables.
```rust
fn handle_shape_start(
local_str: &str,
e: &quick_xml::events::BytesStart,
placeholder_type: &mut Option,
in_text_body: &mut bool,
in_paragraph: &mut bool,
in_run: &mut bool,
in_text: &mut bool,
current_paragraph: &mut String,
) {
match local_str {
"ph" => {
// or etc.
let mut ph_type = PlaceholderType::Other;
for attr in e.attributes().flatten() {
let local_name = attr.key.local_name();
let key = std::str::from_utf8(local_name.as_ref()).unwrap_or("");
if key == "type" {
let val = String::from_utf8_lossy(&attr.value);
ph_type = match val.as_ref() {
"title" => PlaceholderType::Title,
"ctrTitle" => PlaceholderType::CenterTitle,
"subTitle" => PlaceholderType::SubTitle,
"body" => PlaceholderType::Body,
_ => PlaceholderType::Other,
};
}
}
*placeholder_type = Some(ph_type);
}
"txBody" => {
*in_text_body = true;
}
"p" if *in_text_body => {
*in_paragraph = true;
current_paragraph.clear();
}
"r" if *in_paragraph => {
*in_run = true;
}
"t" if *in_run => {
*in_text = true;
}
_ => {}
}
}
```
--------------------------------
### Create GeminiDescriber from Environment (Missing Key)
Source: https://docs.rs/anytomd/1.2.1/src/anytomd/converter/gemini.rs.html
Attempts to create a GeminiDescriber from the environment when the API key is not set. Expects an error.
```rust
with_env_key(|| {
remove_env_key();
let result = GeminiDescriber::from_env();
assert!(result.is_err());
let err = result.unwrap_err();
assert!(
format!("{err}").contains("GEMINI_API_KEY"),
"error was: {err}"
);
});
```
--------------------------------
### Handle Graphic Frame Start Event in Rust
Source: https://docs.rs/anytomd/1.2.1/src/anytomd/converter/pptx.rs.html
Manages the start of a graphic frame, specifically for table elements. It initializes table parsing state, including tracking if inside a table, row, or cell.
```rust
fn handle_graphic_frame_start(
local_str: &str,
in_table: &mut bool,
in_table_row: &mut bool,
in_table_cell: &mut bool,
in_cell_paragraph: &mut bool,
in_cell_run: &mut bool,
in_cell_text: &mut bool,
current_cell: &mut String,
current_row: &mut Vec,
table_rows: &mut Vec>,
) {
match local_str {
"tbl" => {
*in_table = true;
table_rows.clear();
}
"tr" if *in_table => {
*in_table_row = true;
current_row.clear();
}
"tc" if *in_table_row => {
*in_table_cell = true;
current_cell.clear();
}
"p" if *in_table_cell => {
// Add space separator between paragraphs in the same cell
if !current_cell.is_empty() {
current_cell.push(' ');
}
*in_cell_paragraph = true;
}
"r" if *in_cell_paragraph => {
*in_cell_run = true;
}
"t" if *in_cell_run => {
*in_cell_text = true;
}
_ => {}
}
}
```
--------------------------------
### Initialize AsyncGeminiDescriber from Environment Variable
Source: https://docs.rs/anytomd/1.2.1/src/anytomd/converter/gemini.rs.html
Create a new AsyncGeminiDescriber instance by reading the GEMINI_API_KEY environment variable. Requires the 'async-gemini' feature flag. Returns an error if the environment variable is not set.
```rust
use anytomd::gemini::AsyncGeminiDescriber;
let describer = AsyncGeminiDescriber::from_env().unwrap();
```
--------------------------------
### Extract markdown heading
Source: https://docs.rs/anytomd/1.2.1/src/anytomd/converter/ipynb.rs.html
Parses markdown content to find the first top-level heading starting with '# '.
```rust
fn extract_heading_title(markdown: &str) -> Option {
for line in markdown.lines() {
let trimmed = line.trim();
if let Some(heading) = trimmed.strip_prefix("# ") {
let heading = heading.trim();
if !heading.is_empty() {
return Some(heading.to_string());
}
}
}
None
}
```
--------------------------------
### Initialize AsyncGeminiDescriber with API Key
Source: https://docs.rs/anytomd/1.2.1/src/anytomd/converter/gemini.rs.html
Create a new AsyncGeminiDescriber instance using a provided API key. Ensure the 'async-gemini' feature flag is enabled.
```rust
use anytomd::gemini::AsyncGeminiDescriber;
let describer = AsyncGeminiDescriber::new("your-api-key".to_string());
```
--------------------------------
### anytomd - Convert File
Source: https://docs.rs/anytomd
Demonstrates how to convert a file from a given path to Markdown using the `convert_file` function. The library attempts to detect the file format automatically.
```APIDOC
## POST /convert/file
### Description
Converts a file from the specified path to Markdown. The library attempts to detect the file format automatically.
### Method
POST
### Endpoint
/convert/file
### Parameters
#### Request Body
- **filePath** (string) - Required - The path to the file to be converted.
- **options** (object) - Optional - Conversion options.
- **skip_code_blocks** (boolean) - Optional - Whether to skip code blocks.
- **skip_images** (boolean) - Optional - Whether to skip images.
- **image_description_prompt** (string) - Optional - Prompt for image description.
### Request Example
```json
{
"filePath": "/path/to/your/document.docx",
"options": {
"skip_images": false
}
}
```
### Response
#### Success Response (200)
- **markdown** (string) - The converted Markdown content.
- **warnings** (array) - A list of warnings encountered during conversion.
- **code** (string) - The warning code.
- **message** (string) - The warning message.
#### Response Example
```json
{
"markdown": "# Converted Document\nThis is the converted content.",
"warnings": []
}
```
```
--------------------------------
### Initialize AsyncGeminiDescriber
Source: https://docs.rs/anytomd/1.2.1/src/anytomd/converter/gemini.rs.html
Creates a new AsyncGeminiDescriber with a specified API key and default model. Use this for direct initialization.
```rust
let describer = AsyncGeminiDescriber::new("test-key".to_string());
assert_eq!(describer.api_key, "test-key");
assert_eq!(describer.model, "gemini-3-flash-preview");
```
--------------------------------
### Handle picture start events
Source: https://docs.rs/anytomd/1.2.1/src/anytomd/converter/pptx.rs.html
Extracts image relationship IDs and alternative text descriptions from picture XML elements.
```rust
fn handle_picture_start(
local_str: &str,
e: &quick_xml::events::BytesStart,
current_blip_rel_id: &mut Option,
current_image_alt: &mut Option,
) {
match local_str {
"blip" => {
for attr in e.attributes().flatten() {
let key = std::str::from_utf8(attr.key.as_ref()).unwrap_or("");
if key == "r:embed" || key.ends_with(":embed") {
let val = String::from_utf8_lossy(&attr.value).to_string();
*current_blip_rel_id = Some(val);
}
}
}
"cNvPr" => {
for attr in e.attributes().flatten() {
let local_name = attr.key.local_name();
let key = std::str::from_utf8(local_name.as_ref()).unwrap_or("");
if key == "descr" {
let val = String::from_utf8_lossy(&attr.value).to_string();
if !val.is_empty() {
*current_image_alt = Some(val);
}
}
}
}
_ => {}
}
}
```
--------------------------------
### Create GeminiDescriber from Environment (With Key)
Source: https://docs.rs/anytomd/1.2.1/src/anytomd/converter/gemini.rs.html
Creates a GeminiDescriber by reading the API key from the environment variable `GEMINI_API_KEY`.
```rust
with_env_key(|| {
set_env_key("test-env-key");
let result = GeminiDescriber::from_env();
assert!(result.is_ok());
let describer = result.unwrap();
assert_eq!(describer.api_key, "test-env-key");
});
```
--------------------------------
### Get Type ID - Generic Implementation
Source: https://docs.rs/anytomd/1.2.1/anytomd/converter/code/struct.CodeConverter.html
Retrieves the `TypeId` of the implementing type. This is a standard method for types that implement the `Any` trait.
```rust
fn type_id(&self) -> TypeId
```
--------------------------------
### Create AsyncGeminiDescriber from Environment (With Key)
Source: https://docs.rs/anytomd/1.2.1/src/anytomd/converter/gemini.rs.html
Creates an AsyncGeminiDescriber using the GEMINI_API_KEY environment variable. This test confirms successful initialization when the key is present.
```rust
#[cfg(not(target_arch = "wasm32"))]
super::with_env_key(|| {
super::set_env_key("test-async-env-key");
let result = AsyncGeminiDescriber::from_env();
assert!(result.is_ok());
let describer = result.unwrap();
assert_eq!(describer.api_key, "test-async-env-key");
});
```
--------------------------------
### Example: Using `set` to Modify Pinned Value
Source: https://docs.rs/anytomd/1.2.1/anytomd/converter/type.AsyncDescribeFuture.html
Illustrates how to use the `set` method to change the value of a pinned mutable reference.
```rust
use std::pin::Pin;
let mut val: u8 = 5;
let mut pinned: Pin<&mut u8> = Pin::new(&mut val);
println!("{}", pinned); // 5
pinned.set(10);
println!("{}", pinned); // 10
```
--------------------------------
### pub fn as_ref(&self) -> Pin<&::Target>
Source: https://docs.rs/anytomd/1.2.1/anytomd/converter/type.AsyncDescribeFuture.html
Gets a shared reference to the pinned value this Pin points to.
```APIDOC
## GET as_ref
### Description
Gets a shared reference to the pinned value this Pin points to. This is a safe operation because the contract of Pin::new_unchecked ensures the pointee cannot move.
### Method
GET
### Parameters
#### Path Parameters
- **self** (Pin) - Required - The Pin instance to reference.
```
--------------------------------
### Instantiate AsyncGeminiDescriber
Source: https://docs.rs/anytomd/1.2.1/anytomd/converter/gemini/struct.AsyncGeminiDescriber.html
Create a new AsyncGeminiDescriber using an API key or from the GEMINI_API_KEY environment variable. Ensure the `async-gemini` feature is enabled.
```rust
use anytomd::gemini::AsyncGeminiDescriber;
let describer = AsyncGeminiDescriber::new("your-api-key".to_string());
// or from the GEMINI_API_KEY environment variable:
let describer = AsyncGeminiDescriber::from_env().unwrap();
```
--------------------------------
### Supported Extensions - CodeConverter
Source: https://docs.rs/anytomd/1.2.1/anytomd/converter/code/struct.CodeConverter.html
Returns a slice of string slices representing the file extensions that this converter can handle. For example, `["docx"]`.
```rust
fn supported_extensions(&self) -> &[&str]
```
--------------------------------
### Package Presentation Components
Source: https://docs.rs/anytomd/1.2.1/src/anytomd/converter/pptx.rs.html
Handles the ZIP packaging of slide relationships, notes, and presentation metadata into the final PPTX structure.
```rust
r#""#
));
}
for (img_idx, _) in slide.images.iter().enumerate() {
let img_rid = format!("rIdImg{}", img_idx + 1);
slide_rels.push_str(&format!(
r#""#,
img_idx + 1
));
}
slide_rels.push_str("");
zip.start_file(format!("ppt/slides/_rels/slide{slide_num}.xml.rels"), opts)
.unwrap();
zip.write_all(slide_rels.as_bytes()).unwrap();
}
// Build notes slide if present
if let Some(notes_text) = slide.notes {
let notes_xml = build_notes_xml(notes_text);
zip.start_file(format!("ppt/notesSlides/notesSlide{slide_num}.xml"), opts)
.unwrap();
zip.write_all(notes_xml.as_bytes()).unwrap();
}
}
pres_xml.push_str("");
pres_rels_xml.push_str("");
zip.start_file("ppt/presentation.xml", opts).unwrap();
zip.write_all(pres_xml.as_bytes()).unwrap();
zip.start_file("ppt/_rels/presentation.xml.rels", opts)
.unwrap();
zip.write_all(pres_rels_xml.as_bytes()).unwrap();
let cursor = zip.finish().unwrap();
cursor.into_inner()
}
```
--------------------------------
### Parsing 'body' Element in Rust
Source: https://docs.rs/anytomd/1.2.1/src/anytomd/converter/docx.rs.html
Sets the 'in_body' flag to true when the 'body' element is encountered, indicating the start of the main document content.
```Rust
"body" => {
in_body = true;
}
```
--------------------------------
### Test extension handling
Source: https://docs.rs/anytomd/1.2.1/src/anytomd/lib.rs.html
Verifies that file extensions are handled correctly regardless of case or leading dots.
```rust
#[test]
fn test_convert_bytes_extension_case_insensitive() {
let result = convert_bytes(b"hello world", " TXT ", &ConversionOptions::default()).unwrap();
assert!(result.markdown.contains("hello world"));
}
```
```rust
#[test]
fn test_convert_bytes_extension_with_leading_dot() {
let result = convert_bytes(b"hello world", ".txt", &ConversionOptions::default()).unwrap();
assert!(result.markdown.contains("hello world"));
}
```
--------------------------------
### IpynbConverter Struct Definition
Source: https://docs.rs/anytomd/1.2.1/anytomd/converter/ipynb/struct.IpynbConverter.html
Defines the IpynbConverter struct, which is responsible for converting Jupyter Notebook files to Markdown. No specific setup or imports are shown here.
```rust
pub struct IpynbConverter;
```
--------------------------------
### AsyncGeminiDescriber Initialization
Source: https://docs.rs/anytomd/1.2.1/anytomd/converter/gemini/struct.AsyncGeminiDescriber.html
Methods to initialize the AsyncGeminiDescriber instance.
```APIDOC
## Initialization
### Description
Methods to create a new instance of the AsyncGeminiDescriber.
### Methods
- **new(api_key: String)**: Create a new instance with a provided API key.
- **from_env()**: Create an instance by reading the GEMINI_API_KEY environment variable.
- **with_model(model: String)**: Set a custom model name (default: gemini-3-flash-preview).
```
--------------------------------
### Test XML output starts with code fence
Source: https://docs.rs/anytomd/1.2.1/src/anytomd/converter/xml.rs.html
Verifies that the markdown output for valid XML always begins with a ```xml code fence.
```rust
let result = convert(b"").unwrap();
assert!(result.markdown.starts_with("```xml\n"));
```
--------------------------------
### Test IPYNB Source as String
Source: https://docs.rs/anytomd/1.2.1/src/anytomd/converter/ipynb.rs.html
Demonstrates that the converter handles notebook cells where the 'source' is a single string instead of an array.
```rust
#[test]
fn test_ipynb_source_as_string() {
// nbformat allows source as a single string (not array)
let nb = serde_json::json!({
"nbformat": 4,
"nbformat_minor": 2,
"metadata": { "kernelspec": { "language": "python" } },
"cells": [{
"cell_type": "code",
"metadata": {},
"source": "x = 42"
}]
});
let data = serde_json::to_vec(&nb).unwrap();
let result = IpynbConverter
.convert(&data, &ConversionOptions::default())
.unwrap();
assert!(result.markdown.contains("x = 42"));
}
```
--------------------------------
### pub fn as_mut(&mut self) -> Pin<&mut ::Target>
Source: https://docs.rs/anytomd/1.2.1/anytomd/converter/type.AsyncDescribeFuture.html
Gets a mutable reference to the pinned value this Pin points to.
```APIDOC
## GET as_mut
### Description
Gets a mutable reference to the pinned value this Pin points to. This is useful when performing multiple calls to functions that consume the pinning pointer.
### Method
GET
### Parameters
#### Path Parameters
- **self** (Pin) - Required - The Pin instance to reborrow.
```
--------------------------------
### Test JSON detection with UTF-8 BOM
Source: https://docs.rs/anytomd/1.2.1/src/anytomd/lib.rs.html
Verifies that the converter correctly handles files starting with a UTF-8 Byte Order Mark (BOM) when parsing JSON.
```rust
#[cfg(not(target_arch = "wasm32"))]
#[test]
fn test_convert_file_unknown_ext_json_with_utf8_bom() {
let dir = std::env::temp_dir().join("anytomd_test_json_bom_detect");
std::fs::create_dir_all(&dir).unwrap();
let file_path = dir.join("payload.dat");
let mut data = vec![0xEF, 0xBB, 0xBF];
data.extend_from_slice(br#"{"k":1}"#);
std::fs::write(&file_path, data).unwrap();
let result = convert_file(&file_path, &ConversionOptions::default()).unwrap();
assert!(
result.markdown.contains("\"k\""),
"expected JSON conversion, markdown was: {}",
result.markdown
);
let _ = std::fs::remove_dir_all(&dir);
}
```
--------------------------------
### Build Test DOCX with Image
Source: https://docs.rs/anytomd/1.2.1/src/anytomd/converter/docx.rs.html
Helper function to create a ZIP-compressed DOCX structure containing a document, relationships, and an image file for testing purposes.
```rust
fn build_test_docx_with_image(
document_xml: &str,
rels_xml: &str,
image_path: &str,
image_data: &[u8],
) -> Vec {
use std::io::Write;
use zip::ZipWriter;
use zip::write::SimpleFileOptions;
let buf = Vec::new();
let mut zip = ZipWriter::new(Cursor::new(buf));
let opts = SimpleFileOptions::default();
// [Content_Types].xml
let ct = r#""#;
zip.start_file("[Content_Types].xml", opts).unwrap();
zip.write_all(ct.as_bytes()).unwrap();
// _rels/.rels
zip.start_file("_rels/.rels", opts).unwrap();
zip.write_all(
br#""#,
)
.unwrap();
// word/document.xml
zip.start_file("word/document.xml", opts).unwrap();
zip.write_all(document_xml.as_bytes()).unwrap();
// word/_rels/document.xml.rels
zip.start_file("word/_rels/document.xml.rels", opts)
.unwrap();
zip.write_all(rels_xml.as_bytes()).unwrap();
// Image file
zip.start_file(image_path, opts).unwrap();
zip.write_all(image_data).unwrap();
let cursor = zip.finish().unwrap();
cursor.into_inner()
}
```
--------------------------------
### Converter Trait Definition
Source: https://docs.rs/anytomd/1.2.1/src/anytomd/converter/mod.rs.html
Trait implemented by format-specific converters, defining methods to get supported extensions, check conversion capability, and perform the conversion to Markdown.
```rust
pub trait Converter {
/// Returns the file extensions this converter supports (e.g., `["docx"]`).
fn supported_extensions(&self) -> &[&str];
/// Check if this converter can handle the given extension.
fn can_convert(&self, extension: &str, _header_bytes: &[u8]) -> bool {
self.supported_extensions().contains(&extension)
}
/// Convert file bytes to Markdown.
fn convert(
&self,
data: &[u8],
options: &ConversionOptions,
) -> Result;
}
```
--------------------------------
### Create AsyncGeminiDescriber from Environment (Missing Key)
Source: https://docs.rs/anytomd/1.2.1/src/anytomd/converter/gemini.rs.html
Attempts to create an AsyncGeminiDescriber using the GEMINI_API_KEY environment variable. This test verifies that an error is returned if the key is not set.
```rust
#[cfg(not(target_arch = "wasm32"))]
super::with_env_key(|| {
super::remove_env_key();
let result = AsyncGeminiDescriber::from_env();
assert!(result.is_err());
let err = result.unwrap_err();
assert!(
format!("{err}").contains("GEMINI_API_KEY"),
"error was: {err}"
);
});
```
--------------------------------
### AsyncConversionOptions Struct
Source: https://docs.rs/anytomd/1.2.1/src/anytomd/converter/mod.rs.html
Wraps base conversion options with an optional async image describer for concurrent LLM-based alt text generation. Requires the `async` feature.
```rust
#[cfg(feature = "async")]
#[derive(Default)]
pub struct AsyncConversionOptions {
/// Base conversion options (resource limits, extract_images, strict mode).
pub base: ConversionOptions,
/// Optional async image describer for concurrent LLM-based alt text generation.
pub async_image_describer: Option>,
}
```
--------------------------------
### Test: Decode Text UTF-16 LE BOM
Source: https://docs.rs/anytomd/1.2.1/src/anytomd/converter/mod.rs.html
Unit test setup for decoding text with a UTF-16 Little Endian BOM, followed by the characters 'A' and 'B'.
```rust
#[test]
fn test_decode_text_utf16_le_bom() {
// UTF-16 LE BOM + "AB"
let input: Vec = vec![0xFF, 0xFE, b'A', 0x00, b'B', 0x00];
```
--------------------------------
### Implement CloneToUninit for T (Nightly)
Source: https://docs.rs/anytomd/1.2.1/anytomd/converter/struct.ConversionResult.html
Nightly-only experimental API for copying data to uninitialized memory.
```rust
unsafe fn clone_to_uninit(&self, dest: *mut u8)
```
--------------------------------
### Get Shared Reference to Pinned Value
Source: https://docs.rs/anytomd/1.2.1/anytomd/converter/type.AsyncDescribeFuture.html
Retrieves a shared reference (`Pin<&T>`) to the value pointed to by a `Pin`. This is safe due to the pinning contract ensuring the value does not move.
```rust
pub fn as_ref(&self) -> Pin<&::Target>
where Ptr: Deref,
```
--------------------------------
### Create GeminiDescriber with API Key
Source: https://docs.rs/anytomd/1.2.1/src/anytomd/converter/gemini.rs.html
Instantiate `GeminiDescriber` with a provided API key. This is for native targets only.
```rust
use anytomd::gemini::GeminiDescriber;
let describer = GeminiDescriber::new("your-api-key".to_string());
```
--------------------------------
### Example: Calling Method Twice on Pinned Self
Source: https://docs.rs/anytomd/1.2.1/anytomd/converter/type.AsyncDescribeFuture.html
Demonstrates how to call a method that consumes `self` multiple times on a pinned mutable reference by repeatedly using `as_mut` to reborrow.
```rust
use std::pin::Pin;
impl Type {
fn method(self: Pin<&mut Self>) {
// do something
}
fn call_method_twice(mut self: Pin<&mut Self>) {
// `method` consumes `self`, so reborrow the `Pin<&mut Self>` via `as_mut`.
self.as_mut().method();
self.as_mut().method();
}
}
```
--------------------------------
### Build Test DOCX with Multiple Images
Source: https://docs.rs/anytomd/1.2.1/src/anytomd/converter/docx.rs.html
Helper function to create a ZIP-based DOCX structure containing multiple image files for testing purposes.
```rust
fn build_test_docx_with_images(
document_xml: &str,
rels_xml: &str,
images: &[(&str, &[u8])], // (zip_path, data)
) -> Vec {
use std::io::Write;
use zip::ZipWriter;
use zip::write::SimpleFileOptions;
let buf = Vec::new();
let mut zip = ZipWriter::new(Cursor::new(buf));
let opts = SimpleFileOptions::default();
```
--------------------------------
### Test Python Code Conversion
Source: https://docs.rs/anytomd/1.2.1/src/anytomd/converter/code.rs.html
Tests the `convert_with_extension` function for Python files. It asserts that the generated Markdown starts with the correct language tag and contains the expected code content.
```rust
#[test]
fn test_code_python_fenced_block() {
let converter = CodeConverter;
let input = b"def hello():\n print('Hello, world!')\n";
let result = converter
.convert_with_extension(input, "py", &ConversionOptions::default())
.unwrap();
assert!(result.markdown.starts_with("```python\n"));
assert!(result.markdown.ends_with("\n```\n"));
assert!(result.markdown.contains("def hello():"));
}
```
--------------------------------
### Build XML for Notes Slide
Source: https://docs.rs/anytomd/1.2.1/src/anytomd/converter/pptx.rs.html
Constructs the XML structure for a presentation notes slide by splitting input text into paragraphs.
```rust
fn build_notes_xml(text: &str) -> String {
// Split text by newlines to create separate paragraphs
let paragraphs: Vec<&str> = text.lines().collect();
let mut para_xml = String::new();
for p in ¶graphs {
para_xml.push_str(&format!(r#"{p}"#));
}
format!(
r#"1{para_xml}"#
)
}
```
--------------------------------
### Get Nested Mutable Reference from Pin
Source: https://docs.rs/anytomd/1.2.1/anytomd/converter/type.AsyncDescribeFuture.html
Obtains a `Pin<&mut T>` from a nested `Pin<&mut Pin>`. This is safe because the outer `Pin` guarantees the inner pointee cannot move.
```rust
pub fn as_deref_mut( self: Pin<&mut Pin>, ) -> Pin<&mut ::Target>
where Ptr: DerefMut,
```
--------------------------------
### Unwrap Pin to Get Underlying Pointer
Source: https://docs.rs/anytomd/1.2.1/anytomd/converter/type.AsyncDescribeFuture.html
Safely unwraps a `Pin` to return the original `Ptr`, consuming the `Pin`. This is an unsafe operation that should only be used when the pinning contract is fully upheld.
```rust
pub const unsafe fn into_inner_unchecked(pin: Pin) -> Ptr
```
--------------------------------
### Verify Plain Text Content and Syntax
Source: https://docs.rs/anytomd/1.2.1/src/anytomd/converter/xlsx.rs.html
Use these assertions to ensure the plain text output contains expected descriptions and lacks markdown image syntax.
```rust
// plain_text should contain the description
assert!(
result.plain_text.contains("A bar chart"),
"plain_text should contain the image description, was: {}",
result.plain_text
);
// plain_text should NOT contain image markdown syntax
assert!(
!result.plain_text.contains("!["),
"plain_text should not contain ![ image syntax, was: {}",
result.plain_text
);
}
}
```
--------------------------------
### Converter Supported Extensions Method
Source: https://docs.rs/anytomd/1.2.1/anytomd/converter/trait.Converter.html
Returns the file extensions this converter supports (e.g., ["docx"]). Implement this to declare which file types your converter can handle.
```rust
fn supported_extensions(&self) -> &[&str];
```
--------------------------------
### XML Event Processing Loop
Source: https://docs.rs/anytomd/1.2.1/src/anytomd/converter/pptx.rs.html
The loop processes XML events using a reader, maintaining state for shapes, graphic frames, and pictures to correctly route start, empty, and text events.
```rust
let mut in_cell_text = false;
// Image state
let mut current_blip_rel_id: Option = None;
let mut current_image_alt: Option = None;
// Track depth for nested elements
let mut shape_depth: u32 = 0;
let mut graphic_frame_depth: u32 = 0;
let mut picture_depth: u32 = 0;
// Group shape depth: is a transparent container — child shapes
// (sp, graphicFrame, pic) are processed normally. The counter tracks nesting
// for proper End-tag matching but does not gate any logic.
let mut group_depth: u32 = 0;
loop {
match reader.read_event() {
Ok(Event::Start(ref e)) => {
let local = e.local_name();
let local_str = std::str::from_utf8(local.as_ref()).unwrap_or("");
match local_str {
"grpSp" if !in_shape && !in_graphic_frame && !in_picture => {
group_depth += 1;
}
"sp" if !in_shape && !in_graphic_frame && !in_picture => {
in_shape = true;
shape_depth = 1;
placeholder_type = None;
shape_paragraphs.clear();
}
"graphicFrame" if !in_shape && !in_graphic_frame && !in_picture => {
in_graphic_frame = true;
graphic_frame_depth = 1;
}
"pic" if !in_shape && !in_graphic_frame && !in_picture => {
in_picture = true;
picture_depth = 1;
current_blip_rel_id = None;
current_image_alt = None;
}
_ if in_shape => {
shape_depth += 1;
handle_shape_start(
local_str,
e,
&mut placeholder_type,
&mut in_text_body,
&mut in_paragraph,
&mut in_run,
&mut in_text,
&mut current_paragraph,
);
}
_ if in_graphic_frame => {
graphic_frame_depth += 1;
handle_graphic_frame_start(
local_str,
&mut in_table,
&mut in_table_row,
&mut in_table_cell,
&mut in_cell_paragraph,
&mut in_cell_run,
&mut in_cell_text,
&mut current_cell,
&mut current_row,
&mut table_rows,
);
}
_ if in_picture => {
picture_depth += 1;
handle_picture_start(
local_str,
e,
&mut current_blip_rel_id,
&mut current_image_alt,
);
}
_ => {}
}
}
Ok(Event::Empty(ref e)) => {
let local = e.local_name();
let local_str = std::str::from_utf8(local.as_ref()).unwrap_or("");
if in_shape {
handle_shape_empty(
local_str,
e,
&mut placeholder_type,
in_run,
&mut current_paragraph,
);
} else if in_graphic_frame {
handle_graphic_frame_empty(local_str, in_cell_run, &mut current_cell);
} else if in_picture {
handle_picture_start(
local_str,
e,
&mut current_blip_rel_id,
&mut current_image_alt,
);
}
}
Ok(Event::Text(ref e)) => {
if in_shape && in_text && in_run {
let text = e.unescape().unwrap_or_default().to_string();
current_paragraph.push_str(&text);
} else if in_graphic_frame && in_cell_text && in_cell_run {
let text = e.unescape().unwrap_or_default().to_string();
current_cell.push_str(&text);
```
--------------------------------
### Implement Debug and Default for ConversionOptions
Source: https://docs.rs/anytomd/1.2.1/src/anytomd/converter/mod.rs.html
Provides custom Debug formatting and default configuration values for conversion options.
```rust
impl std::fmt::Debug for ConversionOptions {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ConversionOptions")
.field("extract_images", &self.extract_images)
.field("max_total_image_bytes", &self.max_total_image_bytes)
.field("strict", &self.strict)
.field("max_input_bytes", &self.max_input_bytes)
.field(
"max_uncompressed_zip_bytes",
&self.max_uncompressed_zip_bytes,
)
.field(
"image_describer",
&self.image_describer.as_ref().map(|_| ".."),
)
.finish()
}
}
impl Default for ConversionOptions {
fn default() -> Self {
Self {
extract_images: false,
max_total_image_bytes: 50 * 1024 * 1024, // 50 MB
strict: false,
max_input_bytes: 100 * 1024 * 1024, // 100 MB
max_uncompressed_zip_bytes: 500 * 1024 * 1024, // 500 MB
image_describer: None,
}
}
}
```
--------------------------------
### Derive OOXML .rels Path
Source: https://docs.rs/anytomd/1.2.1/src/anytomd/converter/ooxml_utils.rs.html
Derives the corresponding .rels file path for a given file path within an OOXML package. For example, 'ppt/slides/slide1.xml' becomes 'ppt/slides/_rels/slide1.xml.rels'. This function is essential for locating relationship metadata.
```rust
pub(crate) fn derive_rels_path(file_path: &str) -> String {
if let Some(pos) = file_path.rfind('/') {
let dir = &file_path[..pos];
let filename = &file_path[pos + 1..];
format!("{dir}/_rels/{filename}.rels")
} else {
format!(
```
--------------------------------
### Build DOCX ZIP with Numbering for Testing
Source: https://docs.rs/anytomd/1.2.1/src/anytomd/converter/docx.rs.html
Extended helper function to build a DOCX ZIP archive in memory, including optional numbering XML alongside document, styles, and relationships XML.
```rust
fn build_test_docx_with_numbering(
document_xml: &str,
styles_xml: Option<&str>,
rels_xml: Option<&str>,
numbering_xml: Option<&str>,
) -> Vec {
use std::io::Write;
use zip::ZipWriter;
use zip::write::SimpleFileOptions;
let buf = Vec::new();
let mut zip = ZipWriter::new(Cursor::new(buf));
let opts = SimpleFileOptions::default();
// [Content_Types].xml
let mut ct = String::from(r#""#);
ct.push_str(
r#""#,
);
ct.push_str(
r#""#,
);
ct.push_str(r#""#);
ct.push_str(
```
--------------------------------
### Get Mutable Reference to Pinned Value
Source: https://docs.rs/anytomd/1.2.1/anytomd/converter/type.AsyncDescribeFuture.html
Retrieves a mutable reference (`Pin<&mut T>`) to the value pointed to by a `Pin`. This is useful when calling multiple functions that consume the pinning pointer, reborrowing via `as_mut` each time.
```rust
pub fn as_mut(&mut self) -> Pin<&mut ::Target>
where Ptr: DerefMut,
```