{"id":31259999,"url":"https://github.com/botforge-pro/swift-embed","last_synced_at":"2026-05-01T12:32:37.636Z","repository":{"id":311044712,"uuid":"1042188275","full_name":"botforge-pro/swift-embed","owner":"botforge-pro","description":"Property wrappers for embedding JSON/YAML resources in Swift projects","archived":false,"fork":false,"pushed_at":"2025-09-20T11:41:44.000Z","size":25,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-09-20T13:22:13.340Z","etag":null,"topics":["embedded-resources","json","property-wrappers","resources","spm","swift","swift-package-manager","yaml"],"latest_commit_sha":null,"homepage":null,"language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/botforge-pro.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"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}},"created_at":"2025-08-21T16:08:12.000Z","updated_at":"2025-09-20T11:41:48.000Z","dependencies_parsed_at":"2025-08-21T21:35:23.890Z","dependency_job_id":null,"html_url":"https://github.com/botforge-pro/swift-embed","commit_stats":null,"previous_names":["botforge-pro/swift-embed"],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/botforge-pro/swift-embed","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/botforge-pro%2Fswift-embed","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/botforge-pro%2Fswift-embed/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/botforge-pro%2Fswift-embed/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/botforge-pro%2Fswift-embed/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/botforge-pro","download_url":"https://codeload.github.com/botforge-pro/swift-embed/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/botforge-pro%2Fswift-embed/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32497812,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-30T13:12:12.517Z","status":"online","status_checked_at":"2026-05-01T02:00:05.856Z","response_time":64,"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":["embedded-resources","json","property-wrappers","resources","spm","swift","swift-package-manager","yaml"],"created_at":"2025-09-23T08:46:22.732Z","updated_at":"2026-05-01T12:32:37.545Z","avatar_url":"https://github.com/botforge-pro.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Tests](https://github.com/botforge-pro/swift-embed/actions/workflows/tests.yml/badge.svg)](https://github.com/botforge-pro/swift-embed/actions/workflows/tests.yml)\n\n# SwiftEmbed\n\nA lightweight Swift library for embedding JSON, YAML and text resources with automatic caching and Swift 6 concurrency support.\n\n## Features\n\n- 🎯 **Simple API** - Clean property wrapper and computed property syntax\n- 📦 **JSON Support** - Built-in JSON decoding\n- 📝 **YAML Support** - Full YAML decoding via Yams\n- 📄 **Text Support** - Load plain text files as strings\n- 🔒 **Type Safe** - Compile-time type checking with Decodable\n- ⚡ **Automatic Caching** - Resources cached after first load\n- 🔄 **Swift 6 Ready** - No concurrency warnings with static properties\n- 📱 **Cross-Platform** - Works on iOS, macOS, tvOS, watchOS\n\n## Installation\n\n### Swift Package Manager\n\nAdd to your `Package.swift`:\n\n```swift\ndependencies: [\n    .package(url: \"https://github.com/botforge-pro/swift-embed.git\", from: \"1.5.0\")\n]\n```\n\n## Usage\n\nSwiftEmbed provides three ways to load resources:\n\n### 1. Computed Properties (Recommended for Swift 6)\n\nBest for static configuration and avoids Swift 6 concurrency warnings:\n\n```swift\nimport SwiftEmbed\n\nstruct AppConfig {\n    // Clean syntax, no Swift 6 warnings, automatic caching\n    static var config: Config {\n        Embedded.getJSON(Bundle.main, path: \"Resources/config.json\")\n    }\n    \n    static var users: [User] {\n        Embedded.getJSON(Bundle.main, path: \"Resources/users.json\")\n    }\n    \n    static var template: String {\n        Embedded.getText(Bundle.main, path: \"Resources/template.html\")\n    }\n}\n\n// Usage\nlet apiURL = AppConfig.config.apiURL  // Loaded and cached on first access\nlet userCount = AppConfig.users.count // Retrieved from cache\n```\n\n### 2. Property Wrappers\n\nFor instance properties in classes/structs:\n\n```swift\nimport SwiftEmbed\n\nstruct MyApp {\n    @Embedded.JSON(Bundle.main, path: \"Resources/users.json\")\n    var users: [User]\n    \n    @Embedded.YAML(Bundle.main, path: \"Config/settings.yaml\")\n    var config: Config\n    \n    @Embedded.Text(Bundle.main, path: \"Resources/template.html\")\n    var htmlTemplate: String\n}\n```\n\n### 3. Direct Loading\n\nFor immediate use or dynamic loading:\n\n```swift\nimport SwiftEmbed\n\n// Load and decode JSON\nlet users = Embedded.getJSON(Bundle.main, path: \"users.json\", as: [User].self)\n\n// Load and decode YAML\nlet config = Embedded.getYAML(Bundle.main, path: \"config.yaml\", as: Config.self)\n\n// Load plain text\nlet template = Embedded.getText(Bundle.main, path: \"template.html\")\n```\n\n## Caching\n\nAll methods use an internal cache powered by `NSCache`:\n- Resources are loaded from disk only once\n- Subsequent accesses return cached values\n- Memory-safe with automatic purging under pressure\n- Thread-safe for concurrent access\n\n## Testing\n\nPerfect for loading test data:\n\n```swift\nimport Testing\nimport SwiftEmbed\n\n@Suite(\"API Tests\")\nstruct APITests {\n    struct TestCase: Decodable {\n        let input: String\n        let expected: String\n    }\n    \n    // Load test data once, cached for all test runs\n    static var testCases: [TestCase] {\n        Embedded.getJSON(Bundle.module, path: \"TestData/url_tests.json\")\n    }\n    \n    @Test(\"URL Validation\", arguments: testCases)\n    func testURLs(testCase: TestCase) {\n        // Test implementation\n    }\n}\n```\n\n## File Organization\n\nPlace your resource files in your target:\n\n```\nMyApp/\n├── Sources/\n│   └── MyApp/\n│       └── MyClass.swift\n└── Resources/\n    ├── data.json\n    └── config.yaml\n```\n\nFor Swift packages, ensure resources are declared in `Package.swift`:\n\n```swift\n.target(\n    name: \"MyApp\",\n    resources: [\n        .copy(\"Resources\")  // Use .copy() to preserve directory structure\n        // .process() will flatten the directory structure\n    ]\n)\n```\n\n**Important:** Always use `.copy()` instead of `.process()` to preserve your directory structure. The `.process()` rule will flatten directories and may cause resource loading to fail.\n\n## Swift 6 Concurrency\n\nSwiftEmbed is fully compatible with Swift 6's strict concurrency checking:\n\n```swift\n// ✅ No warnings - computed property approach\nstruct MyConfig {\n    static var settings: Settings {\n        Embedded.getJSON(Bundle.module, path: \"config.json\")\n    }\n}\n\n// ✅ No warnings - static let with direct call\nstruct MyData {\n    static let data = Embedded.getJSON(Bundle.module, path: \"data.json\", as: DataModel.self)\n}\n\n// ⚠️ Warning with property wrapper on static var\nstruct BadExample {\n    @Embedded.JSON(Bundle.module, path: \"config.json\")\n    static var config: Config  // Swift 6 warning: static var not concurrency-safe\n}\n```\n\n## Known Issues\n\n### Xcode 14+ Simulator Build Error with \"Resources\" Folder\n\nIf you encounter a code signing error when building for iOS Simulator in Xcode 14 or later:\n\n```\nCodeSign failed with a nonzero exit code\nbundle format unrecognized, invalid, or unsuitable\n```\n\nThis is a known Xcode issue where it tries to code sign SPM resource bundles named \"Resources\" for the simulator, which is not supported.\n\n**Solution:** Rename your resources folder to something else (e.g., `TestData`, `Assets`, `Files`):\n\n```swift\n.target(\n    name: \"MyApp\",\n    resources: [\n        .copy(\"TestData\")  // Instead of \"Resources\"\n    ]\n)\n```\n\nThis issue only affects iOS Simulator builds. Device builds work fine with any folder name.\n\n## Requirements\n\n- Swift 6.0+\n- iOS 15.0+ / macOS 12.0+ / tvOS 15.0+ / watchOS 8.0+","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbotforge-pro%2Fswift-embed","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbotforge-pro%2Fswift-embed","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbotforge-pro%2Fswift-embed/lists"}