Shark

Build

Shark 是一个 Swift 命令行工具,它可以为你的图片、颜色、Storyboard、字体和本地化生成类型安全的枚举。 Shark 支持为 Apple UI 框架 UIKitAppKitSwiftUI 生成代码。

因为 Shark 读取你的 .xcodeproj 文件来查找这些资源,所以设置非常简单。

WWDC 2023 新闻 尽管 Shark 的部分功能被 Xcode 15 中新的 ColorImage 资源抄袭了(**sherlocked**),但它仍然不支持字体、Storyboard 和本地化。因此,我们将继续维护 Shark!

动机

以下是一个为 UIKit 生成的 Shark.swift 文件的示例,以及它如何在代码库中使用

// Shark.swift
// Generated by Shark https://github.com/kaandedeoglu/Shark

import UIKit

// swiftlint:disable all
public enum Shark {
    private static let bundle: Bundle = {
        class Custom {}
        return Bundle(for: Custom.self)
    }()

    public enum I {
        public enum Button {
            public static var profile: UIImage { return UIImage(named:"profile", in: bundle, compatibleWith: nil)! }
            public static var cancel: UIImage { return UIImage(named:"cancel", in: bundle, compatibleWith: nil)! }
            public static var user_avatar: UIImage { return UIImage(named:"user_avatar", in: bundle, compatibleWith: nil)! }
        }
    }

    public enum C {
        public static var blue1: UIColor { return UIColor(named: "blue1", in: bundle, compatibleWith: nil)! }
        public static var blue2: UIColor { return UIColor(named: "blue2", in: bundle, compatibleWith: nil)! }
        public static var gray1: UIColor { return UIColor(named: "gray1", in: bundle, compatibleWith: nil)! }
        public static var gray2: UIColor { return UIColor(named: "gray2", in: bundle, compatibleWith: nil)! }
        public static var green1: UIColor { return UIColor(named: "green1", in: bundle, compatibleWith: nil)! }
        public static var green2: UIColor { return UIColor(named: "green2", in: bundle, compatibleWith: nil)! }
    }

    public enum F {
        public static func gothamBold(ofSize size: CGFloat) -> UIFont { return UIFont(name: "Gotham-Bold", size: size)! }
        public static func gothamMedium(ofSize size: CGFloat) -> UIFont { return UIFont(name: "Gotham-Medium", size: size)! }
        public static func gothamRegular(ofSize size: CGFloat) -> UIFont { return UIFont(name: "Gotham-Regular", size: size)! }
    }

    public enum L {
        public enum button {
            /// Login
            public static var login: String { return NSLocalizedString("button.login", bundle: bundle, comment: "") }

            /// Logout
            public static var logout: String { return NSLocalizedString("button.logout", bundle: bundle, comment: "") }
        }

        public enum login {
            /// Please log in to continue
            public static var title: String { return NSLocalizedString("login.title", bundle: bundle, comment: "") }

            /// Skip login and continue
            public static var skip: String { return NSLocalizedString("login.skip", bundle: bundle, comment: "") }

            public enum error {
                /// Login failed
                public static var title: String { return NSLocalizedString("login.error.title", bundle: bundle, comment: "") }

                /// Operation failed with error: %@
                public static func message(_ value1: String) -> String {
                    return String(format: NSLocalizedString("login.error.message", bundle: bundle, comment: ""), value1)
                }
            }
        }
    }
}

// At the call site
imageView.image = Shark.I.Button.profile
label.font = Shark.F.gothamBold(ofSize: 16.0)
label.text = Shark.L.login.title
view.backgroundColor = Shark.C.green1

// You can also make it prettier with typealiases
typealias I = Shark.I
typealias C = Shark.C
typealias F = Shark.F
typealias L = Shark.L

imageView.image = I.Button.profile
label.font = F.gothamBold(ofSize: 16.0)
label.text = L.login.error.message("I disobeyed my masters")
view.backgroundColor = C.green1

有几点需要注意

