Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Generates data export/import infrastructure for JSON, CSV, PDF formats with GDPR data portability, share sheet integration, and file import. Use when user wants data export functionality, CSV/JSON/PDF export, GDPR compliance data portability, import from files, or share sheet for data.
.claude/skills/rshankras-data-export/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-08 | ✗→✓ | ▲ Improved | 215% | 0% |
| case-19 | ✗→✓ | ▲ Improved | 39% | 0% |
| case-04 | ✓→✓ | = Same ✓ | 87% | 0% |
| case-05 | ✓→✓ | = Same ✓ | 63% | 0% |
| case-06 | ✓→✓ | = Same ✓ | 97% | 0% |
Generate production data export and import infrastructure -- JSON export via Codable, CSV generation with proper escaping, PDF report rendering with UIGraphicsPDFRenderer, GDPR-compliant full data export, file import with UTType-based picker, and share sheet integration. No third-party dependencies.
Use this skill when the user:
Search for existing export code:
Glob: **/*Export*.swift, **/*Import*.swift, **/*CSV*.swift, **/*PDF*.swift
Grep: "UIGraphicsPDFRenderer" or "CSVExport" or "UIActivityViewController" or "ShareLink" or "fileExporter"If existing export code found:
Search for data models that need exporting:
Grep: "@Model" or "NSManagedObject" or "struct.*Codable" or "class.*Codable"Identify the models to build export conformances for.
Ask user via AskUserQuestion:
Read templates.md for production Swift code.
Generate these files:
DataExportManager.swift -- Central export coordinator with format routingDataExportable.swift -- Protocol for models that support exportBased on configuration:
CSVExporter.swift -- If CSV format selectedPDFExporter.swift -- If PDF format selectedIf import capability selected:
DataImporter.swift -- File picker and format parserCheck project structure:
Sources/ exists -> Sources/DataExport/App/ exists -> App/DataExport/DataExport/After generation, provide:
DataExport/
├── DataExportable.swift # Protocol for exportable models
├── DataExportManager.swift # Central export coordinator
├── CSVExporter.swift # CSV generation (optional)
├── PDFExporter.swift # PDF rendering (optional)
└── DataImporter.swift # File import (optional)Make a model exportable:
swiftstruct Expense: Codable, DataExportable { let id: UUID let title: String let amount: Double let date: Date let category: String // DataExportable conformance static var csvHeaders: [String] { ["ID", "Title", "Amount", "Date", "Category"] } var csvRow: [String] { [id.uuidString, title, String(format: "%.2f", amount), ISO8601DateFormatter().string(from: date), category] } var pdfDescription: String { "\(title) - $\(String(format: "%.2f", amount)) (\(category))" } }
Export from a view:
swiftstruct ExpenseListView: View { let expenses: [Expense] @State private var exportURL: URL? @State private var showShareSheet = false var body: some View { List(expenses) { expense in ExpenseRow(expense: expense) } .toolbar { Menu { Button("Export as JSON") { Task { await exportAs(.json) } } Button("Export as CSV") { Task { await exportAs(.csv) } } Button("Export as PDF") { Task { await exportAs(.pdf) } } } label: { Label("Export", systemImage: "square.and.arrow.up") } } .sheet(isPresented: $showShareSheet) { if let exportURL { ShareSheet(activityItems: [exportURL]) } } } private func exportAs(_ format: DataExportManager.ExportFormat) async { do { exportURL = try await DataExportManager.shared.export( expenses, format: format, filename: "expenses" ) showShareSheet = true } catch { // Handle error } } }
SwiftUI ShareLink (iOS 16+):
swiftif let url = exportURL { ShareLink(item: url) { Label("Share Export", systemImage: "square.and.arrow.up") } }
Import from file picker:
swiftstruct ImportView: View { @State private var showFilePicker = false @State private var importedItems: [Expense] = [] var body: some View { Button("Import Data") { showFilePicker = true } .fileImporter( isPresented: $showFilePicker, allowedContentTypes: DataImporter.supportedTypes ) { result in Task { let url = try result.get() importedItems = try await DataImporter.importFile( from: url, as: Expense.self ) } } } }
For full GDPR compliance, export ALL user data:
swiftfunc exportAllUserData() async throws -> URL { let allData = GDPRExportData( profile: try await fetchUserProfile(), expenses: try await fetchAllExpenses(), settings: try await fetchUserSettings(), exportDate: Date(), appVersion: Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "1.0" ) let encoder = JSONEncoder() encoder.outputFormatting = [.prettyPrinted, .sortedKeys] encoder.dateEncodingStrategy = .iso8601 let data = try encoder.encode(allData) let url = FileManager.default.temporaryDirectory .appendingPathComponent("user-data-export.json") try data.write(to: url) return url }
swift@Test func jsonExportRoundTrip() async throws { let expenses = [ Expense(id: UUID(), title: "Coffee", amount: 4.50, date: Date(), category: "Food") ] let url = try await DataExportManager.shared.export( expenses, format: .json, filename: "test" ) let data = try Data(contentsOf: url) let decoded = try JSONDecoder().decode([Expense].self, from: data) #expect(decoded.count == 1) #expect(decoded.first?.title == "Coffee") } @Test func csvExportFormatsCorrectly() { let expenses = [ Expense(id: UUID(), title: "Coffee, Large", amount: 4.50, date: Date(), category: "Food") ] let csv = CSVExporter.generate( from: expenses, headers: Expense.csvHeaders, rowMapper: { $0.csvRow } ) #expect(csv.contains("\"Coffee, Large\"")) // Commas escaped with quotes #expect(csv.hasPrefix("ID,Title,Amount,Date,Category")) } @Test func importParsesCSV() async throws { let csvContent = "ID,Title,Amount\n1,Coffee,4.50\n2,Lunch,12.00" let url = FileManager.default.temporaryDirectory.appendingPathComponent("test.csv") try csvContent.write(to: url, atomically: true, encoding: .utf8) let rows = try CSVExporter.parse(from: url) #expect(rows.count == 2) #expect(rows.first?["Title"] == "Coffee") }
Always export to a temporary directory, then present via share sheet:
swiftlet url = FileManager.default.temporaryDirectory .appendingPathComponent("export.\(format.fileExtension)") try data.write(to: url) // Present via UIActivityViewController or ShareLink
For GDPR Article 20 compliance, export must include:
Wrap fields containing commas, quotes, or newlines in double quotes; escape internal quotes by doubling them.
Delete large export files after sharing completes rather than relying on the system's periodic cleanup.
UIGraphicsPDFRenderer must be used on the main thread if it references UIKit views. For data-only PDF generation (text, lines, rectangles), it is safe to render on a background thread.
For exporting thousands of records, stream the output instead of building the entire string/data in memory. Write CSV line-by-line to a file handle. For JSON, use JSONSerialization with streams.
Use ShareLink for the simple case; use UIActivityViewController when you need excluded activities, completion handlers, or custom activities.
.fileImporter URLs are security-scoped: call url.startAccessingSecurityScopedResource() before reading, url.stopAccessingSecurityScopedResource() after.
generators/settings-screen -- Settings screen with export buttongenerators/account-deletion -- Account deletion includes data export optionOther measured skills in the registry, with their headline benchmark lift.