A MoonBit port of the Go excelize library for reading and writing XLSX (Excel) spreadsheets.
Dependencies
{
"deps": {
"bobzhang/mbtexcel": "0.1.1"
}
}{
"import": ["bobzhang/mbtexcel"]
}///|
test "workbook roundtrip" {
let workbook = new_workbook()
let sheet = workbook.add_sheet("Sheet1")
sheet.set_cell("A1", "hello")
sheet.set_cell_formula("B1", "A1", value="hello")
let bytes = write(workbook)
let parsed = read(bytes)
inspect(parsed.get_cell("Sheet1", "A1"), content="Some(\"hello\")")
inspect(parsed.get_cell_formula("Sheet1", "B1"), content="Some(\"A1\")")
}///|
test "row and column helpers" {
let workbook = new_workbook()
ignore(workbook.add_sheet("Sheet1"))
workbook.set_row("Sheet1", 1, ["a", "b", "c"])
workbook.set_col("Sheet1", 2, ["x", "y"])
inspect(
workbook.get_row("Sheet1", 1),
content=(
#|["a", "x", "c"]
),
)
inspect(workbook.get_col("Sheet1", 2), content="[\"x\", \"y\"]")
}///|
test "cell reference conversion" {
// Split cell name into column and row
inspect(split_cell_name("AB123"), content="(\"AB\", 123)")
// Join column and row into cell name
inspect(join_cell_name("AB", 123), content="AB123")
// Convert between cell name and coordinates (1-indexed)
inspect(cell_name_to_coordinates("B3"), content="(2, 3)")
inspect(coordinates_to_cell_name(2, 3), content="B3")
// Absolute references
inspect(coordinates_to_cell_name(2, 3, abs=true), content="$B$3")
// Column name/number conversion
inspect(column_name_to_number("AB"), content="28")
inspect(column_number_to_name(28), content="AB")
}///|
test "multiple sheets" {
let workbook = new_workbook()
ignore(workbook.add_sheet("Sales"))
ignore(workbook.add_sheet("Expenses"))
ignore(workbook.add_sheet("Summary"))
// Get list of all sheets
inspect(
workbook.get_sheet_list(),
content="[\"Sales\", \"Expenses\", \"Summary\"]",
)
// Access sheet by name
guard workbook.sheet("Sales") is Some(sales) else { return }
sales.set_cell("A1", "Revenue")
inspect(sales.get_cell("A1"), content="Some(\"Revenue\")")
}///|
test "cell value types" {
let workbook = new_workbook()
let sheet = workbook.add_sheet("Data")
// String values
sheet.set_cell("A1", "Hello")
// Numeric values (auto-detected from string)
sheet.set_cell("A2", "42")
sheet.set_cell("A3", "3.14159")
// Using typed CellValue enum for explicit types
sheet.set_cell_value("B1", String("Text"))
sheet.set_cell_value("B2", Numeric(100.5))
sheet.set_cell_value("B3", Bool(true))
// Read back values
inspect(sheet.get_cell("A1"), content="Some(\"Hello\")")
inspect(sheet.get_cell("A2"), content="Some(\"42\")")
inspect(sheet.get_cell_value_raw("B2"), content="Some(Numeric(100.5))")
inspect(sheet.get_cell_value_raw("B3"), content="Some(Bool(true))")
}///|
test "formulas" {
let workbook = new_workbook()
let sheet = workbook.add_sheet("Calc")
// Set some values
sheet.set_cell("A1", "10")
sheet.set_cell("A2", "20")
sheet.set_cell("A3", "30")
// Set formula with cached value
sheet.set_cell_formula("A4", "SUM(A1:A3)", value="60")
// Read formula back
inspect(sheet.get_cell_formula("A4"), content="Some(\"SUM(A1:A3)\")")
// Calculate formula value
inspect(workbook.calc_cell_value("Calc", "A4"), content="60")
}///|
test "merged cells" {
let workbook = new_workbook()
let sheet = workbook.add_sheet("Report")
// Set value before merging
sheet.set_cell("A1", "Title")
// Merge cells A1:D1
sheet.merge_cells("A1:D1")
// Get merged cell ranges
inspect(sheet.merged_cells(), content="[\"A1:D1\"]")
}moon run cmd/demosmoon run cmd/demos -- dashboard demos_out
moon run cmd/demos -- stream_big demos_out 50000scripts/test_demo_roundtrip.shscripts/test_parity_gates.shscripts/test_parity_gates.sh
scripts/test_semantic_parity.sh
scripts/test_semantic_parity_fast.sh
scripts/test_semantic_parity_ultrasmoke.sh| Function | Description |
|---|---|
| new_workbook() | Create an empty workbook (no sheets) |
| new_file() | Create a workbook with one sheet named "Sheet1" |
| read(bytes) | Parse XLSX bytes into a workbook |
| read_with_password(bytes, password) | Parse encrypted XLSX |
| open_file(path) | (async) Open XLSX file from path |
| Function | Description |
|---|---|
| write(workbook) | Serialize workbook to XLSX bytes |
| write_with_password(workbook, password) | Serialize with encryption |
| encrypt(bytes) | Encrypt raw XLSX bytes |
| decrypt(bytes) | Decrypt encrypted XLSX bytes |
| Function | Description |
|---|---|
| split_cell_name("A1") | Returns ("A", 1) |
| join_cell_name("A", 1) | Returns "A1" |
| cell_name_to_coordinates("B3") | Returns (2, 3) (col, row) |
| coordinates_to_cell_name(2, 3) | Returns "B3" |
| column_name_to_number("AB") | Returns 28 |
| column_number_to_name(28) | Returns "AB" |
| Function | Description |
|---|---|
| rgb_to_hsl(r, g, b) | Convert RGB to HSL |
| hsl_to_rgb(h, s, l) | Convert HSL to RGB |
| theme_color(base, tint) | Apply tint to theme color |
| Function | Description |
|---|---|
| excel_date_to_time(serial) | Convert Excel date serial to ZonedDateTime |
///|
fn safe_read(bytes : Bytes) -> Result[@xlsx.Workbook, Error] {
try! @mbtexcel.read(bytes)
}bobzhang/mbtexcel # Facade package (this package)
-> bobzhang/mbtexcel/xlsx # Core implementation
-> bobzhang/mbtexcel/ooxml # OOXML metadata helpers
-> bobzhang/mbtexcel/zip # ZIP archive handling
-> bobzhang/mbtexcel/crypto # Cryptographic operations
-> bobzhang/mbtexcel/base64 # Base64 encodingpub suberror UtfIndexError {
OutOfRange(Int, Int)
InvalidBoundary(Int)
InvalidUtf8(Int)
} derive(Show)let (col, row) = cell_name_to_coordinates("B3")
// col = 2, row = 3let num = column_name_to_number("AA")
// num = 27let name = column_number_to_name(27)
// name = "AA"let ref = coordinates_to_cell_name(2, 3)
// ref = "B3"
let abs_ref = coordinates_to_cell_name(2, 3, abs=true)
// abs_ref = "$B$3"fn excel_date_to_time(excel_date : Double, use_1904_format? : Bool) -> ZonedDateTime raise XlsxErrorlet dt = excel_date_to_time(44197.5) // 2021-01-01 12:00:00fn hsl_to_rgb(h : Double, s : Double, l : Double) -> (Byte, Byte, Byte)let (r, g, b) = hsl_to_rgb(0.0, 1.0, 0.5) // Red
// r = 255, g = 0, b = 0let ref = join_cell_name("AB", 123)
// ref = "AB123"let dv = new_data_validation(true)
dv.set_drop_list(["Option1", "Option2", "Option3"])
dv.set_sqref("A1:A100")
sheet.add_data_validation(dv)let wb = new_file()
wb.set_cell("Sheet1", "A1", "Hello")let wb = new_workbook()
let sheet = wb.add_sheet("Data")let wb = open_file("report.xlsx")
let wb_protected = open_file("secret.xlsx", password="pass123")let bytes = read_file("report.xlsx")
let wb = read(bytes)
let value = wb.get_cell("Sheet1", "A1")let bytes = read_file("protected.xlsx")
let wb = read_with_password(bytes, "secret123")fn rgb_to_hsl(r : Byte, g : Byte, b : Byte) -> (Double, Double, Double)let (h, s, l) = rgb_to_hsl(255, 0, 0) // Red
// h ≈ 0, s = 1.0, l = 0.5let (col, row) = split_cell_name("AB123")
// col = "AB", row = 123fn theme_color(base_color : String, tint : Double) -> Stringlet lighter = theme_color("FF0000", 0.5) // Lighter red
let darker = theme_color("FF0000", -0.5) // Darker redlet wb = new_file()
wb.set_cell("Sheet1", "A1", "Hello")
let bytes = write(wb)
write_file("output.xlsx", bytes)let wb = new_file()
wb.set_cell("Sheet1", "A1", "Confidential")
let bytes = write_with_password(wb, "secret123")A MoonBit port of the Go excelize library for reading and writing XLSX (Excel) spreadsheets.
Dependencies