diff --git a/README.md b/README.md
index c149399..55a109c 100644
--- a/README.md
+++ b/README.md
@@ -117,7 +117,7 @@ function writeExcel(header: string[], rows: (string | number)[][]): Buffer {
headerStyle
.setAlign(FormatAlign.Top)
.setTextWrap()
- .setBackgroundColor(Color.red());
+ .setBackgroundColor("Red");
// Write sheet header
worksheet.writeRowWithFormat(0, 0, header, headerStyle);
diff --git a/examples/nodejs/main.ts b/examples/nodejs/main.ts
index 536ce5c..844b6d1 100644
--- a/examples/nodejs/main.ts
+++ b/examples/nodejs/main.ts
@@ -1,5 +1,4 @@
import {
- Color,
DocProperties,
Format,
FormatAlign,
@@ -31,7 +30,7 @@ function writeExcel(header: string[], rows: (string | number)[][]): Buffer {
headerStyle
.setAlign(FormatAlign.Top)
.setTextWrap()
- .setBackgroundColor(Color.red());
+ .setBackgroundColor("Red");
// Write sheet header
worksheet.writeRowWithFormat(0, 0, header, headerStyle);
diff --git a/rust/Cargo.lock b/rust/Cargo.lock
index da2eebe..7861e65 100644
--- a/rust/Cargo.lock
+++ b/rust/Cargo.lock
@@ -120,6 +120,19 @@ dependencies = [
"miniz_oxide",
]
+[[package]]
+name = "gloo-utils"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b5555354113b18c547c1d3a98fbf7fb32a9ff4f6fa112ce823a21641a0ba3aa"
+dependencies = [
+ "js-sys",
+ "serde",
+ "serde_json",
+ "wasm-bindgen",
+ "web-sys",
+]
+
[[package]]
name = "hashbrown"
version = "0.15.2"
@@ -159,6 +172,12 @@ dependencies = [
"hashbrown",
]
+[[package]]
+name = "itoa"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
+
[[package]]
name = "js-sys"
version = "0.3.80"
@@ -262,26 +281,66 @@ version = "1.0.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4"
+[[package]]
+name = "ryu"
+version = "1.0.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
+
[[package]]
name = "serde"
-version = "1.0.210"
+version = "1.0.226"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a"
+checksum = "0dca6411025b24b60bfa7ec1fe1f8e710ac09782dca409ee8237ba74b51295fd"
+dependencies = [
+ "serde_core",
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_core"
+version = "1.0.226"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba2ba63999edb9dac981fb34b3e5c0d111a69b0924e253ed29d83f7c99e966a4"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
-version = "1.0.210"
+version = "1.0.226"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f"
+checksum = "8db53ae22f34573731bafa1db20f04027b2d25e02d8205921b569171699cdb33"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
+[[package]]
+name = "serde_derive_internals"
+version = "0.29.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.145"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c"
+dependencies = [
+ "itoa",
+ "memchr",
+ "ryu",
+ "serde",
+ "serde_core",
+]
+
[[package]]
name = "shlex"
version = "1.3.0"
@@ -305,6 +364,31 @@ dependencies = [
"unicode-ident",
]
+[[package]]
+name = "tsify"
+version = "0.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b2ec91b85e6c6592ed28636cb1dd1fac377ecbbeb170ff1d79f97aac5e38926d"
+dependencies = [
+ "gloo-utils",
+ "serde",
+ "serde_json",
+ "tsify-macros",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "tsify-macros"
+version = "0.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a324606929ad11628a19206d7853807481dcaecd6c08be70a235930b8241955"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "serde_derive_internals",
+ "syn",
+]
+
[[package]]
name = "unicode-ident"
version = "1.0.13"
@@ -378,6 +462,18 @@ dependencies = [
"console_error_panic_hook",
"js-sys",
"rust_xlsxwriter",
+ "serde",
+ "tsify",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "web-sys"
+version = "0.3.80"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fbe734895e869dc429d78c4b433f8d17d95f8d05317440b4fad5ab2d33e596dc"
+dependencies = [
+ "js-sys",
"wasm-bindgen",
]
diff --git a/rust/Cargo.toml b/rust/Cargo.toml
index bf3c35b..42f21f4 100644
--- a/rust/Cargo.toml
+++ b/rust/Cargo.toml
@@ -13,4 +13,6 @@ chrono = "0.4.42"
console_error_panic_hook = "0.1.7"
js-sys = "0.3.80"
rust_xlsxwriter = { version = "0.90.1", features = ["wasm", "chrono"] }
+serde = { version = "1.0.219", features = ["derive"] }
+tsify = "0.5.5"
wasm-bindgen = "0.2.94"
diff --git a/rust/src/lib.rs b/rust/src/lib.rs
index 92e3807..68aa04e 100644
--- a/rust/src/lib.rs
+++ b/rust/src/lib.rs
@@ -1,4 +1,5 @@
#![allow(clippy::new_without_default)]
mod error;
+mod macros;
mod wrapper;
diff --git a/rust/src/macros.rs b/rust/src/macros.rs
new file mode 100644
index 0000000..3b58a2a
--- /dev/null
+++ b/rust/src/macros.rs
@@ -0,0 +1,12 @@
+#[macro_export]
+macro_rules! impl_method {
+ ($self:ident.$method:ident($($arg:expr),*)) => {
+ let mut lock = $self.lock();
+ let mut inner = std::mem::take(&mut *lock);
+ inner = inner.$method($($arg),*);
+ let _ = std::mem::replace(&mut *lock, inner);
+ return Self {
+ inner: Arc::clone(&$self.inner),
+ }
+ };
+}
diff --git a/rust/src/wrapper/chart/chart_font.rs b/rust/src/wrapper/chart/chart_font.rs
index be27b27..eede818 100644
--- a/rust/src/wrapper/chart/chart_font.rs
+++ b/rust/src/wrapper/chart/chart_font.rs
@@ -52,8 +52,8 @@ impl ChartFont {
/// @param {Color} color - The font color property.
/// @return {ChartFont} - The ChartFont instance.
#[wasm_bindgen(js_name = "setColor")]
- pub fn set_color(&mut self, color: &Color) -> ChartFont {
- self.inner.set_color(color.inner);
+ pub fn set_color(&mut self, color: Color) -> ChartFont {
+ self.inner.set_color(color);
self.clone()
}
diff --git a/rust/src/wrapper/chart/chart_gradient_stop.rs b/rust/src/wrapper/chart/chart_gradient_stop.rs
index 0a65d88..a592b02 100644
--- a/rust/src/wrapper/chart/chart_gradient_stop.rs
+++ b/rust/src/wrapper/chart/chart_gradient_stop.rs
@@ -11,9 +11,9 @@ pub struct ChartGradientStop {
#[wasm_bindgen]
impl ChartGradientStop {
#[wasm_bindgen(constructor)]
- pub fn new(color: &Color, position: u8) -> ChartGradientStop {
+ pub fn new(color: Color, position: u8) -> ChartGradientStop {
ChartGradientStop {
- inner: xlsx::ChartGradientStop::new(color.inner, position),
+ inner: xlsx::ChartGradientStop::new(color, position),
}
}
}
diff --git a/rust/src/wrapper/chart/chart_line.rs b/rust/src/wrapper/chart/chart_line.rs
index dc0c09d..791a4fc 100644
--- a/rust/src/wrapper/chart/chart_line.rs
+++ b/rust/src/wrapper/chart/chart_line.rs
@@ -37,8 +37,8 @@ impl ChartLine {
}
#[wasm_bindgen(js_name = "setColor")]
- pub fn set_color(&mut self, color: &Color) -> ChartLine {
- self.inner.set_color(color.inner);
+ pub fn set_color(&mut self, color: Color) -> ChartLine {
+ self.inner.set_color(color);
self.clone()
}
diff --git a/rust/src/wrapper/chart/chart_pattern_fill.rs b/rust/src/wrapper/chart/chart_pattern_fill.rs
index e90d0c7..73b4dd7 100644
--- a/rust/src/wrapper/chart/chart_pattern_fill.rs
+++ b/rust/src/wrapper/chart/chart_pattern_fill.rs
@@ -25,14 +25,14 @@ impl ChartPatternFill {
}
#[wasm_bindgen(js_name = "setBackgroundColor")]
- pub fn set_background_color(&mut self, color: &Color) -> ChartPatternFill {
- self.inner.set_background_color(color.inner);
+ pub fn set_background_color(&mut self, color: Color) -> ChartPatternFill {
+ self.inner.set_background_color(color);
self.clone()
}
#[wasm_bindgen(js_name = "setForegroundColor")]
- pub fn set_foreground_color(&mut self, color: &Color) -> ChartPatternFill {
- self.inner.set_foreground_color(color.inner);
+ pub fn set_foreground_color(&mut self, color: Color) -> ChartPatternFill {
+ self.inner.set_foreground_color(color);
self.clone()
}
}
diff --git a/rust/src/wrapper/chart/chart_solid_fill.rs b/rust/src/wrapper/chart/chart_solid_fill.rs
index 3d03926..e43d67a 100644
--- a/rust/src/wrapper/chart/chart_solid_fill.rs
+++ b/rust/src/wrapper/chart/chart_solid_fill.rs
@@ -31,8 +31,8 @@ impl ChartSolidFill {
/// @param {Color} color - The color property.
/// @return {ChartSolidFill} - The ChartSolidFill instance.
#[wasm_bindgen(js_name = "setColor")]
- pub fn set_color(&mut self, color: &Color) -> ChartSolidFill {
- self.inner.set_color(color.inner);
+ pub fn set_color(&mut self, color: Color) -> ChartSolidFill {
+ self.inner.set_color(color);
self.clone()
}
diff --git a/rust/src/wrapper/color.rs b/rust/src/wrapper/color.rs
index 3ab9724..0a2d1a3 100644
--- a/rust/src/wrapper/color.rs
+++ b/rust/src/wrapper/color.rs
@@ -1,172 +1,79 @@
+
use rust_xlsxwriter as xlsx;
use wasm_bindgen::prelude::*;
+use tsify::Tsify;
+use serde::{Deserialize, Serialize};
/// The `Color` enum defines Excel colors that can be used throughout the
/// `rust_xlsxwriter` APIs.
-///
+///
/// There are 3 types of colors within the enum:
-///
+///
/// 1. Predefined named colors like `Color::Green`.
/// 2. User defined RGB colors such as `Color::RGB(0x4F026A)` using a format
-/// similar to html colors like `#RRGGBB`, except as an integer.
+/// similar to html colors like `#RRGGBB`, except as an integer.
/// 3. Theme colors from the standard palette of 60 colors like `Color::Theme(9,
-/// 4)`. The theme colors are shown in the image below.
-///
-///
-///
-/// The syntax for theme colors in `Color` is `Theme(color, shade)` where
-/// `color` is one of the 0-9 values on the top row and `shade` is the
-/// variant in the associated column from 0-5. For example "White, background
-/// 1" in the top left is `Theme(0, 0)` and "Orange, Accent 6, Darker 50%" in
-/// the bottom right is `Theme(9, 5)`.
-///
+/// 4)`. The theme colors are shown in the image below.
+///
+///
+///
+/// The syntax for theme colors in `Color` is `Theme(color, shade)` where
+/// `color` is one of the 0-9 values on the top row and `shade` is the
+/// variant in the associated column from 0-5. For example "White, background
+/// 1" in the top left is `Theme(0, 0)` and "Orange, Accent 6, Darker 50%" in
+/// the bottom right is `Theme(9, 5)`.
+///
/// Note, there are no plans to support anything other than the default Excel
/// "Office" theme.
-#[derive(Debug, Copy, Clone, Default)]
-#[wasm_bindgen]
-pub struct Color {
- pub(crate) inner: xlsx::Color,
-}
-
-impl Color {
- pub fn new(inner: xlsx::Color) -> Self {
- Color { inner }
- }
+#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, Tsify)]
+#[tsify(into_wasm_abi, from_wasm_abi)]
+pub enum Color {
+ RGB(u32),
+ Theme(u8, u8),
+ #[default]
+ Default,
+ Automatic,
+ Black,
+ Blue,
+ Brown,
+ Cyan,
+ Gray,
+ Green,
+ Lime,
+ Magenta,
+ Navy,
+ Orange,
+ Pink,
+ Purple,
+ Red,
+ Silver,
+ White,
+ Yellow,
}
-
-#[wasm_bindgen]
-impl Color {
- /// The default color for an Excel property.
- #[wasm_bindgen(constructor)]
- pub fn default() -> Color {
- Color::new(xlsx::Color::Default)
- }
-
- /// A user defined RGB color in the range 0x000000 (black) to 0xFFFFFF
- /// (white). Any values outside this range will be ignored with a a warning.
- #[wasm_bindgen]
- pub fn rgb(hex: u32) -> Color {
- Color::new(xlsx::Color::RGB(hex))
- }
-
- /// A theme color on the default palette (see the image above). The syntax
- /// for theme colors is `Theme(color, shade)` where `color` is one of the
- /// 0-9 values on the top row and `shade` is the variant in the associated
- /// column from 0-5. Any values outside these ranges will be ignored with a
- /// a warning.
- #[wasm_bindgen]
- pub fn theme(color: u8, shade: u8) -> Color {
- Color::new(xlsx::Color::Theme(color, shade))
- }
-
- /// The Automatic color for an Excel property. This is usually the same as
- /// the `Default` color but can vary according to system settings.
- #[wasm_bindgen]
- pub fn automatic() -> Color {
- Color::new(xlsx::Color::Automatic)
- }
-
- /// Convert from a Html style color string line "#6495ED" into a {@link Color} enum value.
- #[wasm_bindgen]
- pub fn parse(s: &str) -> Color {
- let color = xlsx::Color::from(s);
- Color { inner: color }
- }
-
- /// The color Black with a RGB value of 0x000000.
- #[wasm_bindgen]
- pub fn black() -> Color {
- Color::new(xlsx::Color::Black)
- }
-
- /// The color Blue with a RGB value of 0x0000FF.
- #[wasm_bindgen]
- pub fn blue() -> Color {
- Color::new(xlsx::Color::Blue)
- }
-
- /// The color Brown with a RGB value of 0x800000.
- #[wasm_bindgen]
- pub fn brown() -> Color {
- Color::new(xlsx::Color::Brown)
- }
-
- /// The color Cyan with a RGB value of 0x00FFFF.
- #[wasm_bindgen]
- pub fn cyan() -> Color {
- Color::new(xlsx::Color::Cyan)
- }
-
- /// The color Gray with a RGB value of 0x808080.
- #[wasm_bindgen]
- pub fn gray() -> Color {
- Color::new(xlsx::Color::Gray)
- }
-
- /// The color Green with a RGB value of 0x008000.
- #[wasm_bindgen]
- pub fn green() -> Color {
- Color::new(xlsx::Color::Green)
- }
-
- /// The color Lime with a RGB value of 0x00FF00.
- #[wasm_bindgen]
- pub fn lime() -> Color {
- Color::new(xlsx::Color::Lime)
- }
-
- /// The color Magenta with a RGB value of 0xFF00FF.
- #[wasm_bindgen]
- pub fn magenta() -> Color {
- Color::new(xlsx::Color::Magenta)
- }
-
- /// The color Navy with a RGB value of 0x000080.
- #[wasm_bindgen]
- pub fn navy() -> Color {
- Color::new(xlsx::Color::Navy)
- }
-
- /// The color Orange with a RGB value of 0xFF6600.
- #[wasm_bindgen]
- pub fn orange() -> Color {
- Color::new(xlsx::Color::Orange)
- }
-
- /// The color Pink with a RGB value of 0xFFC0CB.
- #[wasm_bindgen]
- pub fn pink() -> Color {
- Color::new(xlsx::Color::Pink)
- }
-
- /// The color Purple with a RGB value of 0x800080.
- #[wasm_bindgen]
- pub fn purple() -> Color {
- Color::new(xlsx::Color::Purple)
- }
-
- /// The color Red with a RGB value of 0xFF0000.
- #[wasm_bindgen]
- pub fn red() -> Color {
- Color::new(xlsx::Color::Red)
- }
-
- /// The color Silver with a RGB value of 0xC0C0C0.
- #[wasm_bindgen]
- pub fn silver() -> Color {
- Color::new(xlsx::Color::Silver)
- }
-
- /// The color White with a RGB value of 0xFFFFFF.
- #[wasm_bindgen]
- pub fn white() -> Color {
- Color::new(xlsx::Color::White)
- }
-
- /// The color Yellow with a RGB value of 0xFFFF00
- #[wasm_bindgen]
- pub fn yellow() -> Color {
- Color::new(xlsx::Color::Yellow)
+impl From:: for xlsx::Color {
+ fn from(value: Color) -> Self {
+ match value {
+ Color::RGB(rgb) => xlsx::Color::RGB(rgb),
+ Color::Theme(color, shade) => xlsx::Color::Theme(color, shade),
+ Color::Default => xlsx::Color::Default,
+ Color::Automatic => xlsx::Color::Automatic,
+ Color::Black => xlsx::Color::Black,
+ Color::Blue => xlsx::Color::Blue,
+ Color::Brown => xlsx::Color::Brown,
+ Color::Cyan => xlsx::Color::Cyan,
+ Color::Gray => xlsx::Color::Gray,
+ Color::Green => xlsx::Color::Green,
+ Color::Lime => xlsx::Color::Lime,
+ Color::Magenta => xlsx::Color::Magenta,
+ Color::Navy => xlsx::Color::Navy,
+ Color::Orange => xlsx::Color::Orange,
+ Color::Pink => xlsx::Color::Pink,
+ Color::Purple => xlsx::Color::Purple,
+ Color::Red => xlsx::Color::Red,
+ Color::Silver => xlsx::Color::Silver,
+ Color::White => xlsx::Color::White,
+ Color::Yellow => xlsx::Color::Yellow,
+ }
}
}
diff --git a/rust/src/wrapper/format.rs b/rust/src/wrapper/format.rs
index 33e7c36..c4be565 100644
--- a/rust/src/wrapper/format.rs
+++ b/rust/src/wrapper/format.rs
@@ -313,7 +313,7 @@ impl Format {
/// TODO: example omitted
#[wasm_bindgen(js_name = "setBorderColor", skip_jsdoc)]
pub fn set_border_color(&self, color: Color) -> Format {
- impl_method!(self.set_border_color(color.inner));
+ impl_method!(self.set_border_color(color));
}
/// Set the cell bottom border style.
@@ -336,7 +336,7 @@ impl Format {
/// @return {Format} - The Format instance.
#[wasm_bindgen(js_name = "setBorderBottomColor", skip_jsdoc)]
pub fn set_border_bottom_color(&self, color: Color) -> Format {
- impl_method!(self.set_border_bottom_color(color.inner));
+ impl_method!(self.set_border_bottom_color(color));
}
/// Set the cell top border style.
@@ -359,7 +359,7 @@ impl Format {
/// @return {Format} - The Format instance.
#[wasm_bindgen(js_name = "setBorderTopColor", skip_jsdoc)]
pub fn set_border_top_color(&self, color: Color) -> Format {
- impl_method!(self.set_border_top_color(color.inner));
+ impl_method!(self.set_border_top_color(color));
}
/// Set the cell left border style.
@@ -382,7 +382,7 @@ impl Format {
/// @return {Format} - The Format instance.
#[wasm_bindgen(js_name = "setBorderLeftColor", skip_jsdoc)]
pub fn set_border_left_color(&self, color: Color) -> Format {
- impl_method!(self.set_border_left_color(color.inner));
+ impl_method!(self.set_border_left_color(color));
}
/// Set the cell right border style.
@@ -405,7 +405,7 @@ impl Format {
/// @return {Format} - The Format instance.
#[wasm_bindgen(js_name = "setBorderRightColor", skip_jsdoc)]
pub fn set_border_right_color(&self, color: Color) -> Format {
- impl_method!(self.set_border_right_color(color.inner));
+ impl_method!(self.set_border_right_color(color));
}
/// Set the Format border diagonal property.
@@ -432,7 +432,7 @@ impl Format {
/// @return {Format} - The Format instance.
#[wasm_bindgen(js_name = "setBorderDiagonalColor", skip_jsdoc)]
pub fn set_border_diagonal_color(&self, color: Color) -> Format {
- impl_method!(self.set_border_diagonal_color(color.inner));
+ impl_method!(self.set_border_diagonal_color(color));
}
/// Set the cell diagonal border direction type.
@@ -470,7 +470,7 @@ impl Format {
/// TODO: example omitted
#[wasm_bindgen(js_name = "setFontColor", skip_jsdoc)]
pub fn set_font_color(&self, color: Color) -> Format {
- impl_method!(self.set_font_color(color.inner));
+ impl_method!(self.set_font_color(color));
}
/// Set the Format font family property.
@@ -570,7 +570,7 @@ impl Format {
/// TODO: example omitted
#[wasm_bindgen(js_name = "setForegroundColor", skip_jsdoc)]
pub fn set_foreground_color(&self, color: Color) -> Format {
- impl_method!(self.set_foreground_color(color.inner));
+ impl_method!(self.set_foreground_color(color));
}
/// Set the Format pattern background color property.
@@ -586,7 +586,7 @@ impl Format {
/// TODO: example omitted
#[wasm_bindgen(js_name = "setBackgroundColor", skip_jsdoc)]
pub fn set_background_color(&self, color: Color) -> Format {
- impl_method!(self.set_background_color(color.inner));
+ impl_method!(self.set_background_color(color));
}
/// Set the number format for a Format.
diff --git a/rust/src/wrapper/note.rs b/rust/src/wrapper/note.rs
index bf6ea88..4d12d00 100644
--- a/rust/src/wrapper/note.rs
+++ b/rust/src/wrapper/note.rs
@@ -68,7 +68,7 @@ impl Note {
}
#[wasm_bindgen(js_name = "setBackgroundColor", skip_jsdoc)]
pub fn set_background_color(&self, color: Color) -> Note {
- impl_method!(self.set_background_color(color.inner));
+ impl_method!(self.set_background_color(color));
}
#[wasm_bindgen(js_name = "setFontName", skip_jsdoc)]
pub fn set_font_name(&self, font_name: &str) -> Note {
diff --git a/rust/tools/rust-toolchain.toml b/rust/tools/rust-toolchain.toml
index 74324bb..1c9923c 100644
--- a/rust/tools/rust-toolchain.toml
+++ b/rust/tools/rust-toolchain.toml
@@ -1,4 +1,4 @@
[toolchain]
-channel = "nightly-2025-07-16"
+channel = "nightly-2025-07-31"
components = ["rustc", "cargo"]
profile = "minimal"
diff --git a/rust/tools/wrapper_generator/Cargo.lock b/rust/tools/wrapper_generator/Cargo.lock
new file mode 100644
index 0000000..20c805d
--- /dev/null
+++ b/rust/tools/wrapper_generator/Cargo.lock
@@ -0,0 +1,590 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 4
+
+[[package]]
+name = "aho-corasick"
+version = "1.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "anstream"
+version = "0.6.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933"
+dependencies = [
+ "anstyle",
+ "anstyle-parse",
+ "anstyle-query",
+ "anstyle-wincon",
+ "colorchoice",
+ "is_terminal_polyfill",
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle"
+version = "1.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd"
+
+[[package]]
+name = "anstyle-parse"
+version = "0.2.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2"
+dependencies = [
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle-query"
+version = "1.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9"
+dependencies = [
+ "windows-sys",
+]
+
+[[package]]
+name = "anstyle-wincon"
+version = "3.0.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882"
+dependencies = [
+ "anstyle",
+ "once_cell_polyfill",
+ "windows-sys",
+]
+
+[[package]]
+name = "anyhow"
+version = "1.0.98"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
+
+[[package]]
+name = "camino"
+version = "1.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0da45bc31171d8d6960122e222a67740df867c1dd53b4d51caa297084c185cab"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "cargo-manifest"
+version = "0.19.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1d8af896b707212cd0e99c112a78c9497dd32994192a463ed2f7419d29bd8c6"
+dependencies = [
+ "serde",
+ "thiserror",
+ "toml",
+]
+
+[[package]]
+name = "cargo-platform"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "cargo_metadata"
+version = "0.19.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba"
+dependencies = [
+ "camino",
+ "cargo-platform",
+ "semver",
+ "serde",
+ "serde_json",
+ "thiserror",
+]
+
+[[package]]
+name = "clap"
+version = "4.5.41"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "be92d32e80243a54711e5d7ce823c35c41c9d929dc4ab58e1276f625841aadf9"
+dependencies = [
+ "clap_builder",
+ "clap_derive",
+]
+
+[[package]]
+name = "clap_builder"
+version = "4.5.41"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "707eab41e9622f9139419d573eca0900137718000c517d47da73045f54331c3d"
+dependencies = [
+ "anstream",
+ "anstyle",
+ "clap_lex",
+ "strsim",
+]
+
+[[package]]
+name = "clap_derive"
+version = "4.5.41"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ef4f52386a59ca4c860f7393bcf8abd8dfd91ecccc0f774635ff68e92eeef491"
+dependencies = [
+ "heck",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "clap_lex"
+version = "0.7.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675"
+
+[[package]]
+name = "colorchoice"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
+
+[[package]]
+name = "crate-inspector"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "61b5a358fe54350c5d7dea8c6d83191dedf33b3ba8fc947a6640d0948c3305e4"
+dependencies = [
+ "rustdoc-json",
+ "rustdoc-types",
+ "serde_json",
+]
+
+[[package]]
+name = "equivalent"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
+
+[[package]]
+name = "hashbrown"
+version = "0.15.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5"
+
+[[package]]
+name = "heck"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
+
+[[package]]
+name = "indenter"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
+
+[[package]]
+name = "indexmap"
+version = "2.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661"
+dependencies = [
+ "equivalent",
+ "hashbrown",
+]
+
+[[package]]
+name = "is_terminal_polyfill"
+version = "1.70.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
+
+[[package]]
+name = "itoa"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
+
+[[package]]
+name = "memchr"
+version = "2.7.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
+
+[[package]]
+name = "once_cell"
+version = "1.21.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
+
+[[package]]
+name = "once_cell_polyfill"
+version = "1.70.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad"
+
+[[package]]
+name = "pin-project-lite"
+version = "0.2.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.95"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "regex"
+version = "1.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-automata",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.4.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
+
+[[package]]
+name = "ruast"
+version = "0.0.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c1f05cb5b2fd678b0c38e2b97737509f7202e63cfb66278c963c6e4ee8a8c23"
+dependencies = [
+ "indenter",
+]
+
+[[package]]
+name = "rustdoc-json"
+version = "0.9.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df2651f0825c500d39b0471dd502356ee74f069b60de1d7c87e9b13bf41c68f8"
+dependencies = [
+ "cargo-manifest",
+ "cargo_metadata",
+ "serde",
+ "thiserror",
+ "toml",
+ "tracing",
+]
+
+[[package]]
+name = "rustdoc-types"
+version = "0.54.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "814bc4dddadb32bef41ec20b836b35aa7aaf88356c721a0dd9cda41331394b8b"
+dependencies = [
+ "serde",
+ "serde_derive",
+]
+
+[[package]]
+name = "ryu"
+version = "1.0.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
+
+[[package]]
+name = "semver"
+version = "1.0.26"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "serde"
+version = "1.0.219"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.219"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.141"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "30b9eff21ebe718216c6ec64e1d9ac57087aad11efc64e32002bce4a0d4c03d3"
+dependencies = [
+ "itoa",
+ "memchr",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "serde_spanned"
+version = "0.6.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "strsim"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
+
+[[package]]
+name = "syn"
+version = "2.0.104"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "thiserror"
+version = "2.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
+dependencies = [
+ "thiserror-impl",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "2.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "toml"
+version = "0.8.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362"
+dependencies = [
+ "indexmap",
+ "serde",
+ "serde_spanned",
+ "toml_datetime",
+ "toml_edit",
+]
+
+[[package]]
+name = "toml_datetime"
+version = "0.6.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "toml_edit"
+version = "0.22.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a"
+dependencies = [
+ "indexmap",
+ "serde",
+ "serde_spanned",
+ "toml_datetime",
+ "toml_write",
+ "winnow",
+]
+
+[[package]]
+name = "toml_write"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801"
+
+[[package]]
+name = "tracing"
+version = "0.1.41"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
+dependencies = [
+ "pin-project-lite",
+ "tracing-attributes",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-attributes"
+version = "0.1.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "tracing-core"
+version = "0.1.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678"
+dependencies = [
+ "once_cell",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
+
+[[package]]
+name = "utf8parse"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
+
+[[package]]
+name = "windows-sys"
+version = "0.59.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
+
+[[package]]
+name = "winnow"
+version = "0.7.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f3edebf492c8125044983378ecb5766203ad3b4c2f7a922bd7dd207f6d443e95"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "wrapper_generator"
+version = "0.1.0"
+dependencies = [
+ "anyhow",
+ "clap",
+ "crate-inspector",
+ "regex",
+ "ruast",
+ "rustdoc-types",
+]
diff --git a/rust/tools/wrapper_generator/Cargo.toml b/rust/tools/wrapper_generator/Cargo.toml
new file mode 100644
index 0000000..75550f9
--- /dev/null
+++ b/rust/tools/wrapper_generator/Cargo.toml
@@ -0,0 +1,13 @@
+[package]
+name = "wrapper_generator"
+version = "0.1.0"
+edition = "2021"
+description = "Tool to automatically generate wasm_xlsxwriter wrapper methods from rust_xlsxwriter"
+
+[dependencies]
+anyhow = "1.0"
+clap = { version = "4.4", features = ["derive"] }
+crate-inspector = "0.3.0"
+ruast = "0.0.20"
+rustdoc-types = "0.54.0"
+regex = "1.10.2"
diff --git a/rust/tools/wrapper_generator/src/common.rs b/rust/tools/wrapper_generator/src/common.rs
new file mode 100644
index 0000000..8775270
--- /dev/null
+++ b/rust/tools/wrapper_generator/src/common.rs
@@ -0,0 +1,37 @@
+use ruast::*;
+
+/// Generate common use statements for struct wrappers
+pub fn generate_use_statements() -> Vec