这是一个命令行工具,用于从自定义 JSON 模式生成配置文件。它大致基于 ConfigGenerator,但具有显著的可扩展性。
因为每个配置都需要一个完全独立的输入文件,它不允许跨配置共享值,而且很容易忘记在每个配置中添加值。
只需将文件夹和方案名称传递给命令
generateconfig --configPath /path/to/my/config --scheme my-scheme-name
generateconfig
将查找所有带有 .config
文件扩展名的文件,搜索合适的模板,并为每个文件输出一个 .swift 文件。
模式示例:
{
"template": {
"imports": [ "MyCustomFramework" ]
},
"key": {
"description": "An optional comment to document the property. Will be added as a comment to the generated code",
"type": "String",
"defaultValue": "value to be used by all schemes",
"overrides": {
"scheme pattern 1": "a different string to be used by schemes matching 'scheme pattern 1'",
"scheme pattern 2": "a different string to be used by schemes matching 'scheme pattern 2'"
}
},
"group: {
"key": {
"type": "String",
"defaultValue": "value to be used by all schemes",
"overrides": {
"scheme pattern 1": "a different string to be used by schemes matching 'scheme pattern 1'",
"scheme pattern 2": "a different string to be used by schemes matching 'scheme pattern 2'"
}
}
}
"key" 将用作 class
中的静态属性名称,因此应具有 Swift 编译器可以接受的格式。最常见的是 lowerCamelCase
。
type
可以具有以下值
String
: Swift 字符串值URL
: URL。将被转换为 URL(string: "the value")!
Int
: 整数值。Double
: 双精度浮点数值Bool
: 布尔值Colour
: 十六进制格式的颜色,将输出为 UIColor
。DynamicColour
: 一对十六进制格式的颜色,将输出为与 iOS 13 兼容的动态颜色。DynamicColourReference
: 一对颜色,作为当前配置或其他位置的属性,将输出为与 iOS 13 兼容的动态颜色。Image
: 图像的名称。将被转换为 UIImage(named: "the value")!
。Regex
: 正则表达式模式。将被转换为 try! NSRegularExpression(patthen: "the value", options: [])
EncryptionKey
: 用于加密敏感信息的密钥。Encrypted
: 应该使用提供的密钥加密的值。EnvironmentVariable
: 命名的环境变量,其值将在运行时从当前 shell 环境中获取。EncryptedEnvironmentVariable
: EnvironmentVariable
的加密版本(需要定义 EncryptionKey
)。Dictionary
: 字典。键应该是字符串,字典中的值应该是字符串、数字或新的字典。Reference
: 请参见下面的 引用属性。type
设置为枚举的名称,将值设置为枚举的 case,前面加上 .
,例如 .thing
。 如果您需要来自自定义模块的枚举,请将字符串数组的导入添加到模板部分。overrides
包含与提供的 defaultValue
不同的值。 此字典中的键应该是一个正则表达式模式,用于匹配传入的方案。 这些值应该与 type
指定的 defaultValue
的类型相同。 如果两个被覆盖的值可以匹配,则使用找到的第一个合适的值。 overrides
是可选的,如果未提供,则所有方案都将使用 defaultValue
。
请注意,属性也可以按照第二个示例进行分组。 可以将任意数量的属性添加到命名组,这将在父配置类中创建一个带有附加属性的嵌套类。
有时您可能希望将一个属性映射到另一个属性的输出,而不是传入的方案。 以下面的示例为例:
{
"host": {
"type": "String",
"defaultValue": "example.com",
"overrides": {
"test": "test.example.com",
"stage": "test.example.com",
"live": "live.example.com"
}
},
"logoName": {
"type": "String",
"defaultValue" "logo.png",
"associatedProperty": "host",
"overrides": {
"test.example.com": "logo-test.png"
}
}
}
logoName
属性有一个 associatedProperty
,它将其 overrides
绑定到 host
的值,而不是传入的方案。 这样可以实现更简洁的覆盖列表,如上面的示例所示,"test" 和 "stage" 方案都将生成一个 "logo-test.png" logoName。
请注意,使用 associatedProperty
时有一些注意事项
overrides
中的键不使用正则表达式模式匹配,而是需要完全字符串匹配。associatedProperty
*必须* 具有 String 类型。有时您可能希望使一个属性返回另一个属性的输出,具体取决于传入的方案。 例如:
{
"red": {
"type": "Colour",
"defaultValue": "#FF0000"
},
"green": {
"type": "Colour",
"defaultValue": "#00FF00"
},
"textColour": {
"type": "Reference",
"defaultValue": "red",
"overrides": {
"greenScheme": "green"
}
}
}
对于除 greenScheme
之外的所有方案,textColour
属性将为 return red
,而对于 greenScheme
,它将为 return green
。
此模式应使用于创建枚举。 模式示例:
{
"template": {
"name": "enum",
"rawType": "String"
},
"key": {
"defaultValue": "",
"overrides": {
"scheme pattern 1": "a dffierent string to be used by schemes matching 'scheme pattern 1'"
}
}
}
template.name
定义 config
应该使用哪个模板代码来解析此文件。 template.rawType
指定要使用的原始枚举类型。 目前仅支持 "String"。 这些属性遵循与默认属性相同的规则,但是不需要 type
。 如果没有为 defaultValue
提供任何值,并且没有 overrides
,则枚举键也将是原始值。
此模式应用于在现有类上创建扩展。 模式示例:
{
"template": {
"extensionOn": "UIColor",
"extensionName": "Palette",
"requiresNonObjC": true
},
"brand": {
"type": "Colour",
"defaultValue": "#FF0000",
"overrides": {
"blue": "#0000FF"
}
}
}
这将在名为 UIColor+Palette.swift
的文件中输出 UIColor
的扩展。
可以使用自己的自定义类型配置。 将 customTypes
数组添加到 template
部分,然后可以添加值,可以作为字符串(对于单个值),也可以作为键控字典。 例如:
{
"template": {
"customTypes": [
{
"typeName": "MyCustomType",
"initialiser": "MyCustomType(thing: {$0})"
},
{
"typeName": "MyMoreComplexCustomType",
"initialiser": "MyMoreComplexCustomType(thing: {thing}, otherThing: {otherThing:String})"
}
]
},
"myThing": {
"type": "MyCustomType",
"defaultValue": "Thingy"
},
"myOtherThing": {
"type": "MyMoreComplexCustomType",
"defaultValue": {
"thing": "Thingy",
"otherThing": "A different thingy"
}
}
}
初始化器模板中的占位符应写为 {key}
或 {key:TypeHint}
,其中类型提示是基本原始类型之一,Bool
、String
、URL
、Int
、Double
。 如果未提供任何类型提示,则该值将被视为表达式。
如果您发现自己重复覆盖模式,例如 (PROD|STAGING)
,则可以将它们列在模板的 patterns
部分中,以便在配置中重复使用。 例如:
{
"template": {
"patterns": [
{
"alias": "prodAndStaging",
"pattern": "(PROD|STAGING)"
}
]
},
"myString": {
"type": "String",
"defaultValue": "Hello",
"overrides": {
"prodAndStaging": "Overridden value"
}
}
}
为了支持 iOS 13 的深色模式,可以将颜色输出为动态颜色。 例如:
"background": {
"type": "DynamicColour",
"defaultValue": {
"light": "#FF",
"dark": "#00"
}
}
将输出
@nonobjc static var background: UIColor {
if #available(iOS 13, *) {
return UIColor(dynamicProvider: {
if $0.userInterfaceStyle == .dark {
return UIColor(white: 0.0 / 255.0, alpha: 1.0)
} else {
return UIColor(white: 255.0 / 255.0, alpha: 1.0)
}
})
} else {
return UIColor(white: 255.0 / 255.0, alpha: 1.0)
}
}
同样,可以使用对另一种颜色的引用,因此
"background": {
"type": "DynamicColourReference",
"defaultValue": {
"light": "UIColor.white",
"dark": "UIColor.black"
}
}
将输出
@nonobjc static var background: UIColor {
if #available(iOS 13, *) {
return UIColor(dynamicProvider: {
if $0.userInterfaceStyle == .dark {
return UIColor.black
} else {
return UIColor.white
}
})
} else {
return UIColor.white
}
}
只需向项目中添加一个新的类或结构,并实现 Template
。 将新的解析器添加到 main.swift 中的 templates
数组中。 您的模板应该检查任何配置中的 template
字典,并确定它是否可以解析它。 可以使用 name
项,或通过其他方式。 确保 ConfigurationFile
是该数组中的最后一项。 作为默认的模式解析器,它声称能够解析所有文件。
由于可以从头开始编写新的模板,因此您的 json 文件应该遵循没有预定义的模式,但是为了其他贡献者的可读性,如果它尽可能地类似于默认模式,那可能是明智的。
如果在 Xcode 中作为构建阶段运行,建议使用 Xcode 文件列表,无论是对于源输入还是生成的文件。 输入文件列表将确保 Xcode 使其文件缓存过期,并且您使用最新版本进行构建。 输出文件列表将确保 Xcode 在继续操作之前等待生成您的文件。