{"id":50745074,"url":"https://github.com/fatbobman/Objects2XLSX","last_synced_at":"2026-06-27T23:00:51.869Z","repository":{"id":301324251,"uuid":"996429382","full_name":"fatbobman/Objects2XLSX","owner":"fatbobman","description":"A powerful, type-safe Swift library for converting Swift objects to Excel (.xlsx) files. Objects2XLSX provides a modern, declarative API for creating professional Excel spreadsheets with full styling support, multiple worksheets, and real-time progress tracking.","archived":false,"fork":false,"pushed_at":"2025-07-10T09:51:30.000Z","size":841,"stargazers_count":50,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2026-06-21T14:59:59.325Z","etag":null,"topics":["business","data-analysis","dataset","excel","export-excel","reporting","spredsheet","swift","xlsx","xlsxwriter"],"latest_commit_sha":null,"homepage":"https://fatbobman.com","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fatbobman.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":null,"patreon":"fatbobman","open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"lfx_crowdfunding":null,"polar":null,"buy_me_a_coffee":"fatbobman","thanks_dev":null,"custom":["https://afdian.com","https://www.paypal.com/paypalme/fatbobman"]}},"created_at":"2025-06-05T00:08:16.000Z","updated_at":"2026-02-14T12:43:17.000Z","dependencies_parsed_at":"2025-07-18T06:48:12.211Z","dependency_job_id":null,"html_url":"https://github.com/fatbobman/Objects2XLSX","commit_stats":null,"previous_names":["fatbobman/objects2xlsx"],"tags_count":11,"template":false,"template_full_name":null,"purl":"pkg:github/fatbobman/Objects2XLSX","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fatbobman%2FObjects2XLSX","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fatbobman%2FObjects2XLSX/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fatbobman%2FObjects2XLSX/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fatbobman%2FObjects2XLSX/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fatbobman","download_url":"https://codeload.github.com/fatbobman/Objects2XLSX/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fatbobman%2FObjects2XLSX/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34870654,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-27T02:00:06.362Z","response_time":126,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["business","data-analysis","dataset","excel","export-excel","reporting","spredsheet","swift","xlsx","xlsxwriter"],"created_at":"2026-06-10T20:00:38.587Z","updated_at":"2026-06-27T23:00:51.862Z","avatar_url":"https://github.com/fatbobman.png","language":"Swift","funding_links":["https://patreon.com/fatbobman","https://buymeacoffee.com/fatbobman","https://afdian.com","https://www.paypal.com/paypalme/fatbobman"],"categories":["Swift"],"sub_categories":[],"readme":"# Objects2XLSX\n\n[![Swift](https://img.shields.io/badge/Swift-6.0+-orange.svg)](https://swift.org)\n[![Platform](https://img.shields.io/badge/Platform-macOS%20%7C%20iOS%20%7C%20tvOS%20%7C%20watchOS%20%7C%20Linux-lightgrey.svg)](https://swift.org)\n[![Swift Package Manager](https://img.shields.io/badge/SPM-Compatible-brightgreen.svg)](https://swift.org/package-manager)\n[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)\n[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/fatbobman/Objects2XLSX)\n\n**Languages**: [English](README.md) | [中文](README_CN.md) | [日本語](README_JP.md)\n\nA powerful, type-safe Swift library for converting Swift objects to Excel (.xlsx) files. Objects2XLSX provides a modern, declarative API for creating professional Excel spreadsheets with full styling support, multiple worksheets, and real-time progress tracking.\n\n## ✨ Features\n\n### 🎯 **Type-Safe Design**\n\n- **Generic Sheets**: `Sheet\u003cObjectType\u003e` with compile-time type safety\n- **KeyPath Integration**: Direct property mapping with `\\.propertyName`\n- **Swift 6 Compliant**: Full support for Swift's strict concurrency model\n\n### 📊 **Comprehensive Excel Support**\n\n- **Excel-Compliant Output**: Generated XLSX files strictly conform to Excel specifications with no warnings or compatibility issues\n- **Enhanced Column API**: Simplified, type-safe column declarations with automatic type inference\n- **Smart Nil Handling**: `.defaultValue()` method for elegant optional value management\n- **Type Conversions**: Powerful `.toString()` method for custom data transformations\n- **Multiple Data Types**: String, Int, Double, Bool, Date, URL, and Percentage with full optional support\n- **Full Styling System**: Fonts, colors, borders, fills, alignment, and number formatting\n- **Multiple Worksheets**: Create workbooks with unlimited sheets\n- **Method Chaining**: Fluent API for combining width, styling, and data transformations\n\n### 🎨 **Advanced Styling**\n\n- **Professional Appearance**: Rich formatting options matching Excel's capabilities\n- **Style Hierarchy**: Book → Sheet → Column → Cell styling with proper precedence\n- **Custom Themes**: Create consistent styling across your documents\n- **Border Management**: Precise border control with automatic region detection\n\n### 🚀 **Performance \u0026 Usability**\n\n- **Standards Compliant**: Generated files open seamlessly in Excel, Numbers, Google Sheets, and LibreOffice without warnings\n- **Async Data Support**: Safe cross-thread data fetching with `@Sendable` async data providers\n- **Memory Efficient**: Stream-based processing for large datasets\n- **Progress Tracking**: Real-time progress updates with AsyncStream\n- **Cross-Platform**: Pure Swift implementation supporting macOS, iOS, tvOS, watchOS, and Linux\n- **Zero Dependencies**: No external dependencies except optional SimpleLogger\n\n### 🛠 **Developer Experience**\n\n- **Simplified API**: Intuitive, chainable column declarations with automatic type inference\n- **Live Demo Project**: Comprehensive example showcasing all library features\n- **Builder Pattern**: Declarative DSL for creating sheets and columns\n- **Comprehensive Documentation**: Detailed API documentation with real-world examples\n- **Extensive Testing**: 340+ tests ensuring reliability across all features\n- **SwiftFormat Integration**: Consistent code formatting with Git hooks\n\n## 📋 Requirements\n\n- **Swift**: 6.0+\n- **iOS**: 15.0+\n- **macOS**: 12.0+\n- **tvOS**: 15.0+\n- **watchOS**: 8.0+\n- **Linux**: Ubuntu 20.04+ (with Swift 6.0+)\n\n\u003e **Note**: Current testing covers iOS 15+ and macOS 12+. If you have access to older system versions and would like to test compatibility, please let us know so we can adjust the minimum version requirements accordingly.\n\n## 📦 Installation\n\n### Swift Package Manager\n\nAdd Objects2XLSX to your project using Xcode's Package Manager or by adding it to your `Package.swift`:\n\n```swift\ndependencies: [\n    .package(url: \"https://github.com/fatbobman/Objects2XLSX.git\", from: \"1.2.1\")\n]\n```\n\nThen add it to your target:\n\n```swift\n.target(\n    name: \"YourTarget\",\n    dependencies: [\"Objects2XLSX\"]\n)\n```\n\n## 🚀 Quick Start\n\n### Basic Usage\n\n```swift\nimport Objects2XLSX\n\n// 1. Define your data model\nstruct Person: Sendable {\n    let name: String\n    let age: Int\n    let email: String\n}\n\n// 2. Prepare your data\nlet people = [\n    Person(name: \"Alice Smith\", age: 28, email: \"alice@example.com\"),\n    Person(name: \"Bob Johnson\", age: 35, email: \"bob@example.com\"),\n    Person(name: \"Carol Davis\", age: 42, email: \"carol@example.com\")\n]\n\n// 3. Create a sheet with type-safe columns\nlet sheet = Sheet\u003cPerson\u003e(name: \"Employees\", dataProvider: { people }) {\n    Column(name: \"Full Name\", keyPath: \\.name)\n    Column(name: \"Age\", keyPath: \\.age)\n    Column(name: \"Email Address\", keyPath: \\.email)\n}\n\n// 4. Create workbook and generate Excel file\nlet book = Book(style: BookStyle()) {\n    sheet\n}\n\nlet outputURL = URL(fileURLWithPath: \"/path/to/employees.xlsx\")\ntry book.write(to: outputURL)\n```\n\n### Async Data Providers (NEW!)\n\nObjects2XLSX now supports asynchronous data fetching for thread-safe operations with Core Data, SwiftData, and API calls:\n\n```swift\nimport Objects2XLSX\n\n// Define Sendable data transfer objects\nstruct PersonData: Sendable {\n    let name: String\n    let department: String\n    let salary: Double\n    let hireDate: Date\n}\n\n// Create data service with async fetching\nclass DataService {\n    private let persistentContainer: NSPersistentContainer\n    \n    @Sendable\n    func fetchEmployees() async -\u003e [PersonData] {\n        await withCheckedContinuation { continuation in\n            // Execute in Core Data's thread\n            persistentContainer.viewContext.perform {\n                let employees = // ... fetch Core Data objects\n                \n                // Convert to Sendable objects\n                let data = employees.map { employee in\n                    PersonData(\n                        name: employee.name ?? \"\",\n                        department: employee.department?.name ?? \"\",\n                        salary: employee.salary,\n                        hireDate: employee.hireDate ?? Date()\n                    )\n                }\n                continuation.resume(returning: data)\n            }\n        }\n    }\n}\n\n// Create sheet with async data provider\nlet dataService = DataService(persistentContainer: container)\n\nlet sheet = Sheet\u003cPersonData\u003e(\n    name: \"Async Employees\",\n    asyncDataProvider: dataService.fetchEmployees  // 🚀 Async \u0026 thread-safe!\n) {\n    Column(name: \"Name\", keyPath: \\.name)\n    Column(name: \"Department\", keyPath: \\.department)\n    Column(name: \"Salary\", keyPath: \\.salary)\n    Column(name: \"Hire Date\", keyPath: \\.hireDate)\n}\n\nlet book = Book(style: BookStyle()) { sheet }\n\n// Generate Excel file asynchronously\nlet outputURL = try await book.writeAsync(to: URL(fileURLWithPath: \"/path/to/report.xlsx\"))\n```\n\n**Key Benefits:**\n- ✅ **Thread Safety**: Data fetching happens in the correct thread context\n- ✅ **Type Safety**: `@Sendable` constraints ensure safe data transfer\n- ✅ **Mixed Sources**: Combine sync and async sheets in the same workbook\n- ✅ **Progress Tracking**: Full async progress monitoring support\n\n### Try the Live Demo\n\nExperience all features with our comprehensive demo project:\n\n```bash\n# Clone the repository\ngit clone https://github.com/fatbobman/Objects2XLSX.git\ncd Objects2XLSX\n\n# Run the demo with different options\nswift run Objects2XLSXDemo --help\nswift run Objects2XLSXDemo -s medium -v demo.xlsx\nswift run Objects2XLSXDemo -s large -t mixed -v -b output.xlsx\n```\n\nThe demo generates a professional Excel workbook with three worksheets showcasing:\n\n- **Employee data** with corporate styling and data transformations\n- **Product catalog** with modern styling and conditional formatting  \n- **Order history** with default styling and calculated fields\n\n**Demo Features:**\n\n- 🎨 Three professional styling themes (Corporate, Modern, Default)\n- 📊 Multiple data sizes (small: 30, medium: 150, large: 600 records)\n- 🔧 All column types and advanced features demonstrated\n- ⚡ Real-time progress tracking and performance benchmarks\n- 📁 Ready-to-open Excel files showcasing library capabilities\n\n### Multiple Data Types \u0026 Enhanced Column API\n\nObjects2XLSX features a simplified, type-safe column API that automatically handles various Swift data types:\n\n```swift\nstruct Employee: Sendable {\n    let name: String\n    let age: Int\n    let salary: Double?        // Optional salary\n    let bonus: Double?         // Optional bonus\n    let isManager: Bool\n    let hireDate: Date\n    let profileURL: URL?       // Optional profile URL\n}\n\nlet employees = [\n    Employee(\n        name: \"John Doe\",\n        age: 30,\n        salary: 75000.50,\n        bonus: nil,           // No bonus this period\n        isManager: true,\n        hireDate: Date(),\n        profileURL: URL(string: \"https://company.com/profiles/john\")\n    )\n]\n\nlet sheet = Sheet\u003cEmployee\u003e(name: \"Staff\", dataProvider: { employees }) {\n    // Simple non-optional columns\n    Column(name: \"Name\", keyPath: \\.name)\n    Column(name: \"Age\", keyPath: \\.age)\n    \n    // Optional columns with default values\n    Column(name: \"Salary\", keyPath: \\.salary)\n        .defaultValue(0.0)\n        .width(12)\n    \n    Column(name: \"Bonus\", keyPath: \\.bonus)\n        .defaultValue(0.0)\n        .width(10)\n    \n    // Boolean and date columns\n    Column(name: \"Manager\", keyPath: \\.isManager, booleanExpressions: .yesAndNo)\n    Column(name: \"Hire Date\", keyPath: \\.hireDate, timeZone: .current)\n    \n    // Optional URL with default\n    Column(name: \"Profile\", keyPath: \\.profileURL)\n        .defaultValue(URL(string: \"https://company.com/default\")!)\n}\n```\n\n## 🔧 Enhanced Column Features\n\n### Simplified Column Declarations\n\nThe new API provides intuitive, type-safe column creation with automatic type inference:\n\n```swift\nstruct Product: Sendable {\n    let id: Int\n    let name: String\n    let price: Double?\n    let discount: Double?\n    let stock: Int?\n    let isActive: Bool?\n}\n\nlet sheet = Sheet\u003cProduct\u003e(name: \"Products\", dataProvider: { products }) {\n    // Non-optional columns (simple syntax)\n    Column(name: \"ID\", keyPath: \\.id)\n    Column(name: \"Product Name\", keyPath: \\.name)\n    \n    // Optional columns with default values\n    Column(name: \"Price\", keyPath: \\.price)\n        .defaultValue(0.0)\n    \n    Column(name: \"Stock\", keyPath: \\.stock)\n        .defaultValue(0)\n    \n    Column(name: \"Active\", keyPath: \\.isActive)\n        .defaultValue(true)\n}\n```\n\n### Advanced Type Conversions\n\nTransform column data using the powerful `toString` method:\n\n```swift\nlet sheet = Sheet\u003cProduct\u003e(name: \"Products\", dataProvider: { products }) {\n    // Convert price ranges to categories\n    Column(name: \"Price Category\", keyPath: \\.price)\n        .defaultValue(0.0)\n        .toString { (price: Double) in\n            switch price {\n            case 0..\u003c50: \"Budget\"\n            case 50..\u003c200: \"Mid-Range\"\n            default: \"Premium\"\n            }\n        }\n    \n    // Convert stock levels to status\n    Column(name: \"Stock Status\", keyPath: \\.stock)\n        .defaultValue(0)\n        .toString { (stock: Int) in\n            stock == 0 ? \"Out of Stock\" : \n            stock \u003c 10 ? \"Low Stock\" : \"In Stock\"\n        }\n    \n    // Convert optional discount to display format\n    Column(name: \"Discount Info\", keyPath: \\.discount)\n        .toString { (discount: Double?) in\n            guard let discount = discount else { return \"No Discount\" }\n            return String(format: \"%.0f%% Off\", discount * 100)\n        }\n}\n```\n\n### Flexible Nil Handling\n\nControl how optional values are handled:\n\n```swift\nlet sheet = Sheet\u003cEmployee\u003e(name: \"Employees\", dataProvider: { employees }) {\n    // Option 1: Use default values\n    Column(name: \"Salary\", keyPath: \\.salary)\n        .defaultValue(0.0)  // nil becomes 0.0\n    \n    // Option 2: Keep empty cells (default behavior)\n    Column(name: \"Bonus\", keyPath: \\.bonus)\n        // nil values remain as empty cells\n    \n    // Option 3: Transform with custom nil handling\n    Column(name: \"Salary Range\", keyPath: \\.salary)\n        .toString { (salary: Double?) in\n            guard let salary = salary else { return \"Not Specified\" }\n            return salary \u003e 50000 ? \"High\" : \"Standard\"\n        }\n}\n```\n\n### Method Chaining\n\nCombine multiple configurations elegantly:\n\n```swift\nlet sheet = Sheet\u003cEmployee\u003e(name: \"Employees\", dataProvider: { employees }) {\n    Column(name: \"Salary Level\", keyPath: \\.salary)\n        .defaultValue(0.0)                    // Handle nil values\n        .toString { $0 \u003e 50000 ? \"Senior\" : \"Junior\" }  // Transform to categories\n        .width(15)                            // Set column width\n        .bodyStyle(CellStyle(                 // Apply styling\n            font: Font(bold: true),\n            fill: Fill.solid(.lightBlue)\n        ))\n}\n```\n\n## 🎨 Styling \u0026 Formatting\n\n### Professional Styling\n\n```swift\n// Create custom header style\nlet headerStyle = CellStyle(\n    font: Font(size: 14, name: \"Arial\", bold: true, color: .white),\n    fill: Fill.solid(.blue),\n    alignment: Alignment(horizontal: .center, vertical: .center),\n    border: Border.all(style: .thin, color: .black)\n)\n\n// Create data cell style\nlet dataStyle = CellStyle(\n    font: Font(size: 11, name: \"Calibri\"),\n    alignment: Alignment(horizontal: .left, wrapText: true),\n    border: Border.outline(style: .thin, color: .gray)\n)\n\n// Apply styles to sheet using enhanced API\nlet styledSheet = Sheet\u003cPerson\u003e(name: \"Styled Employees\", dataProvider: { people }) {\n    Column(name: \"Name\", keyPath: \\.name)\n        .width(20)\n        .headerStyle(headerStyle)\n        .bodyStyle(dataStyle)\n    \n    Column(name: \"Age\", keyPath: \\.age)\n        .width(8)\n        .headerStyle(headerStyle)\n        .bodyStyle(CellStyle(alignment: Alignment(horizontal: .center)))\n}\n```\n\n### Color Customization\n\n```swift\n// Predefined colors\nlet redFill = Fill.solid(.red)\nlet blueFill = Fill.solid(.blue)\n\n// Custom colors\nlet customColor = Color(red: 255, green: 128, blue: 0) // Orange\nlet hexColor = Color(hex: \"#FF5733\") // From hex string\nlet transparentColor = Color(red: 255, green: 0, blue: 0, alpha: .medium) // 50% transparent red\n\n// Gradient fills (advanced)\nlet gradientFill = Fill.gradient(\n    .linear(angle: 90),\n    colors: [.blue, .white, .red]\n)\n```\n\n### Border Styles\n\n```swift\n// Simple borders\nlet thinBorder = Border.all(style: .thin, color: .black)\nlet thickOutline = Border.outline(style: .thick, color: .blue)\n\n// Selective borders\nlet horizontalOnly = Border.horizontal(style: .medium, color: .gray)\nlet verticalOnly = Border.vertical(style: .thin, color: .lightGray)\n\n// Custom border configuration\nlet customBorder = Border(\n    left: Border.Side(style: .thick, color: .red),\n    right: Border.Side(style: .thin, color: .black),\n    top: Border.Side(style: .dashed, color: .blue),\n    bottom: nil // No bottom border\n)\n```\n\n## 📈 Multiple Worksheets\n\nCreate workbooks with multiple sheets for different data types:\n\n```swift\nstruct Product: Sendable {\n    let name: String\n    let price: Double?\n    let category: String\n    let inStock: Bool?\n}\n\nstruct Customer: Sendable {\n    let name: String\n    let email: String?\n    let registrationDate: Date\n    let isPremium: Bool?\n}\n\n// Create multiple sheets with enhanced API\nlet productsSheet = Sheet\u003cProduct\u003e(name: \"Products\", dataProvider: { products }) {\n    Column(name: \"Product Name\", keyPath: \\.name)\n        .width(25)\n    \n    Column(name: \"Price\", keyPath: \\.price)\n        .defaultValue(0.0)\n        .width(12)\n    \n    Column(name: \"Category\", keyPath: \\.category)\n        .width(15)\n    \n    Column(name: \"In Stock\", keyPath: \\.inStock)\n        .defaultValue(false)\n        .width(10)\n}\n\nlet customersSheet = Sheet\u003cCustomer\u003e(name: \"Customers\", dataProvider: { customers }) {\n    Column(name: \"Customer Name\", keyPath: \\.name)\n        .width(20)\n    \n    Column(name: \"Email\", keyPath: \\.email)\n        .defaultValue(\"no-email@company.com\")\n        .width(25)\n    \n    Column(name: \"Registration\", keyPath: \\.registrationDate)\n        .width(15)\n    \n    Column(name: \"Premium\", keyPath: \\.isPremium)\n        .defaultValue(false)\n        .toString { $0 ? \"Premium Member\" : \"Standard Member\" }\n        .width(15)\n}\n\n// Combine sheets in workbook\nlet book = Book(style: BookStyle()) {\n    productsSheet\n    customersSheet\n}\n\ntry book.write(to: outputURL)\n```\n\n## 📊 Progress Tracking\n\nMonitor Excel generation progress for both synchronous and asynchronous operations:\n\n```swift\nlet book = Book(style: BookStyle()) {\n    // Mix of sync and async sheets\n    Sheet\u003cProduct\u003e(name: \"Products\", dataProvider: { products }) {\n        Column(name: \"Name\", keyPath: \\.name)\n        Column(name: \"Price\", keyPath: \\.price)\n    }\n    \n    Sheet\u003cEmployee\u003e(name: \"Employees\", asyncDataProvider: fetchEmployeesAsync) {\n        Column(name: \"Name\", keyPath: \\.name)\n        Column(name: \"Department\", keyPath: \\.department)\n    }\n}\n\n// Monitor progress\nTask {\n    for await progress in book.progressStream {\n        print(\"Progress: \\(Int(progress.progressPercentage * 100))%\")\n        print(\"Current step: \\(progress.description)\")\n        \n        if progress.isFinal {\n            print(\"✅ Excel file generation completed!\")\n            break\n        }\n    }\n}\n\n// Generate file synchronously\nTask {\n    do {\n        try book.write(to: outputURL)\n        print(\"📁 File saved to: \\(outputURL.path)\")\n    } catch {\n        print(\"❌ Error: \\(error)\")\n    }\n}\n\n// OR generate file asynchronously (supports async data providers)\nTask {\n    do {\n        let outputURL = try await book.writeAsync(to: outputURL)\n        print(\"📁 Async file saved to: \\(outputURL.path)\")\n    } catch {\n        print(\"❌ Error: \\(error)\")\n    }\n}\n```\n\n## 🔧 Advanced Configuration\n\n### Working Directory Management\n\nObjects2XLSX provides flexible control over where temporary working files are stored during XLSX generation. This is particularly useful when working with temporary directories to avoid file system pollution:\n\n```swift\n// Default behavior - working directory alongside output file\ntry book.write(to: outputURL)\n// Output: /path/to/report.xlsx\n// Working dir: /path/to/report.temp/\n\n// System temporary directory - recommended for temp outputs\ntry book.write(to: outputURL, workingDirectory: .systemTemp)\n// Output: /path/to/report.xlsx\n// Working dir: /tmp/Objects2XLSX_UUID/\n\n// Custom working directory\nlet workspaceURL = URL(fileURLWithPath: \"/custom/workspace\")\ntry book.write(to: outputURL, workingDirectory: .custom(workspaceURL))\n// Output: /path/to/report.xlsx\n// Working dir: /custom/workspace/Objects2XLSX_UUID/\n```\n\n**Best Practices for Temporary Directory Usage:**\n\n```swift\nextension Book {\n    /// Smart writing that automatically chooses appropriate working directory\n    func writeSmartly(to url: URL) throws -\u003e URL {\n        let tempDir = FileManager.default.temporaryDirectory\n        \n        if url.path.hasPrefix(tempDir.path) {\n            // Output is in temp directory - use isolated working space\n            return try write(to: url, workingDirectory: .systemTemp)\n        } else {\n            // Output is in regular directory - use default behavior\n            return try write(to: url)\n        }\n    }\n}\n\n// Usage examples\nlet documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]\nlet tempURL = FileManager.default.temporaryDirectory\n\n// ✅ Good: Documents directory with default behavior\ntry book.write(to: documentsURL.appendingPathComponent(\"report.xlsx\"))\n\n// ✅ Good: Temp directory with isolated working space\ntry book.write(\n    to: tempURL.appendingPathComponent(\"report.xlsx\"), \n    workingDirectory: .systemTemp\n)\n\n// ✅ Good: Smart automatic selection\ntry book.writeSmartly(to: outputURL)\n```\n\n**Working Directory Strategies:**\n\n- **`.alongsideOutput` (default)**: Creates `.temp` folder next to output file\n  - ✅ Good for: Documents, Downloads, custom directories\n  - ⚠️ Avoid for: System temporary directories (causes pollution)\n\n- **`.systemTemp`**: Uses isolated temporary directory\n  - ✅ Good for: Any output in system temp directories\n  - ✅ Prevents: Temporary directory structure pollution\n  - 🚀 Recommended: When output path starts with temp directory\n\n- **`.custom(URL)`**: Uses specified directory for working files\n  - ✅ Good for: Custom build systems, specific workspace requirements\n  - 🔧 Control: Full control over working file location\n\n### Custom Sheet Styling\n\n```swift\nvar sheetStyle = SheetStyle()\nsheetStyle.defaultRowHeight = 20\nsheetStyle.defaultColumnWidth = 15\nsheetStyle.showGridlines = false\nsheetStyle.freezePanes = .freezeTopRow()\nsheetStyle.zoom = .custom(125)\n\nlet sheet = Sheet\u003cPerson\u003e(name: \"Custom Sheet\", dataProvider: { people }, style: sheetStyle) {\n    // ... columns\n}\n```\n\n### Number Formatting\n\n```swift\nlet sheet = Sheet\u003cProduct\u003e(name: \"Products\", dataProvider: { products }) {\n    Column(name: \"Product\", keyPath: \\.name)\n    \n    Column(name: \"Price\", keyPath: \\.price)\n        .bodyStyle(CellStyle(numberFormat: .currency))\n    \n    Column(name: \"Discount\", keyPath: \\.discountRate)\n        .bodyStyle(CellStyle(numberFormat: .percentage(precision: 1)))\n    \n    Column(name: \"Launch Date\", keyPath: \\.launchDate)\n        .bodyStyle(CellStyle(numberFormat: .date))\n}\n```\n\n### Memory Optimization for Large Datasets\n\n```swift\n// Use lazy data loading for large datasets\nlet largeDataSheet = Sheet\u003cLargeDataModel\u003e(name: \"Big Data\", dataProvider: {\n    // Load data only when needed\n    return fetchLargeDataset()\n}) {\n    Column(name: \"ID\", keyPath: \\.id)\n    Column(name: \"Value\", keyPath: \\.value)\n    // ... more columns\n}\n```\n\n### Async Data Loading \u0026 Thread Safety\n\nObjects2XLSX provides thread-safe async data loading for complex scenarios:\n\n```swift\n// Thread-safe async data fetching\nclass EmployeeDataService {\n    private let coreDataStack: CoreDataStack\n    \n    @Sendable\n    func fetchEmployeesAsync() async -\u003e [EmployeeData] {\n        await withCheckedContinuation { continuation in\n            // Switch to Core Data's thread\n            coreDataStack.viewContext.perform {\n                do {\n                    let request: NSFetchRequest\u003cEmployee\u003e = Employee.fetchRequest()\n                    let employees = try self.coreDataStack.viewContext.fetch(request)\n                    \n                    // Convert to Sendable DTOs\n                    let employeeData = employees.map { EmployeeData(from: $0) }\n                    continuation.resume(returning: employeeData)\n                } catch {\n                    continuation.resume(returning: [])\n                }\n            }\n        }\n    }\n}\n\n// Use async data provider\nlet service = EmployeeDataService(coreDataStack: stack)\n\nlet book = Book(style: BookStyle()) {\n    // Sync sheet\n    Sheet\u003cProduct\u003e(name: \"Products\", dataProvider: { loadProducts() }) {\n        Column(name: \"Name\", keyPath: \\.name)\n        Column(name: \"Price\", keyPath: \\.price)\n    }\n    \n    // Async sheet - data fetched in Core Data thread\n    Sheet\u003cEmployeeData\u003e(name: \"Employees\", asyncDataProvider: service.fetchEmployeesAsync) {\n        Column(name: \"Name\", keyPath: \\.name)\n        Column(name: \"Department\", keyPath: \\.department)\n        Column(name: \"Salary\", keyPath: \\.salary)\n    }\n}\n\n// Generate with async support\nlet outputURL = try await book.writeAsync(to: URL(fileURLWithPath: \"/path/to/report.xlsx\"))\n```\n\n**Thread Safety Guidelines:**\n\n- ✅ **Create Book on any thread** - Book creation is thread-safe\n- ✅ **Data fetching in correct context** - Async providers handle thread switching\n- ✅ **Mixed sync/async sheets** - Combine both types seamlessly\n- ⚠️ **Use `writeAsync()` for async providers** - Ensures proper async data loading\n\n## 📚 Architecture Overview\n\nObjects2XLSX follows a hierarchical architecture:\n\n```\nBook (Workbook)\n├── BookStyle (Global styling)\n├── Sheet\u003cObjectType\u003e (Individual worksheets)\n│   ├── SheetStyle (Sheet-specific styling)\n│   └── Column\u003cObjectType, InputType, OutputType\u003e\n│       ├── ColumnStyle (Column-specific styling)\n│       └── Cell (Individual cells)\n│           └── CellStyle (Cell-specific styling)\n```\n\n### Style Precedence\n\nStyles are applied with the following precedence (highest to lowest):\n\n1. **Cell Style** - Individual cell styling\n2. **Column Style** - Column-wide styling  \n3. **Sheet Style** - Sheet-wide styling\n4. **Book Style** - Workbook defaults\n\n## 🧪 Testing\n\nRun the comprehensive test suite:\n\n```bash\n# Run all tests\nswift test\n\n# Run tests with verbose output\nswift test --verbose\n\n# Run specific test cases\nswift test --filter BookAPITests\n```\n\nThe library includes:\n\n- **340+ Unit Tests** covering all components including enhanced column API\n- **Integration Tests** for complete workflows and demo scenarios\n- **Performance Tests** for large dataset handling and memory optimization\n- **Cross-Platform Tests** ensuring compatibility across all supported platforms\n\n## 🛠 Development\n\n### Code Formatting\n\nThe project uses SwiftFormat with Git hooks for consistent code style:\n\n```bash\n# Format code manually\nswiftformat Sources Tests\n\n# Check formatting without changes\nswiftformat --lint Sources Tests\n\n# The pre-push hook automatically formats code before pushing\ngit push\n```\n\n### Building\n\n```bash\n# Build the library\nswift build\n\n# Build for release\nswift build -c release\n\n# Generate Xcode project\nswift package generate-xcodeproj\n```\n\n## 🤝 Contributing\n\nWe welcome contributions! Please see our contributing guidelines:\n\n1. **Fork** the repository\n2. **Create** a feature branch (`git checkout -b feature/amazing-feature`)\n3. **Commit** your changes (`git commit -m 'Add amazing feature'`)\n4. **Push** to the branch (`git push origin feature/amazing-feature`)\n5. **Open** a Pull Request\n\n### Code Standards\n\n- Follow Swift API Design Guidelines\n- Add comprehensive documentation for public APIs\n- Include unit tests for new functionality\n- Ensure SwiftFormat compliance\n- Maintain Swift 6 concurrency compliance\n\n## 📋 Requirements\n\n- **Swift 6.0+**\n- **Platforms**: macOS 13+, iOS 16+, tvOS 16+, watchOS 9+, Linux\n- **Dependencies**: None (except optional SimpleLogger for logging)\n\n## 👨‍💻 Author\n\n**Fatbobman (东坡肘子)**\n\n- Blog: [https://fatbobman.com](https://fatbobman.com)\n- GitHub: [@fatbobman](https://github.com/fatbobman)\n- X: [@fatbobman](https://x.com/fatbobman)\n- LinkedIn: [@fatbobman](https://www.linkedin.com/in/fatbobman/)\n- Mastodon: [@fatbobman@mastodon.social](https://mastodon.social/@fatbobman)\n- BlueSky: [@fatbobman.com](https://bsky.app/profile/fatbobman.com)\n\n### 📰 Stay Connected\n\nDon't miss out on the latest updates and excellent articles about Swift, SwiftUI, Core Data, and SwiftData. Subscribe to **[Fatbobman's Swift Weekly](https://weekly.fatbobman.com)** and receive weekly insights and valuable content directly to your inbox.\n\n## 💖 Support the Project\n\nIf you find Objects2XLSX useful and want to support its continued development:\n\n- [☕️ Buy Me A Coffee](https://buymeacoffee.com/fatbobman) - Support development with a small donation\n- [💳 PayPal](https://www.paypal.com/paypalme/fatbobman) - Alternative donation method\n\nYour support helps maintain and improve this open-source project. Thank you! 🙏\n\n## 📄 License\n\nObjects2XLSX is released under the Apache License 2.0. See [LICENSE](LICENSE) for details.\n\n### Third-Party Dependencies\n\nThis project includes the following third-party software:\n\n- **[SimpleLogger](https://github.com/fatbobman/SimpleLogger)** - MIT License\n  - A lightweight logging library for Swift\n  - Copyright (c) 2024 Fatbobman\n\n## 🙏 Acknowledgments\n\n- Built with ❤️ using Swift 6's modern concurrency features\n- Inspired by the need for type-safe Excel generation in Swift\n- Thanks to the Swift community for feedback and contributions\n\n## 📖 Documentation\n\nFor detailed API documentation, examples, and advanced usage patterns, explore the comprehensive DocC documentation included with the library. You can access it directly in Xcode after importing the package, or build it locally using:\n\n```bash\nswift package generate-documentation --target Objects2XLSX\n```\n\nThe library includes extensive inline documentation for all public APIs, complete with usage examples and best practices.\n\n---\n\n**Made with ❤️ by the Swift Community**\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffatbobman%2FObjects2XLSX","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffatbobman%2FObjects2XLSX","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffatbobman%2FObjects2XLSX/lists"}