jramos57/cuneiform
Pure Swift library for reading and writing Office Open XML SpreadsheetML (.xlsx) files with comprehensive formula support.
Features
✅ Read & Write - Open existing workbooks and create new ones ✅ 467 Excel Functions - Comprehensive formula engine (97% full implementations) ✅ Advanced Queries - Built-in filtering, searching, and range operations ✅ High Performance - Lazy loading and memory-efficient streaming ✅ Type Safety - Swift 6 with Sendable types and typed throws ✅ Cross-Platform - macOS, iOS, tvOS, watchOS, visionOS, and Linux ✅ Zero Dependencies - Pure Swift with no external libraries ✅ Well-Tested - 834 passing tests ensuring reliability
Quick Start
Reading Workbooks
import Cuneiform
// Open an .xlsx file
let workbook = try Workbook.open(url: fileURL)
// Access a sheet and read cells
if let sheet = try workbook.sheet(named: "Sheet1") {
// Get a cell value (type-safe enum)
if let value = sheet.cell(at: "A1") {
switch value {
case .text(let text): print("Text: \(text)")
case .number(let num): print("Number: \(num)")
case .date(let date): print("Date: \(date)")
case .boolean(let bool): print("Boolean: \(bool)")
case .error(let err): print("Error: \(err)")
case .empty: print("Empty cell")
}
}
// Iterate rows efficiently
for row in sheet.rows() {
for (ref, value) in row {
print("\(ref): \(value)")
}
}
}Writing Workbooks
import Cuneiform
// Create a new workbook
var writer = WorkbookWriter()
let sheetIndex = writer.addSheet(named: "Data")
// Write cells with various types
writer.modifySheet(at: sheetIndex) { sheet in
sheet.writeText("Name", to: "A1")
sheet.writeNumber(42, to: "B1")
sheet.writeBoolean(true, to: "C1")
sheet.writeFormula("SUM(B1:B10)", to: "B11")
sheet.writeDate(Date(), to: "D1")
}
// Save to disk
try writer.save(to: outputURL)Advanced Queries
// Filter rows by condition
let activeRows = sheet.rows { cells in
cells.contains { $0.value == .text("Active") }
}
// Find cells matching criteria
let highValues = sheet.findAll { ref, value in
if case .number(let num) = value {
return num > 100
}
return false
}
// Access entire columns
let columnB = sheet.column("B")
let total = columnB.reduce(0.0) { sum, (_, value) in
if case .number(let num) = value {
return sum + num
}
return sum
}
// Work with ranges
let range = sheet.range("A1:C10")
for (ref, value) in range {
// Process each cell
}Formula Evaluation
// Evaluate formulas programmatically
let evaluator = FormulaEvaluator(workbook: workbook)
// Simple calculations
let result = try evaluator.evaluate("=SUM(1, 2, 3)") // 6.0
// Reference cells
let total = try evaluator.evaluate("=SUM(A1:A10)")
// Complex formulas with nested functions
let analysis = try evaluator.evaluate(
"=IF(AVERAGE(A1:A10) > 50, \"High\", \"Low\")"
)Documentation
Comprehensive documentation is available:
- 📚 API Documentation - Complete API reference
- 🚀 Getting Started Guide - Installation and quick start
- 📖 Architecture Overview - System design and layers
- ⚡️ Performance Tuning - Optimization strategies
- ✍️ Writing Workbooks - Creating Excel files
- 🔍 Advanced Queries - Filtering and searching
- 🧮 Formula Engine - 467 supported functions
- 📊 Formula Reference - Complete function catalog
- ⚠️ Error Handling - Error patterns and recovery
- 🔄 Migration Guide - Migrate from CoreXLSX
Tutorials
Step-by-step tutorials for common tasks:
- 📊 Data Analysis Tutorial - Reading and analyzing data
- 📝 Report Generation Tutorial - Creating multi-sheet reports
Examples
Complete example projects:
- 💡 Data Analysis Example - Extract and compute statistics
- 📈 Report Generation Example - Create structured reports
Installation
Swift Package Manager
Add Cuneiform to your Package.swift:
dependencies: [
.package(url: "https://github.com/jramos57/cuneiform.git", from: "0.1.0")
]Then add it to your target:
targets: [
.target(
name: "YourTarget",
dependencies: ["Cuneiform"]
)
]Xcode
- File → Add Package Dependencies
- Enter:
https://github.com/jramos57/cuneiform.git - Select version:
0.1.0or higher
Requirements
- Swift 6.0 or later
- macOS 13.0+ / iOS 16.0+ / tvOS 16.0+ / watchOS 9.0+ / visionOS 1.0+
- Linux (Ubuntu 20.04+ or similar)
Formula Support
Cuneiform includes a comprehensive formula engine with 467 Excel-compatible functions across 12 categories:
| Category | Functions | Examples | |----------|-----------|----------| | Mathematical | 75+ | SUM, AVERAGE, ROUND, SIN, COS, SQRT, POWER | | Statistical | 100+ | MIN, MAX, MEDIAN, STDEV, PERCENTILE, CORREL | | Text | 40 | LEFT, RIGHT, MID, CONCAT, FIND, SUBSTITUTE | | Date & Time | 27 | TODAY, DATE, YEAR, MONTH, WEEKDAY, EOMONTH | | Financial | 55 | PMT, PV, FV, IRR, NPV, PRICE, YIELD | | Logical | 11 | IF, AND, OR, NOT, IFS, SWITCH, IFERROR | | Lookup | 35 | VLOOKUP, XLOOKUP, INDEX, MATCH, FILTER, SORT | | Engineering | 60+ | CONVERT, HEX2DEC, COMPLEX, BESSELI, ERF | | Database | 10 | DSUM, DAVERAGE, DCOUNT, DMAX, DMIN | | Information | 28 | ISBLANK, ISERROR, TYPE, CELL, INFO | | Compatibility | 23 | Legacy functions + LAMBDA, LET, MAP, REDUCE | | Web Service | 8 | HYPERLINK, WEBSERVICE, ENCODEURL |
Implementation Status: 97% full implementations, 2% partial, 1% stubs
See the Formula Reference for complete documentation.
Performance
Benchmark Results
Typical performance on modern hardware:
| Operation | Performance | |-----------|-------------| | Read 1,000 rows | ~34ms | | Write 1,000 rows (10 columns) | ~50ms | | Round-trip 500 rows | ~80ms | | Find operations (1,000 rows) | <1ms | | Range query (2,600 cells) | ~660ms |
Optimization Tips
- Use lazy iteration -
sheet.rows()for memory-efficient processing - Batch writes - Modify multiple cells before saving
- Limit queries - Use
find()instead offindAll()when appropriate - Defer loading - Access sheets only when needed (automatic lazy loading)
See the Performance Tuning Guide for detailed optimization strategies.
Advanced Features
Sheet Protection
// Protect a sheet with custom permissions
writer.modifySheet(at: sheetIndex) { sheet in
var options = SheetProtectionOptions()
options.formatCells = false
options.insertRows = false
sheet.protectSheet(password: "secret", options: options)
}Hyperlinks
// External hyperlink
sheet.addHyperlinkExternal(
at: "A1",
url: "https://example.com",
display: "Visit Site"
)
// Internal hyperlink
sheet.addHyperlinkInternal(
at: "B1",
location: "Sheet2!A1",
display: "Go to Sheet2"
)Data Validations
// Read validations from a sheet
let validations = sheet.validations(at: "A2")
for validation in validations {
print("Type: \(validation.kind)")
print("Formula: \(validation.formula1 ?? "")")
}Named Ranges
// Access defined names
if let (sheet, range) = workbook.definedNameRange("SalesData") {
for (ref, value) in range {
print("\(ref): \(value)")
}
}Merge Cells
// Merge a range of cells
sheet.mergeCells(range: "A1:C1")Comments
// Read comments from cells
let comments = sheet.comments(at: "A1")
for comment in comments {
print("Author: \(comment.author)")
print("Text: \(comment.text)")
}Charts
// Access chart data (read-only)
for chart in sheet.charts {
print("Chart: \(chart.title ?? "Untitled")")
print("Type: \(chart.type)")
}Architecture
Cuneiform is built with a clean, layered architecture:
Layer 1: OPC Package
- ZIP archive management
- Part reading and relationships
- Content type resolution
Layer 2: Parsers
- XML parsing for all SpreadsheetML parts
- Shared strings, styles, workbooks, worksheets
- Charts, pivot tables, comments
Layer 3: Domain
- High-level
WorkbookandSheetAPIs - Cell value resolution
- Query and filtering operations
Layer 4: Builders
- XML generation for all parts
- Workbook and worksheet construction
- ZIP packaging for output
Layer 5: Formula Engine
- Formula parsing (tokenization + AST)
- Expression evaluation (467 functions)
- Cell reference resolution
See the Architecture Guide for detailed information.
Contributing
Bug reports are welcome! Please use the issue tracker to report bugs.
Note: This project does not accept pull requests. If you have a feature suggestion, please open a feature request instead.
See CONTRIBUTING.md for more information.
License
Cuneiform is released under the MIT License. See LICENSE for details.
Credits
Created by Jonathan Ramos
Resources
- Documentation: https://jramos57.github.io/cuneiform/documentation/cuneiform/
- GitHub: https://github.com/jramos57/cuneiform
- Issues: https://github.com/jramos57/cuneiform/issues
- Discussions: https://github.com/jramos57/cuneiform/discussions
- OOXML Standard: ECMA-376
Made with ❤️ using Swift
Package Metadata
Repository: jramos57/cuneiform
Default branch: main
README: README.md