{"id":3121,"url":"https://github.com/kaandedeoglu/Shark","last_synced_at":"2025-08-03T13:31:55.809Z","repository":{"id":34924420,"uuid":"38985577","full_name":"kaandedeoglu/Shark","owner":"kaandedeoglu","description":"Swift CLI for strong-typing images, colors, storyboards, fonts and localizations","archived":false,"fork":false,"pushed_at":"2023-06-14T13:48:56.000Z","size":481,"stargazers_count":381,"open_issues_count":3,"forks_count":16,"subscribers_count":6,"default_branch":"master","last_synced_at":"2024-04-24T19:26:02.781Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","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/kaandedeoglu.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}},"created_at":"2015-07-13T01:44:14.000Z","updated_at":"2023-10-09T09:31:53.000Z","dependencies_parsed_at":"2024-01-02T21:28:28.736Z","dependency_job_id":null,"html_url":"https://github.com/kaandedeoglu/Shark","commit_stats":{"total_commits":116,"total_committers":11,"mean_commits":"10.545454545454545","dds":0.4655172413793104,"last_synced_commit":"d01e3436d707dd914890b44165594c12f33e995b"},"previous_names":[],"tags_count":32,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kaandedeoglu%2FShark","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kaandedeoglu%2FShark/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kaandedeoglu%2FShark/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kaandedeoglu%2FShark/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kaandedeoglu","download_url":"https://codeload.github.com/kaandedeoglu/Shark/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":228548567,"owners_count":17935221,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":[],"created_at":"2024-01-05T20:16:31.978Z","updated_at":"2025-08-03T13:31:55.766Z","avatar_url":"https://github.com/kaandedeoglu.png","language":"Swift","funding_links":[],"categories":["Tools","WebSocket"],"sub_categories":["Web View","Other free courses"],"readme":"# Shark\n\n![Build](https://github.com/kaandedeoglu/Shark/workflows/Swift/badge.svg)\n\nShark is a Swift command line tool that generates type safe enums for your images, colors, storyboards, fonts and localizations.\nShark supports code generation for the Apple UI frameworks `UIKit`, `AppKit`, and `SwiftUI`.\n\nBecause Shark reads your `.xcodeproj` to find these assets, the setup is extremely simple.\n\n**WWDC 2023 NEWS** Although Shark has been a bit [sherlocked](https://umatechnology.org/what-does-it-mean-when-an-app-gets-sherlocked-by-apple/)\nby the new `Color` and `Image` resources in Xcode 15, there's still no support for fonts, storyboards, and localizations.\nWe will therefore continue to maintain Shark!\n\n**WWDC 2025 NEWS** This year, Shark has been [sherlocked](https://umatechnology.org/what-does-it-mean-when-an-app-gets-sherlocked-by-apple/) again\nwith type-safe localization resources. We still have the leading edge for fonts and storyboards though ;-)\n\n## Motivation\n\nHere's what a generated `Shark.swift` file for `UIKit` looks like and how it is used in a codebase:\n\n```swift\n// Shark.swift\n// Generated by Shark https://github.com/kaandedeoglu/Shark\n\nimport UIKit\n\n// swiftlint:disable all\npublic enum Shark {\n    private static let bundle: Bundle = {\n        class Custom {}\n        return Bundle(for: Custom.self)\n    }()\n\n    public enum I {\n        public enum Button {\n            public static var profile: UIImage { return UIImage(named:\"profile\", in: bundle, compatibleWith: nil)! }\n            public static var cancel: UIImage { return UIImage(named:\"cancel\", in: bundle, compatibleWith: nil)! }\n            public static var user_avatar: UIImage { return UIImage(named:\"user_avatar\", in: bundle, compatibleWith: nil)! }\n        }\n    }\n\n    public enum C {\n        public static var blue1: UIColor { return UIColor(named: \"blue1\", in: bundle, compatibleWith: nil)! }\n        public static var blue2: UIColor { return UIColor(named: \"blue2\", in: bundle, compatibleWith: nil)! }\n        public static var gray1: UIColor { return UIColor(named: \"gray1\", in: bundle, compatibleWith: nil)! }\n        public static var gray2: UIColor { return UIColor(named: \"gray2\", in: bundle, compatibleWith: nil)! }\n        public static var green1: UIColor { return UIColor(named: \"green1\", in: bundle, compatibleWith: nil)! }\n        public static var green2: UIColor { return UIColor(named: \"green2\", in: bundle, compatibleWith: nil)! }\n    }\n\n    public enum F {\n        public static func gothamBold(ofSize size: CGFloat) -\u003e UIFont { return UIFont(name: \"Gotham-Bold\", size: size)! }\n        public static func gothamMedium(ofSize size: CGFloat) -\u003e UIFont { return UIFont(name: \"Gotham-Medium\", size: size)! }\n        public static func gothamRegular(ofSize size: CGFloat) -\u003e UIFont { return UIFont(name: \"Gotham-Regular\", size: size)! }\n    }\n\n    public enum L {\n        public enum button {\n            /// Login\n            public static var login: String { return NSLocalizedString(\"button.login\", bundle: bundle, comment: \"\") }\n\n            /// Logout\n            public static var logout: String { return NSLocalizedString(\"button.logout\", bundle: bundle, comment: \"\") }\n        }\n\n        public enum login {\n            /// Please log in to continue\n            public static var title: String { return NSLocalizedString(\"login.title\", bundle: bundle, comment: \"\") }\n\n            /// Skip login and continue\n            public static var skip: String { return NSLocalizedString(\"login.skip\", bundle: bundle, comment: \"\") }\n\n            public enum error {\n                /// Login failed\n                public static var title: String { return NSLocalizedString(\"login.error.title\", bundle: bundle, comment: \"\") }\n\n                /// Operation failed with error: %@\n                public static func message(_ value1: String) -\u003e String {\n                    return String(format: NSLocalizedString(\"login.error.message\", bundle: bundle, comment: \"\"), value1)\n                }\n            }\n        }\n    }\n}\n\n// At the call site\nimageView.image = Shark.I.Button.profile\nlabel.font = Shark.F.gothamBold(ofSize: 16.0)\nlabel.text = Shark.L.login.title\nview.backgroundColor = Shark.C.green1\n\n// You can also make it prettier with typealiases\ntypealias I = Shark.I\ntypealias C = Shark.C\ntypealias F = Shark.F\ntypealias L = Shark.L\n\nimageView.image = I.Button.profile\nlabel.font = F.gothamBold(ofSize: 16.0)\nlabel.text = L.login.error.message(\"I disobeyed my masters\")\nview.backgroundColor = C.green1\n```\n\nThere are a few things to notice:\n\nFirst, have a look at this Xcode screenshot from the inspector pane of an asset catalogue's folder entry:\n\n![](https://user-images.githubusercontent.com/167469/190901709-d4cf52f9-43bb-4c5e-bc4e-dfce24dd2638.png)\n\nIf you place your image and color assets in folders, Shark will create namespaced `enum`s ­– provided you have configured the respective Xcode setting _Provides Namespace_. If you have deeply nested folders, Shark will respect every one's individual namespace setting.\n\nLocalizations are always namespaced with separators. Currently Shark uses the dot symbol `.` as the separator.\n  As you can see localization keys are recursively namespaced until we get to the last component.\n\n## Installation\n\n### Homebrew\n\n```bash\nbrew install kaandedeoglu/formulae/shark\n```\n\n### Mint\n\n```bash\nmint install kaandedeoglu/formulae/shark\n```\n\n### Manually\n\nClone the project, then do:\n\n```bash\n\u003e swift build -c release\n\u003e cp ./build/release/Shark /usr/local/bin\n```\n\nYou can then verify the installation by doing\n\n```bash\n\u003e shark --help\n```\n\n## Setup (Easy)\n\n- Add a new Run Script phase to your target's build phases. This build phase should ideally run before the `Compile Sources` phase. The script body should look like the following:\n\n  ```bash\n  unset SDKROOT\n  if [ -x \"$(command -v shark)\" ]; then\n  shark $PROJECT_FILE_PATH $PROJECT_DIR/$PROJECT_NAME/\n  fi\n  ```\n\n  the `if/fi` block makes sure that Shark runs only if it's installed on the current machine.\n\n- Build your project. You should now see a file named `Shark.swift` in your project folder.\n- Add this file to your target. Voila! `Shark.swift` will be updated every time you build the project.\n- Alternatively you can do the following:\n\n  ```bash\n  # Write to a specific file called MyAssets.swift\n  shark $PROJECT_FILE_PATH $PROJECT_DIR/$PROJECT_NAME/MyAssets.swift\n  ```\n\n  ```bash\n  # Write to a specific file in a different folder\n  shark $PROJECT_FILE_PATH $PROJECT_DIR/$PROJECT_NAME/Utility/MyAssets.swift\n  ```\n  \n  With this setup, Shark will generate the resource files on every code run.\n  This can add several seconds to the build time which you may not like.\n\n## Setup (Advanced)\n\nIf you want to run Shark only when it really needs to, then make the following adjustments:\n\n1. Edit the command line to have Shark create a dependency file. This file will contain the paths of all the assets in your project.\n\n  ```bash\n  shark $PROJECT_FILE_PATH $PROJECT_DIR/$PROJECT_NAME --deps /tmp/deps-$PROJECT_NAME.d\n  ```\n\n2. Add the output file (e.g. `${SRCROOT}/Shark.swift`) as a dependency to the Run Script phase.\n\n3. Check the *[x] Based on dependency analyses* in the build phase.\n\n4. Check the *[x] Use discovered dependency file:* and enter the path to the dependency file.\n\nAt the end of all that, your run Script phase should look similar to this:\n\n![Shark build phase in Xcode](https://github.com/user-attachments/assets/1a767515-ddf0-4e59-ae8f-6aa36e291b31)\n\n## Options \u0026 Flags\n\nShark also accepts the following command line options to configure behavior\n\n### --name\n\nBy default, the top level enum everything else lives under is called - you guessed it - `Shark`. You can change this by using the `--name` flag.\n\n ```bash\n  shark $PROJECT_FILE_PATH $PROJECT_DIR/$PROJECT_NAME --name Assets\n  ```\n\n### --locale\n\nBy default, Shark will try to find English localizations to generate the localizations enum. If there are no English `.strings` file in your project, or you'd like Shark to take another localization as base, you can specify the language code with the `--locale` flag.\n\n ```bash\n# Use Spanish localizations for generation\nshark $PROJECT_FILE_PATH $PROJECT_DIR/$PROJECT_NAME --locale es\n```\n\n### --target\n\nIn case your Xcode project has multiple application targets, you should specify which one Shark should look at by using the `--target` flag.\n\n   ```bash\nshark $PROJECT_FILE_PATH $PROJECT_DIR/$PROJECT_NAME --target MyAppTarget\n```\n\n### --visibility\n\nBy default, Shark will create all properties with the visibilty of `public`. Submit this option to change this to, e.g., `internal`.\n\n### --framework\n\nBy default, Shark creates code for `UIKit`. Specify `--framework appkit` to create code for `AppKit`, and `--framework swiftui` for `SwiftUI`.\n\n### --separator\n\nShark will split localization keys using the separator character value, and create nested enums until we hit the last element. For example, the lines `login.button.positive = \"Log in!\";` and `login.button.negative = \"Go back...\";` will create the following structure inside the top level localizations enum `L`:\n\n```swift\npublic enum login {\n    public enum button {\n        public static var positive: String { return NSLocalizedString(\"login.button.positive\") }\n        public static var negative: String { return NSLocalizedString(\"login.button.negative\") }\n    }\n}\n```\n\nBy default, the separator is `.`, only single character inputs are accepted for this option.\n\n### --top-level-scope\n\nDeclares the `I, C, F, L` enums in the top level scope instead of nesting it in a top level `Shark` enum.\n\n### --deps\n\nAdd the path to a Makefile-style dependency file. This gives Xcode a hint when to skip calling build phase because nothing has changed.\n\n### --exclude\n\nBy default, Shark will process all resource files it knows about. If you don't want that, you can specify exceptions. Note that Shark uses infix matching to identify files to exclude.\n\n### --help\n\nPrints the overview, example usage and available flags to the console.\n\n## License\n\nThe MIT License (MIT)\n\nCopyright (c) Kaan Dedeoglu, Dr. Michael 'Mickey' Lauer, and contributors.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkaandedeoglu%2FShark","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkaandedeoglu%2FShark","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkaandedeoglu%2FShark/lists"}