skills/generators/data-export/SKILL.md
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.
npx skillsauth add rshankras/claude-code-apple-skills data-exportInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
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:
Export formats needed?
What data needs exporting?
Do you need import capability?
How should users trigger export?
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:
3. CSVExporter.swift -- If CSV format selected
4. PDFExporter.swift -- If PDF format selected
If import capability selected:
5. DataImporter.swift -- File picker and format parser
Check 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:
struct 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:
struct 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+):
if let url = exportURL {
ShareLink(item: url) {
Label("Share Export", systemImage: "square.and.arrow.up")
}
}
Import from file picker:
struct 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:
func 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
}
@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:
let 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:
Commas, quotes, and newlines in field values must be properly escaped:
Files in FileManager.default.temporaryDirectory are cleaned up by the system periodically, but not immediately. For large exports, delete the file after sharing completes to free disk space.
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.
SwiftUI ShareLink (iOS 16+) is simpler but less configurable. UIActivityViewController gives full control over excluded activities, completion handlers, and custom activities.
When using .fileImporter, the returned URL is security-scoped. You must call url.startAccessingSecurityScopedResource() before reading and url.stopAccessingSecurityScopedResource() after.
generators/settings-screen -- Settings screen with export buttongenerators/account-deletion -- Account deletion includes data export optiondevelopment
Build, install, and launch an iOS app on a physical iPhone or iPad entirely from the command line (no Xcode GUI), using xcodebuild + devicectl. Use when the user wants to run, test, or screenshot their app on a real device without opening Xcode.
development
Comprehensive iOS development guidance including Swift best practices, SwiftUI patterns, UI/UX review against HIG, and app planning. Use for iOS code review, best practices, accessibility audits, or planning new iOS apps.
development
Build, install, launch, and screenshot an iOS app in the Simulator to verify a change visually. Use when the user wants to run the app, see a change live, screenshot the running app, or confirm a UI fix actually works (not just that it compiles).
development
Audits skills in this repo for consistency, API drift, and structural gaps. Produces a prioritized report grouped by severity (Critical/High/Medium/Low). Use when asked to "audit skills", "check the skill repo for drift", or when planning bulk skill cleanup. Read-only — does not apply fixes.