首先,请查看 Xcode 中资源目录文件夹条目的检查器窗格的截图

如果你将图片和颜色资源放在文件夹中,Shark 将创建命名空间的 enum – 前提是你已配置相应的 Xcode 设置 _Provides Namespace_(提供命名空间)。 如果你有深度嵌套的文件夹,Shark 将遵循每个文件夹的单独命名空间设置。

本地化总是使用分隔符进行命名空间。 目前,Shark 使用点符号 . 作为分隔符。 正如你所见,本地化键会递归地进行命名空间,直到我们到达最后一个组成部分。

安装

Homebrew

brew install kaandedeoglu/formulae/shark

Mint

mint install kaandedeoglu/formulae/shark

手动

克隆项目,然后执行

> swift build -c release
> cp ./build/release/Shark /usr/local/bin

然后,你可以通过执行以下操作来验证安装

> shark --help

设置

选项 & 标志

Shark 还接受以下命令行选项来配置行为

--name

默认情况下,一切都在顶层枚举下,这个枚举的名字是 - 你猜对了 - Shark。 你可以使用 --name 标志来更改它。

 shark $PROJECT_FILE_PATH $PROJECT_DIR/$PROJECT_NAME --name Assets

--locale

默认情况下,Shark 将尝试查找英语本地化以生成本地化枚举。 如果你的项目中没有英文 .strings 文件,或者你希望 Shark 将其他本地化作为基础,你可以使用 --locale 标志指定语言代码。

# Use Spanish localizations for generation
shark $PROJECT_FILE_PATH $PROJECT_DIR/$PROJECT_NAME --locale es

--target

如果你的 Xcode 项目有多个应用程序目标,你应该使用 --target 标志指定 Shark 应该查看哪一个。

shark $PROJECT_FILE_PATH $PROJECT_DIR/$PROJECT_NAME --target MyAppTarget

--visibility

默认情况下,Shark 将创建所有属性,其可见性为 public。 提交此选项以将其更改为例如 internal

--framework

默认情况下,Shark 为 UIKit 创建代码。 指定 --framework appkit 以创建 AppKit 的代码,并指定 --framework swiftui 以创建 SwiftUI 的代码。

--separator

Shark 将使用分隔符字符值分割本地化键,并创建嵌套的枚举,直到我们到达最后一个元素。 例如,以下行 login.button.positive = "Log in!";login.button.negative = "Go back..."; 将在顶级本地化枚举 L 中创建以下结构

public enum login {
    public enum button {
        public static var positive: String { return NSLocalizedString("login.button.positive") }
        public static var negative: String { return NSLocalizedString("login.button.negative") }
    }
}

默认情况下,分隔符是 .,此选项仅接受单字符输入。

--top-level-scope

在顶级作用域中声明 I、C、F、L 枚举,而不是将它们嵌套在顶级 Shark 枚举中。

--exclude

默认情况下,Shark 将处理它知道的所有资源文件。 如果你不希望这样做,你可以指定例外。 请注意,Shark 使用后缀匹配来识别要排除的文件。

--help

将概述、示例用法和可用标志打印到控制台。

许可证

MIT 许可证 (MIT)

版权所有 (c) Kaan Dedeoglu, Dr. Michael 'Mickey' Lauer, 和贡献者。

特此授予任何人免费获得本软件及相关文档文件(“软件”)副本的许可,允许对软件进行处理,不受限制,包括但不限于使用、复制、修改、合并、发布、分发、再许可和/或销售软件副本的权利,并允许向提供软件的人员提供软件,但须遵守以下条件

上述版权声明和本许可声明应包含在所有副本或本软件的实质性部分中。

本软件按“原样”提供,不提供任何形式的明示或暗示保证,包括但不限于适销性、特定用途的适用性和不侵权的保证。 在任何情况下,作者或版权持有者均不对任何索赔、损害或其他责任负责,无论是在合同、侵权或其他方面,由软件或软件的使用或其他交易引起、产生或与之相关。