Compare commits

...

53 commits

Author SHA1 Message Date
fmodf 48d7030090 Merge pull request 'feature/new-target' (#2) from feature/new-target into develop
Reviewed-on: #2
2023-09-14 15:00:23 +00:00
fmodf 2d8019217a add local package 2023-09-14 18:58:53 +04:00
fmodf 43dde437c5 add packages 2023-09-14 16:29:48 +04:00
fmodf 20db5d5f2d add colors from dino, add swiftgen 2023-09-12 22:04:56 +04:00
fmodf 7424e9171a app template 2023-09-11 18:40:58 +04:00
fmodf 6906c094ea upd project 2023-09-11 17:32:07 +04:00
fmodf 3ab551e8de wip 2023-09-11 17:06:34 +04:00
fmodf 1c745f2b25 wip 2023-09-11 16:45:34 +04:00
fmodf 4717aa8649 linter update 2023-09-11 16:24:37 +04:00
fmodf f387236d9d wip 2023-09-11 16:22:16 +04:00
fmodf 80c56f1d48 wip 2023-09-11 16:21:44 +04:00
fmodf 43f01272ab wip 2023-09-11 16:13:44 +04:00
fmodf 1a51090b03 wip 2023-09-11 15:41:19 +04:00
fmodf dba6463116 wip 2023-09-11 15:37:44 +04:00
fmodf 1f414b9344 new multiplatform target 2023-09-11 15:11:45 +04:00
fmodf fc4610192b move old sources 2023-09-11 14:45:21 +04:00
fmodf 50feee4f74 Merge pull request 'feature/project-update' (#1) from feature/project-update into develop
Reviewed-on: #1
2023-09-06 09:05:48 +00:00
fmodf 9df49aa422 wip 2023-09-06 13:02:52 +04:00
fmodf 2736e72e9d fix linter warnings 2023-09-06 12:58:09 +04:00
fmodf 4d7e8d2fbd fix linter warnings 2023-09-06 12:43:28 +04:00
fmodf 4c6aaea4d8 fix linter warnings 2023-09-06 12:24:39 +04:00
fmodf cad4d3dcb0 fix linter warnings 2023-09-06 12:03:57 +04:00
fmodf 3e668aa808 fix linter errors 2023-09-05 18:46:24 +04:00
fmodf 54f2b3b825 fix linter warnings 2023-09-05 18:43:42 +04:00
fmodf f33c3de839 fix linter warnings 2023-09-05 18:25:31 +04:00
fmodf c95460b80e fix linter errors 2023-09-05 18:21:07 +04:00
fmodf cc20619e2c fix linter errors 2023-09-05 18:05:11 +04:00
fmodf f1fd81841e fix linter errors 2023-09-05 18:00:40 +04:00
fmodf 7603ace54e fix linter errors 2023-09-05 17:52:31 +04:00
fmodf b75eed2677 fix linter errors 2023-09-05 17:15:14 +04:00
fmodf d62937af4b fix linter errors 2023-09-05 17:00:08 +04:00
fmodf ab08d43225 fix linter errors 2023-09-05 16:46:12 +04:00
fmodf 507bc16846 fix linter errors 2023-09-05 16:40:40 +04:00
fmodf ac6eb97b16 fix linter errors 2023-09-05 16:33:35 +04:00
fmodf f31f0c54c5 fix linter errors 2023-09-05 13:50:58 +04:00
fmodf 8cbd60d30d fix linter errors 2023-09-05 13:41:32 +04:00
fmodf 93ee79ee20 fix linter error 2023-09-05 13:20:11 +04:00
fmodf a7fddc9022 fix linter errors 2023-09-05 12:32:09 +04:00
fmodf 4316eb2ca1 fix linter errors 2023-09-04 17:39:13 +04:00
fmodf 4b4de74eda fix linter error 2023-09-04 17:31:49 +04:00
fmodf 4d02aaea5b fix linter errors 2023-09-04 17:24:32 +04:00
fmodf 97ac8373c9 fix linter errors 2023-09-04 17:20:18 +04:00
fmodf 68a136e4b7 fix linter errors 2023-08-30 17:33:07 +04:00
fmodf aaa5428bfc fix linter errors 2023-08-30 17:28:14 +04:00
fmodf 39b8a4c6bc fix linter errors 2023-08-30 17:20:46 +04:00
fmodf 050a12b1cc fix linter errors 2023-08-30 17:07:51 +04:00
fmodf f9d776da64 fix linter errors 2023-08-30 16:54:00 +04:00
fmodf 129b63fd16 fix linter errors 2023-08-30 16:28:00 +04:00
fmodf 0535e59bb3 fix linter errors 2023-08-30 16:23:07 +04:00
fmodf 05d79d058f fix linter errors 2023-08-30 16:18:21 +04:00
fmodf eefce61e3a fix linter errors 2023-08-30 16:07:36 +04:00
fmodf 44f3c598cd up to iOS 15 2023-08-28 19:17:55 +04:00
fmodf ac15a7e8c5 move WebRTC and OpenSSL to SPM 2023-08-28 17:18:46 +04:00
728 changed files with 26111 additions and 21737 deletions

7
.gitignore vendored
View file

@ -110,4 +110,9 @@ xcuserdata
#
# We're using source-control, so this is a "feature" that we do not want!
*.moved-aside
*.moved-aside
/.idea
/Snikket/.idea
/Snikket.xcodeproj
/Info.plist
/old/.idea

View file

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>BuildMachineOSBuild</key>
<string></string>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>SwiftGen_SwiftGenCLI</string>
<key>CFBundleIdentifier</key>
<string>SwiftGen.SwiftGenCLI.resources</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>SwiftGen_SwiftGenCLI</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleSupportedPlatforms</key>
<array>
<string>MacOSX</string>
</array>
<key>DTCompiler</key>
<string>com.apple.compilers.llvm.clang.1_0</string>
<key>DTPlatformBuild</key>
<string>13A233</string>
<key>DTPlatformName</key>
<string>macosx</string>
<key>DTPlatformVersion</key>
<string>11.3</string>
<key>DTSDKBuild</key>
<string>20E214</string>
<key>DTSDKName</key>
<string>macosx11.3</string>
<key>DTXcode</key>
<string>1300</string>
<key>DTXcodeBuild</key>
<string>13A233</string>
<key>LSMinimumSystemVersion</key>
<string>10.11</string>
</dict>
</plist>

View file

@ -0,0 +1,43 @@
// swiftlint:disable all
// Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen
{% if palettes %}
{% set enumName %}{{param.enumName|default:"ColorName"}}{% endset %}
{% set accessModifier %}{% if param.publicAccess %}public{% else %}internal{% endif %}{% endset %}
#if os(macOS)
import AppKit
{% if enumName != 'NSColor' %}{{accessModifier}} enum {{enumName}} { }{% endif %}
#elseif os(iOS) || os(tvOS) || os(watchOS)
import UIKit
{% if enumName != 'UIColor' %}{{accessModifier}} enum {{enumName}} { }{% endif %}
#endif
// swiftlint:disable superfluous_disable_command
// swiftlint:disable file_length
// MARK: - Colors
// swiftlint:disable identifier_name line_length type_body_length
{{accessModifier}} extension {{enumName}} {
{% macro h2f hex %}{{hex|hexToInt|int255toFloat}}{% endmacro %}
{% macro enumBlock colors accessPrefix %}
{% for color in colors %}
/// 0x{{color.red}}{{color.green}}{{color.blue}}{{color.alpha}} (r: {{color.red|hexToInt}}, g: {{color.green|hexToInt}}, b: {{color.blue|hexToInt}}, a: {{color.alpha|hexToInt}})
{{accessPrefix}}static let {{color.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}} = #colorLiteral(red: {% call h2f color.red %}, green: {% call h2f color.green %}, blue: {% call h2f color.blue %}, alpha: {% call h2f color.alpha %})
{% endfor %}
{% endmacro %}
{% if palettes.count > 1 or param.forceFileNameEnum %}
{% set accessPrefix %}{{accessModifier}} {% endset %}
{% for palette in palettes %}
enum {{palette.name|swiftIdentifier:"pretty"|escapeReservedKeywords}} {
{% filter indent:2 %}{% call enumBlock palette.colors accessPrefix %}{% endfilter %}
}
{% endfor %}
{% else %}
{% call enumBlock palettes.first.colors "" %}
{% endif %}
}
// swiftlint:enable identifier_name line_length type_body_length
{% else %}
// No color found
{% endif %}

View file

@ -0,0 +1,43 @@
// swiftlint:disable all
// Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen
{% if palettes %}
{% set enumName %}{{param.enumName|default:"ColorName"}}{% endset %}
{% set accessModifier %}{% if param.publicAccess %}public{% else %}internal{% endif %}{% endset %}
#if os(macOS)
import AppKit
{% if enumName != 'NSColor' %}{{accessModifier}} enum {{enumName}} { }{% endif %}
#elseif os(iOS) || os(tvOS) || os(watchOS)
import UIKit
{% if enumName != 'UIColor' %}{{accessModifier}} enum {{enumName}} { }{% endif %}
#endif
// swiftlint:disable superfluous_disable_command
// swiftlint:disable file_length
// MARK: - Colors
// swiftlint:disable identifier_name line_length type_body_length
{{accessModifier}} extension {{enumName}} {
{% macro h2f hex %}{{hex|hexToInt|int255toFloat}}{% endmacro %}
{% macro enumBlock colors accessPrefix %}
{% for color in colors %}
/// 0x{{color.red}}{{color.green}}{{color.blue}}{{color.alpha}} (r: {{color.red|hexToInt}}, g: {{color.green|hexToInt}}, b: {{color.blue|hexToInt}}, a: {{color.alpha|hexToInt}})
{{accessPrefix}}static let {{color.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}} = #colorLiteral(red: {% call h2f color.red %}, green: {% call h2f color.green %}, blue: {% call h2f color.blue %}, alpha: {% call h2f color.alpha %})
{% endfor %}
{% endmacro %}
{% if palettes.count > 1 or param.forceFileNameEnum %}
{% set accessPrefix %}{{accessModifier}} {% endset %}
{% for palette in palettes %}
enum {{palette.name|swiftIdentifier:"pretty"|escapeReservedKeywords}} {
{% filter indent:2 %}{% call enumBlock palette.colors accessPrefix %}{% endfilter %}
}
{% endfor %}
{% else %}
{% call enumBlock palettes.first.colors "" %}
{% endif %}
}
// swiftlint:enable identifier_name line_length type_body_length
{% else %}
// No color found
{% endif %}

View file

@ -0,0 +1,84 @@
// swiftlint:disable all
// Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen
{% if palettes %}
{% set colorAlias %}{{param.colorAliasName|default:"Color"}}{% endset %}
{% set accessModifier %}{% if param.publicAccess %}public{% else %}internal{% endif %}{% endset %}
#if os(macOS)
import AppKit.NSColor
{{accessModifier}} typealias {{colorAlias}} = NSColor
#elseif os(iOS) || os(tvOS) || os(watchOS)
import UIKit.UIColor
{{accessModifier}} typealias {{colorAlias}} = UIColor
#endif
// swiftlint:disable superfluous_disable_command file_length implicit_return
// MARK: - Colors
// swiftlint:disable identifier_name line_length type_body_length
{% set enumName %}{{param.enumName|default:"ColorName"}}{% endset %}
{{accessModifier}} struct {{enumName}} {
{{accessModifier}} let rgbaValue: UInt32
{{accessModifier}} var color: {{colorAlias}} { return {{colorAlias}}(named: self) }
{% macro rgbaValue color %}0x{{color.red}}{{color.green}}{{color.blue}}{{color.alpha}}{% endmacro %}
{% macro enumBlock colors %}
{% for color in colors %}
/// <span style="display:block;width:3em;height:2em;border:1px solid black;background:#{{color.red}}{{color.green}}{{color.blue}}"></span>
/// Alpha: {{color.alpha|hexToInt|int255toFloat|percent}} <br/> (0x{{color.red}}{{color.green}}{{color.blue}}{{color.alpha}})
{{accessModifier}} static let {{color.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}} = {{enumName}}(rgbaValue: {% call rgbaValue color %})
{% endfor %}
{% endmacro %}
{% if palettes.count > 1 or param.forceFileNameEnum %}
{% for palette in palettes %}
{{accessModifier}} enum {{palette.name|swiftIdentifier:"pretty"|escapeReservedKeywords}} {
{% filter indent:2 %}{% call enumBlock palette.colors %}{% endfilter %}
}
{% endfor %}
{% else %}
{% call enumBlock palettes.first.colors %}
{% endif %}
}
// swiftlint:enable identifier_name line_length type_body_length
// MARK: - Implementation Details
internal extension {{colorAlias}} {
convenience init(rgbaValue: UInt32) {
let components = RGBAComponents(rgbaValue: rgbaValue).normalized
self.init(red: components[0], green: components[1], blue: components[2], alpha: components[3])
}
}
private struct RGBAComponents {
let rgbaValue: UInt32
private var shifts: [UInt32] {
[
rgbaValue >> 24, // red
rgbaValue >> 16, // green
rgbaValue >> 8, // blue
rgbaValue // alpha
]
}
private var components: [CGFloat] {
shifts.map {
CGFloat($0 & 0xff)
}
}
var normalized: [CGFloat] {
components.map { $0 / 255.0 }
}
}
{{accessModifier}} extension {{colorAlias}} {
convenience init(named color: {{enumName}}) {
self.init(rgbaValue: color.rgbaValue)
}
}
{% else %}
// No color found
{% endif %}

View file

@ -0,0 +1,84 @@
// swiftlint:disable all
// Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen
{% if palettes %}
{% set colorAlias %}{{param.colorAliasName|default:"Color"}}{% endset %}
{% set accessModifier %}{% if param.publicAccess %}public{% else %}internal{% endif %}{% endset %}
#if os(macOS)
import AppKit.NSColor
{{accessModifier}} typealias {{colorAlias}} = NSColor
#elseif os(iOS) || os(tvOS) || os(watchOS)
import UIKit.UIColor
{{accessModifier}} typealias {{colorAlias}} = UIColor
#endif
// swiftlint:disable superfluous_disable_command file_length implicit_return
// MARK: - Colors
// swiftlint:disable identifier_name line_length type_body_length
{% set enumName %}{{param.enumName|default:"ColorName"}}{% endset %}
{{accessModifier}} struct {{enumName}} {
{{accessModifier}} let rgbaValue: UInt32
{{accessModifier}} var color: {{colorAlias}} { return {{colorAlias}}(named: self) }
{% macro rgbaValue color %}0x{{color.red}}{{color.green}}{{color.blue}}{{color.alpha}}{% endmacro %}
{% macro enumBlock colors %}
{% for color in colors %}
/// <span style="display:block;width:3em;height:2em;border:1px solid black;background:#{{color.red}}{{color.green}}{{color.blue}}"></span>
/// Alpha: {{color.alpha|hexToInt|int255toFloat|percent}} <br/> (0x{{color.red}}{{color.green}}{{color.blue}}{{color.alpha}})
{{accessModifier}} static let {{color.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}} = {{enumName}}(rgbaValue: {% call rgbaValue color %})
{% endfor %}
{% endmacro %}
{% if palettes.count > 1 or param.forceFileNameEnum %}
{% for palette in palettes %}
{{accessModifier}} enum {{palette.name|swiftIdentifier:"pretty"|escapeReservedKeywords}} {
{% filter indent:2 %}{% call enumBlock palette.colors %}{% endfilter %}
}
{% endfor %}
{% else %}
{% call enumBlock palettes.first.colors %}
{% endif %}
}
// swiftlint:enable identifier_name line_length type_body_length
// MARK: - Implementation Details
internal extension {{colorAlias}} {
convenience init(rgbaValue: UInt32) {
let components = RGBAComponents(rgbaValue: rgbaValue).normalized
self.init(red: components[0], green: components[1], blue: components[2], alpha: components[3])
}
}
private struct RGBAComponents {
let rgbaValue: UInt32
private var shifts: [UInt32] {
[
rgbaValue >> 24, // red
rgbaValue >> 16, // green
rgbaValue >> 8, // blue
rgbaValue // alpha
]
}
private var components: [CGFloat] {
shifts.map {
CGFloat($0 & 0xff)
}
}
var normalized: [CGFloat] {
components.map { $0 / 255.0 }
}
}
{{accessModifier}} extension {{colorAlias}} {
convenience init(named color: {{enumName}}) {
self.init(rgbaValue: color.rgbaValue)
}
}
{% else %}
// No color found
{% endif %}

View file

@ -0,0 +1,211 @@
// swiftlint:disable all
// Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen
// swiftlint:disable superfluous_disable_command implicit_return
// swiftlint:disable sorted_imports
import CoreData
import Foundation
{% for import in param.extraImports %}
import {{ import }}
{% empty %}
{# If extraImports is a single String instead of an array, `for` considers it empty but we still have to check if there's a single String value #}
{% if param.extraImports %}import {{ param.extraImports }}{% endif %}
{% endfor %}
// swiftlint:disable attributes file_length vertical_whitespace_closing_braces
// swiftlint:disable identifier_name line_length type_body_length
{% set accessModifier %}{% if param.publicAccess %}public{% else %}internal{% endif %}{% endset %}
{% for model in models %}
{% for name, entity in model.entities %}
{% set superclass %}{{ model.entities[entity.superEntity].className|default:"NSManagedObject" }}{% endset %}
{% set entityClassName %}{{ entity.className|default:"NSManagedObject" }}{% endset %}
// MARK: - {{ entity.name }}
{% if not entity.shouldGenerateCode %}
// Note: '{{ entity.name }}' has codegen enabled for Xcode, skipping code generation.
{% elif entityClassName|contains:"." %}
// Warning: '{{ entityClassName }}' cannot be a valid type name, skipping code generation.
{% else %}
{% if param.generateObjcName %}
@objc({{ entityClassName }})
{% endif %}
{{ accessModifier }} class {{ entityClassName }}: {{ superclass }} {
{% set override %}{% if superclass != "NSManagedObject" %}override {% endif %}{% endset %}
{{ override }}{{ accessModifier }} class var entityName: String {
return "{{ entity.name }}"
}
{{ override }}{{ accessModifier }} class func entity(in managedObjectContext: NSManagedObjectContext) -> NSEntityDescription? {
return NSEntityDescription.entity(forEntityName: entityName, in: managedObjectContext)
}
@available(*, deprecated, renamed: "makeFetchRequest", message: "To avoid collisions with the less concrete method in `NSManagedObject`, please use `makeFetchRequest()` instead.")
@nonobjc {{ accessModifier }} class func fetchRequest() -> NSFetchRequest<{{ entityClassName }}> {
return NSFetchRequest<{{ entityClassName }}>(entityName: entityName)
}
@nonobjc {{ accessModifier }} class func makeFetchRequest() -> NSFetchRequest<{{ entityClassName }}> {
return NSFetchRequest<{{ entityClassName }}>(entityName: entityName)
}
// swiftlint:disable discouraged_optional_boolean discouraged_optional_collection
{% for attribute in entity.attributes %}
{% if attribute.userInfo.RawType %}
{% set rawType attribute.userInfo.RawType %}
{% set unwrapOptional attribute.userInfo.unwrapOptional %}
{{ accessModifier }} var {{ attribute.name }}: {{ rawType }}{% if not unwrapOptional %}?{% endif %} {
get {
let key = "{{ attribute.name }}"
willAccessValue(forKey: key)
defer { didAccessValue(forKey: key) }
{% if unwrapOptional %}
guard let value = primitiveValue(forKey: key) as? {{ rawType }}.RawValue,
let result = {{ rawType }}(rawValue: value) else {
fatalError("Could not convert value for key '\(key)' to type '{{ rawType }}'")
}
return result
{% else %}
guard let value = primitiveValue(forKey: key) as? {{ rawType }}.RawValue else {
return nil
}
return {{ rawType }}(rawValue: value)
{% endif %}
}
set {
let key = "{{ attribute.name }}"
willChangeValue(forKey: key)
defer { didChangeValue(forKey: key) }
setPrimitiveValue(newValue{% if not unwrapOptional %}?{% endif %}.rawValue, forKey: key)
}
}
{% elif attribute.usesScalarValueType and attribute.isOptional %}
{{ accessModifier }} var {{ attribute.name }}: {{ attribute.typeName }}? {
get {
let key = "{{ attribute.name }}"
willAccessValue(forKey: key)
defer { didAccessValue(forKey: key) }
return primitiveValue(forKey: key) as? {{ attribute.typeName }}
}
set {
let key = "{{ attribute.name }}"
willChangeValue(forKey: key)
defer { didChangeValue(forKey: key) }
setPrimitiveValue(newValue, forKey: key)
}
}
{% else %}
@NSManaged {{ accessModifier }} var {{ attribute.name }}: {{ attribute.typeName }}{% if attribute.isOptional %}?{% endif %}
{% endif %}
{% endfor %}
{% for relationship in entity.relationships %}
{% if relationship.isToMany %}
@NSManaged {{ accessModifier }} var {{ relationship.name }}: {% if relationship.isOrdered %}NSOrderedSet{% else %}Set<{{ model.entities[relationship.destinationEntity].className|default:"NSManagedObject" }}>{% endif %}{% if relationship.isOptional %}?{% endif %}
{% else %}
@NSManaged {{ accessModifier }} var {{ relationship.name }}: {{ model.entities[relationship.destinationEntity].className|default:"NSManagedObject" }}{% if relationship.isOptional %}?{% endif %}
{% endif %}
{% endfor %}
{% for fetchedProperty in entity.fetchedProperties %}
@NSManaged {{ accessModifier }} var {{ fetchedProperty.name }}: [{{ fetchedProperty.fetchRequest.entity }}]
{% endfor %}
// swiftlint:enable discouraged_optional_boolean discouraged_optional_collection
}
{% for relationship in entity.relationships where relationship.isToMany %}
{% set destinationEntityClassName %}{{ model.entities[relationship.destinationEntity].className|default:"NSManagedObject" }}{% endset %}
{% set collectionClassName %}{% if relationship.isOrdered %}NSOrderedSet{% else %}Set<{{ destinationEntityClassName }}>{% endif %}{% endset %}
{% set relationshipName %}{{ relationship.name | upperFirstLetter }}{% endset %}
// MARK: Relationship {{ relationshipName }}
extension {{ entityClassName }} {
{% if relationship.isOrdered %}
@objc(insertObject:in{{ relationshipName }}AtIndex:)
@NSManaged public func insertInto{{ relationshipName }}(_ value: {{ destinationEntityClassName }}, at idx: Int)
@objc(removeObjectFrom{{ relationshipName }}AtIndex:)
@NSManaged public func removeFrom{{ relationshipName }}(at idx: Int)
@objc(insert{{ relationshipName }}:atIndexes:)
@NSManaged public func insertInto{{ relationshipName }}(_ values: [{{ destinationEntityClassName }}], at indexes: NSIndexSet)
@objc(remove{{ relationshipName }}AtIndexes:)
@NSManaged public func removeFrom{{ relationshipName }}(at indexes: NSIndexSet)
@objc(replaceObjectIn{{ relationshipName }}AtIndex:withObject:)
@NSManaged public func replace{{ relationshipName }}(at idx: Int, with value: {{ destinationEntityClassName }})
@objc(replace{{ relationshipName }}AtIndexes:with{{ relationshipName }}:)
@NSManaged public func replace{{ relationshipName }}(at indexes: NSIndexSet, with values: [{{ destinationEntityClassName }}])
{% endif %}
@objc(add{{ relationshipName }}Object:)
@NSManaged public func addTo{{ relationshipName }}(_ value: {{ destinationEntityClassName }})
@objc(remove{{ relationshipName }}Object:)
@NSManaged public func removeFrom{{ relationshipName }}(_ value: {{ destinationEntityClassName }})
@objc(add{{ relationshipName }}:)
@NSManaged public func addTo{{ relationshipName }}(_ values: {{ collectionClassName }})
@objc(remove{{ relationshipName }}:)
@NSManaged public func removeFrom{{ relationshipName }}(_ values: {{ collectionClassName }})
}
{% endfor %}
{% if model.fetchRequests[entity.name].count > 0 %}
// MARK: Fetch Requests
extension {{ entityClassName }} {
{% for fetchRequest in model.fetchRequests[entity.name] %}
{% set resultTypeName %}{% filter removeNewlines:"leading" %}
{% if fetchRequest.resultType == "Object" %}
{{ entityClassName }}
{% elif fetchRequest.resultType == "Object ID" %}
NSManagedObjectID
{% elif fetchRequest.resultType == "Dictionary" %}
[String: Any]
{% endif %}
{% endfilter %}{% endset %}
class func fetch{{ fetchRequest.name | upperFirstLetter }}({% filter removeNewlines:"leading" %}
managedObjectContext: NSManagedObjectContext
{% for variableName, variableType in fetchRequest.substitutionVariables %}
, {{ variableName | lowerFirstWord }}: {{ variableType }}
{% endfor %}
{% endfilter %}) throws -> [{{ resultTypeName }}] {
guard let persistentStoreCoordinator = managedObjectContext.persistentStoreCoordinator else {
fatalError("Managed object context has no persistent store coordinator for getting fetch request templates")
}
let model = persistentStoreCoordinator.managedObjectModel
let substitutionVariables: [String: Any] = [
{% for variableName, variableType in fetchRequest.substitutionVariables %}
"{{ variableName }}": {{ variableName | lowerFirstWord }}{{ "," if not forloop.last }}
{% empty %}
:
{% endfor %}
]
guard let fetchRequest = model.fetchRequestFromTemplate(withName: "{{ fetchRequest.name }}", substitutionVariables: substitutionVariables) else {
fatalError("No fetch request template named '{{ fetchRequest.name }}' found.")
}
guard let result = try managedObjectContext.fetch(fetchRequest) as? [{{ resultTypeName }}] else {
fatalError("Unable to cast fetch result to correct result type.")
}
return result
}
{% endfor %}
}
{% endif %}
{% endif %}
{% endfor %}
{% endfor %}
// swiftlint:enable identifier_name line_length type_body_length

View file

@ -0,0 +1,211 @@
// swiftlint:disable all
// Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen
// swiftlint:disable superfluous_disable_command implicit_return
// swiftlint:disable sorted_imports
import CoreData
import Foundation
{% for import in param.extraImports %}
import {{ import }}
{% empty %}
{# If extraImports is a single String instead of an array, `for` considers it empty but we still have to check if there's a single String value #}
{% if param.extraImports %}import {{ param.extraImports }}{% endif %}
{% endfor %}
// swiftlint:disable attributes file_length vertical_whitespace_closing_braces
// swiftlint:disable identifier_name line_length type_body_length
{% set accessModifier %}{% if param.publicAccess %}public{% else %}internal{% endif %}{% endset %}
{% for model in models %}
{% for name, entity in model.entities %}
{% set superclass %}{{ model.entities[entity.superEntity].className|default:"NSManagedObject" }}{% endset %}
{% set entityClassName %}{{ entity.className|default:"NSManagedObject" }}{% endset %}
// MARK: - {{ entity.name }}
{% if not entity.shouldGenerateCode %}
// Note: '{{ entity.name }}' has codegen enabled for Xcode, skipping code generation.
{% elif entityClassName|contains:"." %}
// Warning: '{{ entityClassName }}' cannot be a valid type name, skipping code generation.
{% else %}
{% if param.generateObjcName %}
@objc({{ entityClassName }})
{% endif %}
{{ accessModifier }} class {{ entityClassName }}: {{ superclass }} {
{% set override %}{% if superclass != "NSManagedObject" %}override {% endif %}{% endset %}
{{ override }}{{ accessModifier }} class var entityName: String {
return "{{ entity.name }}"
}
{{ override }}{{ accessModifier }} class func entity(in managedObjectContext: NSManagedObjectContext) -> NSEntityDescription? {
return NSEntityDescription.entity(forEntityName: entityName, in: managedObjectContext)
}
@available(*, deprecated, renamed: "makeFetchRequest", message: "To avoid collisions with the less concrete method in `NSManagedObject`, please use `makeFetchRequest()` instead.")
@nonobjc {{ accessModifier }} class func fetchRequest() -> NSFetchRequest<{{ entityClassName }}> {
return NSFetchRequest<{{ entityClassName }}>(entityName: entityName)
}
@nonobjc {{ accessModifier }} class func makeFetchRequest() -> NSFetchRequest<{{ entityClassName }}> {
return NSFetchRequest<{{ entityClassName }}>(entityName: entityName)
}
// swiftlint:disable discouraged_optional_boolean discouraged_optional_collection
{% for attribute in entity.attributes %}
{% if attribute.userInfo.RawType %}
{% set rawType attribute.userInfo.RawType %}
{% set unwrapOptional attribute.userInfo.unwrapOptional %}
{{ accessModifier }} var {{ attribute.name }}: {{ rawType }}{% if not unwrapOptional %}?{% endif %} {
get {
let key = "{{ attribute.name }}"
willAccessValue(forKey: key)
defer { didAccessValue(forKey: key) }
{% if unwrapOptional %}
guard let value = primitiveValue(forKey: key) as? {{ rawType }}.RawValue,
let result = {{ rawType }}(rawValue: value) else {
fatalError("Could not convert value for key '\(key)' to type '{{ rawType }}'")
}
return result
{% else %}
guard let value = primitiveValue(forKey: key) as? {{ rawType }}.RawValue else {
return nil
}
return {{ rawType }}(rawValue: value)
{% endif %}
}
set {
let key = "{{ attribute.name }}"
willChangeValue(forKey: key)
defer { didChangeValue(forKey: key) }
setPrimitiveValue(newValue{% if not unwrapOptional %}?{% endif %}.rawValue, forKey: key)
}
}
{% elif attribute.usesScalarValueType and attribute.isOptional %}
{{ accessModifier }} var {{ attribute.name }}: {{ attribute.typeName }}? {
get {
let key = "{{ attribute.name }}"
willAccessValue(forKey: key)
defer { didAccessValue(forKey: key) }
return primitiveValue(forKey: key) as? {{ attribute.typeName }}
}
set {
let key = "{{ attribute.name }}"
willChangeValue(forKey: key)
defer { didChangeValue(forKey: key) }
setPrimitiveValue(newValue, forKey: key)
}
}
{% else %}
@NSManaged {{ accessModifier }} var {{ attribute.name }}: {{ attribute.typeName }}{% if attribute.isOptional %}?{% endif %}
{% endif %}
{% endfor %}
{% for relationship in entity.relationships %}
{% if relationship.isToMany %}
@NSManaged {{ accessModifier }} var {{ relationship.name }}: {% if relationship.isOrdered %}NSOrderedSet{% else %}Set<{{ model.entities[relationship.destinationEntity].className|default:"NSManagedObject" }}>{% endif %}{% if relationship.isOptional %}?{% endif %}
{% else %}
@NSManaged {{ accessModifier }} var {{ relationship.name }}: {{ model.entities[relationship.destinationEntity].className|default:"NSManagedObject" }}{% if relationship.isOptional %}?{% endif %}
{% endif %}
{% endfor %}
{% for fetchedProperty in entity.fetchedProperties %}
@NSManaged {{ accessModifier }} var {{ fetchedProperty.name }}: [{{ fetchedProperty.fetchRequest.entity }}]
{% endfor %}
// swiftlint:enable discouraged_optional_boolean discouraged_optional_collection
}
{% for relationship in entity.relationships where relationship.isToMany %}
{% set destinationEntityClassName %}{{ model.entities[relationship.destinationEntity].className|default:"NSManagedObject" }}{% endset %}
{% set collectionClassName %}{% if relationship.isOrdered %}NSOrderedSet{% else %}Set<{{ destinationEntityClassName }}>{% endif %}{% endset %}
{% set relationshipName %}{{ relationship.name | upperFirstLetter }}{% endset %}
// MARK: Relationship {{ relationshipName }}
extension {{ entityClassName }} {
{% if relationship.isOrdered %}
@objc(insertObject:in{{ relationshipName }}AtIndex:)
@NSManaged public func insertInto{{ relationshipName }}(_ value: {{ destinationEntityClassName }}, at idx: Int)
@objc(removeObjectFrom{{ relationshipName }}AtIndex:)
@NSManaged public func removeFrom{{ relationshipName }}(at idx: Int)
@objc(insert{{ relationshipName }}:atIndexes:)
@NSManaged public func insertInto{{ relationshipName }}(_ values: [{{ destinationEntityClassName }}], at indexes: NSIndexSet)
@objc(remove{{ relationshipName }}AtIndexes:)
@NSManaged public func removeFrom{{ relationshipName }}(at indexes: NSIndexSet)
@objc(replaceObjectIn{{ relationshipName }}AtIndex:withObject:)
@NSManaged public func replace{{ relationshipName }}(at idx: Int, with value: {{ destinationEntityClassName }})
@objc(replace{{ relationshipName }}AtIndexes:with{{ relationshipName }}:)
@NSManaged public func replace{{ relationshipName }}(at indexes: NSIndexSet, with values: [{{ destinationEntityClassName }}])
{% endif %}
@objc(add{{ relationshipName }}Object:)
@NSManaged public func addTo{{ relationshipName }}(_ value: {{ destinationEntityClassName }})
@objc(remove{{ relationshipName }}Object:)
@NSManaged public func removeFrom{{ relationshipName }}(_ value: {{ destinationEntityClassName }})
@objc(add{{ relationshipName }}:)
@NSManaged public func addTo{{ relationshipName }}(_ values: {{ collectionClassName }})
@objc(remove{{ relationshipName }}:)
@NSManaged public func removeFrom{{ relationshipName }}(_ values: {{ collectionClassName }})
}
{% endfor %}
{% if model.fetchRequests[entity.name].count > 0 %}
// MARK: Fetch Requests
extension {{ entityClassName }} {
{% for fetchRequest in model.fetchRequests[entity.name] %}
{% set resultTypeName %}{% filter removeNewlines:"leading" %}
{% if fetchRequest.resultType == "Object" %}
{{ entityClassName }}
{% elif fetchRequest.resultType == "Object ID" %}
NSManagedObjectID
{% elif fetchRequest.resultType == "Dictionary" %}
[String: Any]
{% endif %}
{% endfilter %}{% endset %}
class func fetch{{ fetchRequest.name | upperFirstLetter }}({% filter removeNewlines:"leading" %}
managedObjectContext: NSManagedObjectContext
{% for variableName, variableType in fetchRequest.substitutionVariables %}
, {{ variableName | lowerFirstWord }}: {{ variableType }}
{% endfor %}
{% endfilter %}) throws -> [{{ resultTypeName }}] {
guard let persistentStoreCoordinator = managedObjectContext.persistentStoreCoordinator else {
fatalError("Managed object context has no persistent store coordinator for getting fetch request templates")
}
let model = persistentStoreCoordinator.managedObjectModel
let substitutionVariables: [String: Any] = [
{% for variableName, variableType in fetchRequest.substitutionVariables %}
"{{ variableName }}": {{ variableName | lowerFirstWord }}{{ "," if not forloop.last }}
{% empty %}
:
{% endfor %}
]
guard let fetchRequest = model.fetchRequestFromTemplate(withName: "{{ fetchRequest.name }}", substitutionVariables: substitutionVariables) else {
fatalError("No fetch request template named '{{ fetchRequest.name }}' found.")
}
guard let result = try managedObjectContext.fetch(fetchRequest) as? [{{ resultTypeName }}] else {
fatalError("Unable to cast fetch result to correct result type.")
}
return result
}
{% endfor %}
}
{% endif %}
{% endif %}
{% endfor %}
{% endfor %}
// swiftlint:enable identifier_name line_length type_body_length

View file

@ -0,0 +1,103 @@
// swiftlint:disable all
// Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen
{% if groups.count > 0 %}
{% set enumName %}{{param.enumName|default:"Files"}}{% endset %}
{% set useExt %}{% if param.useExtension|default:"true" %}true{% endif %}{% endset %}
{% set accessModifier %}{% if param.publicAccess %}public{% else %}internal{% endif %}{% endset %}
{% set resourceType %}{{param.resourceTypeName|default:"File"}}{% endset %}
import Foundation
// swiftlint:disable superfluous_disable_command file_length line_length implicit_return
// MARK: - Files
{% macro groupBlock group %}
{% for file in group.files %}
{% call fileBlock file %}
{% endfor %}
{% for dir in group.directories %}
{% call dirBlock dir %}
{% endfor %}
{% endmacro %}
{% macro fileBlock file %}
/// {% if file.path and param.preservePath %}{{file.path}}/{% endif %}{{file.name}}{% if file.ext %}.{{file.ext}}{% endif %}
{% set identifier %}{{ file.name }}{% if useExt %}.{{ file.ext }}{% endif %}{% endset %}
{{accessModifier}} static let {{identifier|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}} = {{resourceType}}(name: "{{file.name}}", ext: {% if file.ext %}"{{file.ext}}"{% else %}nil{% endif %}, relativePath: "{{file.path if param.preservePath}}", mimeType: "{{file.mimeType}}")
{% endmacro %}
{% macro dirBlock directory %}
{% for file in directory.files %}
{% call fileBlock file %}
{% endfor %}
{% for dir in directory.directories %}
{% call dirBlock dir %}
{% endfor %}
{% endmacro %}
// swiftlint:disable explicit_type_interface identifier_name
// swiftlint:disable nesting type_body_length type_name vertical_whitespace_opening_braces
{{accessModifier}} enum {{enumName}} {
{% if groups.count > 1 or param.forceFileNameEnum %}
{% for group in groups %}
{{accessModifier}} enum {{group.name|swiftIdentifier:"pretty"|escapeReservedKeywords}} {
{% filter indent:2 %}{% call groupBlock group %}{% endfilter %}
}
{% endfor %}
{% else %}
{% call groupBlock groups.first %}
{% endif %}
}
// swiftlint:enable explicit_type_interface identifier_name
// swiftlint:enable nesting type_body_length type_name vertical_whitespace_opening_braces
// MARK: - Implementation Details
{{accessModifier}} struct {{resourceType}} {
{{accessModifier}} let name: String
{{accessModifier}} let ext: String?
{{accessModifier}} let relativePath: String
{{accessModifier}} let mimeType: String
{{accessModifier}} var url: URL {
return url(locale: nil)
}
{{accessModifier}} func url(locale: Locale?) -> URL {
let bundle = {{param.bundle|default:"BundleToken.bundle"}}
let url = bundle.url(
forResource: name,
withExtension: ext,
subdirectory: relativePath,
localization: locale?.identifier
)
guard let result = url else {
let file = name + (ext.flatMap { ".\($0)" } ?? "")
fatalError("Could not locate file named \(file)")
}
return result
}
{{accessModifier}} var path: String {
return path(locale: nil)
}
{{accessModifier}} func path(locale: Locale?) -> String {
return url(locale: locale).path
}
}
{% if not param.bundle %}
// swiftlint:disable convenience_type explicit_type_interface
private final class BundleToken {
static let bundle: Bundle = {
#if SWIFT_PACKAGE
return Bundle.module
#else
return Bundle(for: BundleToken.self)
#endif
}()
}
// swiftlint:enable convenience_type explicit_type_interface
{% endif %}
{% else %}
// No files found
{% endif %}

View file

@ -0,0 +1,103 @@
// swiftlint:disable all
// Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen
{% if groups.count > 0 %}
{% set enumName %}{{param.enumName|default:"Files"}}{% endset %}
{% set useExt %}{% if param.useExtension|default:"true" %}true{% endif %}{% endset %}
{% set accessModifier %}{% if param.publicAccess %}public{% else %}internal{% endif %}{% endset %}
{% set resourceType %}{{param.resourceTypeName|default:"File"}}{% endset %}
import Foundation
// swiftlint:disable superfluous_disable_command file_length line_length implicit_return
// MARK: - Files
{% macro groupBlock group %}
{% for file in group.files %}
{% call fileBlock file %}
{% endfor %}
{% for dir in group.directories %}
{% call dirBlock dir %}
{% endfor %}
{% endmacro %}
{% macro fileBlock file %}
/// {% if file.path and param.preservePath %}{{file.path}}/{% endif %}{{file.name}}{% if file.ext %}.{{file.ext}}{% endif %}
{% set identifier %}{{ file.name }}{% if useExt %}.{{ file.ext }}{% endif %}{% endset %}
{{accessModifier}} static let {{identifier|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}} = {{resourceType}}(name: "{{file.name}}", ext: {% if file.ext %}"{{file.ext}}"{% else %}nil{% endif %}, relativePath: "{{file.path if param.preservePath}}", mimeType: "{{file.mimeType}}")
{% endmacro %}
{% macro dirBlock directory %}
{% for file in directory.files %}
{% call fileBlock file %}
{% endfor %}
{% for dir in directory.directories %}
{% call dirBlock dir %}
{% endfor %}
{% endmacro %}
// swiftlint:disable explicit_type_interface identifier_name
// swiftlint:disable nesting type_body_length type_name vertical_whitespace_opening_braces
{{accessModifier}} enum {{enumName}} {
{% if groups.count > 1 or param.forceFileNameEnum %}
{% for group in groups %}
{{accessModifier}} enum {{group.name|swiftIdentifier:"pretty"|escapeReservedKeywords}} {
{% filter indent:2 %}{% call groupBlock group %}{% endfilter %}
}
{% endfor %}
{% else %}
{% call groupBlock groups.first %}
{% endif %}
}
// swiftlint:enable explicit_type_interface identifier_name
// swiftlint:enable nesting type_body_length type_name vertical_whitespace_opening_braces
// MARK: - Implementation Details
{{accessModifier}} struct {{resourceType}} {
{{accessModifier}} let name: String
{{accessModifier}} let ext: String?
{{accessModifier}} let relativePath: String
{{accessModifier}} let mimeType: String
{{accessModifier}} var url: URL {
return url(locale: nil)
}
{{accessModifier}} func url(locale: Locale?) -> URL {
let bundle = {{param.bundle|default:"BundleToken.bundle"}}
let url = bundle.url(
forResource: name,
withExtension: ext,
subdirectory: relativePath,
localization: locale?.identifier
)
guard let result = url else {
let file = name + (ext.flatMap { ".\($0)" } ?? "")
fatalError("Could not locate file named \(file)")
}
return result
}
{{accessModifier}} var path: String {
return path(locale: nil)
}
{{accessModifier}} func path(locale: Locale?) -> String {
return url(locale: locale).path
}
}
{% if not param.bundle %}
// swiftlint:disable convenience_type explicit_type_interface
private final class BundleToken {
static let bundle: Bundle = {
#if SWIFT_PACKAGE
return Bundle.module
#else
return Bundle(for: BundleToken.self)
#endif
}()
}
// swiftlint:enable convenience_type explicit_type_interface
{% endif %}
{% else %}
// No files found
{% endif %}

View file

@ -0,0 +1,107 @@
// swiftlint:disable all
// Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen
{% if groups.count > 0 %}
{% set enumName %}{{param.enumName|default:"Files"}}{% endset %}
{% set useExt %}{% if param.useExtension|default:"true" %}true{% endif %}{% endset %}
{% set accessModifier %}{% if param.publicAccess %}public{% else %}internal{% endif %}{% endset %}
{% set resourceType %}{{param.resourceTypeName|default:"File"}}{% endset %}
import Foundation
// swiftlint:disable superfluous_disable_command file_length line_length implicit_return
// MARK: - Files
{% macro groupBlock group %}
{% for file in group.files %}
{% call fileBlock file %}
{% endfor %}
{% for dir in group.directories %}
{% call dirBlock dir "" %}
{% endfor %}
{% endmacro %}
{% macro fileBlock file %}
/// {% if file.path and param.preservePath %}{{file.path}}/{% endif %}{{file.name}}{% if file.ext %}.{{file.ext}}{% endif %}
{% set identifier %}{{ file.name }}{% if useExt %}.{{ file.ext }}{% endif %}{% endset %}
{{accessModifier}} static let {{identifier|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}} = {{resourceType}}(name: "{{file.name}}", ext: {% if file.ext %}"{{file.ext}}"{% else %}nil{% endif %}, relativePath: "{{file.path if param.preservePath}}", mimeType: "{{file.mimeType}}")
{% endmacro %}
{% macro dirBlock directory parent %}
{% set fullDir %}{{parent}}{{directory.name}}/{% endset %}
/// {{ fullDir }}
{{accessModifier}} enum {{directory.name|swiftIdentifier:"pretty"|escapeReservedKeywords}} {
{% for file in directory.files %}
{% filter indent:2 %}{% call fileBlock file %}{% endfilter %}
{% endfor %}
{% for dir in directory.directories %}
{% filter indent:2 %}{% call dirBlock dir fullDir %}{% endfilter %}
{% endfor %}
}
{% endmacro %}
// swiftlint:disable explicit_type_interface identifier_name
// swiftlint:disable nesting type_body_length type_name vertical_whitespace_opening_braces
{{accessModifier}} enum {{enumName}} {
{% if groups.count > 1 or param.forceFileNameEnum %}
{% for group in groups %}
{{accessModifier}} enum {{group.name|swiftIdentifier:"pretty"|escapeReservedKeywords}} {
{% filter indent:2 %}{% call groupBlock group %}{% endfilter %}
}
{% endfor %}
{% else %}
{% call groupBlock groups.first %}
{% endif %}
}
// swiftlint:enable explicit_type_interface identifier_name
// swiftlint:enable nesting type_body_length type_name vertical_whitespace_opening_braces
// MARK: - Implementation Details
{{accessModifier}} struct {{resourceType}} {
{{accessModifier}} let name: String
{{accessModifier}} let ext: String?
{{accessModifier}} let relativePath: String
{{accessModifier}} let mimeType: String
{{accessModifier}} var url: URL {
return url(locale: nil)
}
{{accessModifier}} func url(locale: Locale?) -> URL {
let bundle = {{param.bundle|default:"BundleToken.bundle"}}
let url = bundle.url(
forResource: name,
withExtension: ext,
subdirectory: relativePath,
localization: locale?.identifier
)
guard let result = url else {
let file = name + (ext.flatMap { ".\($0)" } ?? "")
fatalError("Could not locate file named \(file)")
}
return result
}
{{accessModifier}} var path: String {
return path(locale: nil)
}
{{accessModifier}} func path(locale: Locale?) -> String {
return url(locale: locale).path
}
}
{% if not param.bundle %}
// swiftlint:disable convenience_type explicit_type_interface
private final class BundleToken {
static let bundle: Bundle = {
#if SWIFT_PACKAGE
return Bundle.module
#else
return Bundle(for: BundleToken.self)
#endif
}()
}
// swiftlint:enable convenience_type explicit_type_interface
{% endif %}
{% else %}
// No files found
{% endif %}

View file

@ -0,0 +1,107 @@
// swiftlint:disable all
// Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen
{% if groups.count > 0 %}
{% set enumName %}{{param.enumName|default:"Files"}}{% endset %}
{% set useExt %}{% if param.useExtension|default:"true" %}true{% endif %}{% endset %}
{% set accessModifier %}{% if param.publicAccess %}public{% else %}internal{% endif %}{% endset %}
{% set resourceType %}{{param.resourceTypeName|default:"File"}}{% endset %}
import Foundation
// swiftlint:disable superfluous_disable_command file_length line_length implicit_return
// MARK: - Files
{% macro groupBlock group %}
{% for file in group.files %}
{% call fileBlock file %}
{% endfor %}
{% for dir in group.directories %}
{% call dirBlock dir "" %}
{% endfor %}
{% endmacro %}
{% macro fileBlock file %}
/// {% if file.path and param.preservePath %}{{file.path}}/{% endif %}{{file.name}}{% if file.ext %}.{{file.ext}}{% endif %}
{% set identifier %}{{ file.name }}{% if useExt %}.{{ file.ext }}{% endif %}{% endset %}
{{accessModifier}} static let {{identifier|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}} = {{resourceType}}(name: "{{file.name}}", ext: {% if file.ext %}"{{file.ext}}"{% else %}nil{% endif %}, relativePath: "{{file.path if param.preservePath}}", mimeType: "{{file.mimeType}}")
{% endmacro %}
{% macro dirBlock directory parent %}
{% set fullDir %}{{parent}}{{directory.name}}/{% endset %}
/// {{ fullDir }}
{{accessModifier}} enum {{directory.name|swiftIdentifier:"pretty"|escapeReservedKeywords}} {
{% for file in directory.files %}
{% filter indent:2 %}{% call fileBlock file %}{% endfilter %}
{% endfor %}
{% for dir in directory.directories %}
{% filter indent:2 %}{% call dirBlock dir fullDir %}{% endfilter %}
{% endfor %}
}
{% endmacro %}
// swiftlint:disable explicit_type_interface identifier_name
// swiftlint:disable nesting type_body_length type_name vertical_whitespace_opening_braces
{{accessModifier}} enum {{enumName}} {
{% if groups.count > 1 or param.forceFileNameEnum %}
{% for group in groups %}
{{accessModifier}} enum {{group.name|swiftIdentifier:"pretty"|escapeReservedKeywords}} {
{% filter indent:2 %}{% call groupBlock group %}{% endfilter %}
}
{% endfor %}
{% else %}
{% call groupBlock groups.first %}
{% endif %}
}
// swiftlint:enable explicit_type_interface identifier_name
// swiftlint:enable nesting type_body_length type_name vertical_whitespace_opening_braces
// MARK: - Implementation Details
{{accessModifier}} struct {{resourceType}} {
{{accessModifier}} let name: String
{{accessModifier}} let ext: String?
{{accessModifier}} let relativePath: String
{{accessModifier}} let mimeType: String
{{accessModifier}} var url: URL {
return url(locale: nil)
}
{{accessModifier}} func url(locale: Locale?) -> URL {
let bundle = {{param.bundle|default:"BundleToken.bundle"}}
let url = bundle.url(
forResource: name,
withExtension: ext,
subdirectory: relativePath,
localization: locale?.identifier
)
guard let result = url else {
let file = name + (ext.flatMap { ".\($0)" } ?? "")
fatalError("Could not locate file named \(file)")
}
return result
}
{{accessModifier}} var path: String {
return path(locale: nil)
}
{{accessModifier}} func path(locale: Locale?) -> String {
return url(locale: locale).path
}
}
{% if not param.bundle %}
// swiftlint:disable convenience_type explicit_type_interface
private final class BundleToken {
static let bundle: Bundle = {
#if SWIFT_PACKAGE
return Bundle.module
#else
return Bundle(for: BundleToken.self)
#endif
}()
}
// swiftlint:enable convenience_type explicit_type_interface
{% endif %}
{% else %}
// No files found
{% endif %}

View file

@ -0,0 +1,110 @@
// swiftlint:disable all
// Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen
{% if families %}
{% set accessModifier %}{% if param.publicAccess %}public{% else %}internal{% endif %}{% endset %}
{% set fontType %}{{param.fontTypeName|default:"FontConvertible"}}{% endset %}
#if os(macOS)
import AppKit.NSFont
#elseif os(iOS) || os(tvOS) || os(watchOS)
import UIKit.UIFont
#endif
// Deprecated typealiases
@available(*, deprecated, renamed: "{{fontType}}.Font", message: "This typealias will be removed in SwiftGen 7.0")
{{accessModifier}} typealias {{param.fontAliasName|default:"Font"}} = {{fontType}}.Font
// swiftlint:disable superfluous_disable_command
// swiftlint:disable file_length
// swiftlint:disable implicit_return
// MARK: - Fonts
// swiftlint:disable identifier_name line_length type_body_length
{% macro transformPath path %}{% filter removeNewlines %}
{% if param.preservePath %}
{{path}}
{% else %}
{{path|basename}}
{% endif %}
{% endfilter %}{% endmacro %}
{{accessModifier}} enum {{param.enumName|default:"FontFamily"}} {
{% for family in families %}
{{accessModifier}} enum {{family.name|swiftIdentifier:"pretty"|escapeReservedKeywords}} {
{% for font in family.fonts %}
{{accessModifier}} static let {{font.style|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}} = {{fontType}}(name: "{{font.name}}", family: "{{family.name}}", path: "{% call transformPath font.path %}")
{% endfor %}
{{accessModifier}} static let all: [{{fontType}}] = [{% for font in family.fonts %}{{font.style|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}}{{ ", " if not forloop.last }}{% endfor %}]
}
{% endfor %}
{{accessModifier}} static let allCustomFonts: [{{fontType}}] = [{% for family in families %}{{family.name|swiftIdentifier:"pretty"|escapeReservedKeywords}}.all{{ ", " if not forloop.last }}{% endfor %}].flatMap { $0 }
{{accessModifier}} static func registerAllCustomFonts() {
allCustomFonts.forEach { $0.register() }
}
}
// swiftlint:enable identifier_name line_length type_body_length
// MARK: - Implementation Details
{{accessModifier}} struct {{fontType}} {
{{accessModifier}} let name: String
{{accessModifier}} let family: String
{{accessModifier}} let path: String
#if os(macOS)
{{accessModifier}} typealias Font = NSFont
#elseif os(iOS) || os(tvOS) || os(watchOS)
{{accessModifier}} typealias Font = UIFont
#endif
{{accessModifier}} func font(size: CGFloat) -> Font! {
return Font(font: self, size: size)
}
{{accessModifier}} func register() {
// swiftlint:disable:next conditional_returns_on_newline
guard let url = url else { return }
CTFontManagerRegisterFontsForURL(url as CFURL, .process, nil)
}
fileprivate var url: URL? {
{% if param.lookupFunction %}
return {{param.lookupFunction}}(name, family, path)
{% else %}
return {{param.bundle|default:"BundleToken.bundle"}}.url(forResource: path, withExtension: nil)
{% endif %}
}
}
{{accessModifier}} extension {{fontType}}.Font {
convenience init?(font: {{fontType}}, size: CGFloat) {
#if os(iOS) || os(tvOS) || os(watchOS)
if !UIFont.fontNames(forFamilyName: font.family).contains(font.name) {
font.register()
}
#elseif os(macOS)
if let url = font.url, CTFontManagerGetScopeForURL(url as CFURL) == .none {
font.register()
}
#endif
self.init(name: font.name, size: size)
}
}
{% if not param.bundle and not param.lookupFunction %}
// swiftlint:disable convenience_type
private final class BundleToken {
static let bundle: Bundle = {
#if SWIFT_PACKAGE
return Bundle.module
#else
return Bundle(for: BundleToken.self)
#endif
}()
}
// swiftlint:enable convenience_type
{% endif %}
{% else %}
// No fonts found
{% endif %}

View file

@ -0,0 +1,113 @@
// swiftlint:disable all
// Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen
{% if families %}
{% set accessModifier %}{% if param.publicAccess %}public{% else %}internal{% endif %}{% endset %}
{% set fontType %}{{param.fontTypeName|default:"FontConvertible"}}{% endset %}
#if os(macOS)
import AppKit.NSFont
#elseif os(iOS) || os(tvOS) || os(watchOS)
import UIKit.UIFont
#endif
// Deprecated typealiases
@available(*, deprecated, renamed: "{{fontType}}.Font", message: "This typealias will be removed in SwiftGen 7.0")
{{accessModifier}} typealias {{param.fontAliasName|default:"Font"}} = {{fontType}}.Font
// swiftlint:disable superfluous_disable_command
// swiftlint:disable file_length
// MARK: - Fonts
// swiftlint:disable identifier_name line_length type_body_length
{% macro transformPath path %}{% filter removeNewlines %}
{% if param.preservePath %}
{{path}}
{% else %}
{{path|basename}}
{% endif %}
{% endfilter %}{% endmacro %}
{{accessModifier}} enum {{param.enumName|default:"FontFamily"}} {
{% for family in families %}
{{accessModifier}} enum {{family.name|swiftIdentifier:"pretty"|escapeReservedKeywords}} {
{% for font in family.fonts %}
{{accessModifier}} static let {{font.style|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}} = {{fontType}}(name: "{{font.name}}", family: "{{family.name}}", path: "{% call transformPath font.path %}")
{% endfor %}
{{accessModifier}} static let all: [{{fontType}}] = [{% for font in family.fonts %}{{font.style|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}}{{ ", " if not forloop.last }}{% endfor %}]
}
{% endfor %}
{{accessModifier}} static let allCustomFonts: [{{fontType}}] = [{% for family in families %}{{family.name|swiftIdentifier:"pretty"|escapeReservedKeywords}}.all{{ ", " if not forloop.last }}{% endfor %}].flatMap { $0 }
{{accessModifier}} static func registerAllCustomFonts() {
allCustomFonts.forEach { $0.register() }
}
}
// swiftlint:enable identifier_name line_length type_body_length
// MARK: - Implementation Details
{{accessModifier}} struct {{fontType}} {
{{accessModifier}} let name: String
{{accessModifier}} let family: String
{{accessModifier}} let path: String
#if os(macOS)
{{accessModifier}} typealias Font = NSFont
#elseif os(iOS) || os(tvOS) || os(watchOS)
{{accessModifier}} typealias Font = UIFont
#endif
{{accessModifier}} func font(size: CGFloat) -> Font {
guard let font = Font(font: self, size: size) else {
fatalError("Unable to initialize font '\(name)' (\(family))")
}
return font
}
{{accessModifier}} func register() {
// swiftlint:disable:next conditional_returns_on_newline
guard let url = url else { return }
CTFontManagerRegisterFontsForURL(url as CFURL, .process, nil)
}
fileprivate var url: URL? {
// swiftlint:disable:next implicit_return
{% if param.lookupFunction %}
return {{param.lookupFunction}}(name, family, path)
{% else %}
return {{param.bundle|default:"BundleToken.bundle"}}.url(forResource: path, withExtension: nil)
{% endif %}
}
}
{{accessModifier}} extension {{fontType}}.Font {
convenience init?(font: {{fontType}}, size: CGFloat) {
#if os(iOS) || os(tvOS) || os(watchOS)
if !UIFont.fontNames(forFamilyName: font.family).contains(font.name) {
font.register()
}
#elseif os(macOS)
if let url = font.url, CTFontManagerGetScopeForURL(url as CFURL) == .none {
font.register()
}
#endif
self.init(name: font.name, size: size)
}
}
{% if not param.bundle and not param.lookupFunction %}
// swiftlint:disable convenience_type
private final class BundleToken {
static let bundle: Bundle = {
#if SWIFT_PACKAGE
return Bundle.module
#else
return Bundle(for: BundleToken.self)
#endif
}()
}
// swiftlint:enable convenience_type
{% endif %}
{% else %}
// No fonts found
{% endif %}

View file

@ -0,0 +1,157 @@
// swiftlint:disable all
// Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen
{% if platform and storyboards %}
{% set accessModifier %}{% if param.publicAccess %}public{% else %}internal{% endif %}{% endset %}
{% set isAppKit %}{% if platform == "macOS" %}true{% endif %}{% endset %}
{% set prefix %}{% if isAppKit %}NS{% else %}UI{% endif %}{% endset %}
{% set controller %}{% if isAppKit %}Controller{% else %}ViewController{% endif %}{% endset %}
// swiftlint:disable sorted_imports
import Foundation
{% for module in modules where module != env.PRODUCT_MODULE_NAME and module != param.module %}
import {{module}}
{% endfor %}
// swiftlint:disable superfluous_disable_command
// swiftlint:disable file_length implicit_return
// MARK: - Storyboard Scenes
// swiftlint:disable explicit_type_interface identifier_name line_length type_body_length type_name
{% macro moduleName item %}{% filter removeNewlines %}
{% if item.moduleIsPlaceholder %}
{{ env.PRODUCT_MODULE_NAME|default:param.module }}
{% else %}
{{ item.module }}
{% endif %}
{% endfilter %}{% endmacro %}
{% macro className item %}{% filter removeNewlines %}
{% set module %}{% call moduleName item %}{% endset %}
{% if module and ( not param.ignoreTargetModule or module != env.PRODUCT_MODULE_NAME and module != param.module ) %}
{{module}}.
{% endif %}
{{item.type}}
{% endfilter %}{% endmacro %}
{{accessModifier}} enum {{param.enumName|default:"StoryboardScene"}} {
{% for storyboard in storyboards %}
{% set storyboardName %}{{storyboard.name|swiftIdentifier:"pretty"|escapeReservedKeywords}}{% endset %}
{{accessModifier}} enum {{storyboardName}}: StoryboardType {
{{accessModifier}} static let storyboardName = "{{storyboard.name}}"
{% if storyboard.initialScene %}
{% set sceneClass %}{% call className storyboard.initialScene %}{% endset %}
{{accessModifier}} static let initialScene = InitialSceneType<{{sceneClass}}>(storyboard: {{storyboardName}}.self)
{% endif %}
{% for scene in storyboard.scenes %}
{% set sceneID %}{{scene.identifier|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}}{% endset %}
{% set sceneClass %}{% call className scene %}{% endset %}
{{accessModifier}} static let {{sceneID}} = SceneType<{{sceneClass}}>(storyboard: {{storyboardName}}.self, identifier: "{{scene.identifier}}")
{% endfor %}
}
{% endfor %}
}
// swiftlint:enable explicit_type_interface identifier_name line_length type_body_length type_name
// MARK: - Implementation Details
{{accessModifier}} protocol StoryboardType {
static var storyboardName: String { get }
}
{{accessModifier}} extension StoryboardType {
static var storyboard: {{prefix}}Storyboard {
let name = {% if isAppKit %}NSStoryboard.Name({% endif %}self.storyboardName{% if isAppKit %}){% endif %}
{% if param.lookupFunction %}
return {{param.lookupFunction}}(name)
{% else %}
return {{prefix}}Storyboard(name: name, bundle: {{param.bundle|default:"BundleToken.bundle"}})
{% endif %}
}
}
{{accessModifier}} struct SceneType<T{% if not isAppKit %}: UIViewController{% endif %}> {
{{accessModifier}} let storyboard: StoryboardType.Type
{{accessModifier}} let identifier: String
{{accessModifier}} func instantiate() -> T {
let identifier = {% if isAppKit %}NSStoryboard.SceneIdentifier({% endif %}self.identifier{% if isAppKit %}){% endif %}
guard let controller = storyboard.storyboard.instantiate{{controller}}(withIdentifier: identifier) as? T else {
fatalError("{{controller}} '\(identifier)' is not of the expected class \(T.self).")
}
return controller
}
{% if isAppKit %}
@available(macOS 10.15, *)
{{accessModifier}} func instantiate(creator block: @escaping (NSCoder) -> T?) -> T where T: NSViewController {
return storyboard.storyboard.instantiate{{controller}}(identifier: identifier, creator: block)
}
@available(macOS 10.15, *)
{{accessModifier}} func instantiate(creator block: @escaping (NSCoder) -> T?) -> T where T: NSWindowController {
return storyboard.storyboard.instantiate{{controller}}(identifier: identifier, creator: block)
}
{% else %}
@available(iOS 13.0, tvOS 13.0, *)
{{accessModifier}} func instantiate(creator block: @escaping (NSCoder) -> T?) -> T {
return storyboard.storyboard.instantiate{{controller}}(identifier: identifier, creator: block)
}
{% endif %}
}
{{accessModifier}} struct InitialSceneType<T{% if not isAppKit %}: UIViewController{% endif %}> {
{{accessModifier}} let storyboard: StoryboardType.Type
{{accessModifier}} func instantiate() -> T {
guard let controller = storyboard.storyboard.instantiateInitial{{controller}}() as? T else {
fatalError("{{controller}} is not of the expected class \(T.self).")
}
return controller
}
{% if isAppKit %}
@available(macOS 10.15, *)
{{accessModifier}} func instantiate(creator block: @escaping (NSCoder) -> T?) -> T where T: NSViewController {
guard let controller = storyboard.storyboard.instantiateInitial{{controller}}(creator: block) else {
fatalError("Storyboard \(storyboard.storyboardName) does not have an initial scene.")
}
return controller
}
@available(macOS 10.15, *)
{{accessModifier}} func instantiate(creator block: @escaping (NSCoder) -> T?) -> T where T: NSWindowController {
guard let controller = storyboard.storyboard.instantiateInitial{{controller}}(creator: block) else {
fatalError("Storyboard \(storyboard.storyboardName) does not have an initial scene.")
}
return controller
}
{% else %}
@available(iOS 13.0, tvOS 13.0, *)
{{accessModifier}} func instantiate(creator block: @escaping (NSCoder) -> T?) -> T {
guard let controller = storyboard.storyboard.instantiateInitial{{controller}}(creator: block) else {
fatalError("Storyboard \(storyboard.storyboardName) does not have an initial scene.")
}
return controller
}
{% endif %}
}
{% if not param.bundle and not param.lookupFunction %}
// swiftlint:disable convenience_type
private final class BundleToken {
static let bundle: Bundle = {
#if SWIFT_PACKAGE
return Bundle.module
#else
return Bundle(for: BundleToken.self)
#endif
}()
}
// swiftlint:enable convenience_type
{% endif %}
{% elif storyboards %}
// Mixed AppKit and UIKit storyboard files found, please invoke swiftgen with these separately
{% else %}
// No storyboard found
{% endif %}

View file

@ -0,0 +1,159 @@
// swiftlint:disable all
// Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen
{% if platform and storyboards %}
{% set accessModifier %}{% if param.publicAccess %}public{% else %}internal{% endif %}{% endset %}
{% set isAppKit %}{% if platform == "macOS" %}true{% endif %}{% endset %}
{% set prefix %}{% if isAppKit %}NS{% else %}UI{% endif %}{% endset %}
{% set controller %}{% if isAppKit %}Controller{% else %}ViewController{% endif %}{% endset %}
// swiftlint:disable sorted_imports
import Foundation
{% for module in modules where module != env.PRODUCT_MODULE_NAME and module != param.module %}
import {{module}}
{% endfor %}
// swiftlint:disable superfluous_disable_command
// swiftlint:disable file_length implicit_return
// MARK: - Storyboard Scenes
// swiftlint:disable explicit_type_interface identifier_name line_length type_body_length type_name
{% macro moduleName item %}{% filter removeNewlines %}
{% if item.moduleIsPlaceholder %}
{{ env.PRODUCT_MODULE_NAME|default:param.module }}
{% else %}
{{ item.module }}
{% endif %}
{% endfilter %}{% endmacro %}
{% macro className item %}{% filter removeNewlines %}
{% set module %}{% call moduleName item %}{% endset %}
{% if module and ( not param.ignoreTargetModule or module != env.PRODUCT_MODULE_NAME and module != param.module ) %}
{{module}}.
{% endif %}
{{item.type}}
{% endfilter %}{% endmacro %}
{{accessModifier}} enum {{param.enumName|default:"StoryboardScene"}} {
{% for storyboard in storyboards %}
{% set storyboardName %}{{storyboard.name|swiftIdentifier:"pretty"|escapeReservedKeywords}}{% endset %}
{{accessModifier}} enum {{storyboardName}}: StoryboardType {
{{accessModifier}} static let storyboardName = "{{storyboard.name}}"
{% if storyboard.initialScene %}
{% set sceneClass %}{% call className storyboard.initialScene %}{% endset %}
{{accessModifier}} static let initialScene = InitialSceneType<{{sceneClass}}>(storyboard: {{storyboardName}}.self)
{% endif %}
{% for scene in storyboard.scenes %}
{% set sceneID %}{{scene.identifier|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}}{% endset %}
{% set sceneClass %}{% call className scene %}{% endset %}
{{accessModifier}} static let {{sceneID}} = SceneType<{{sceneClass}}>(storyboard: {{storyboardName}}.self, identifier: "{{scene.identifier}}")
{% endfor %}
}
{% endfor %}
}
// swiftlint:enable explicit_type_interface identifier_name line_length type_body_length type_name
// MARK: - Implementation Details
{{accessModifier}} protocol StoryboardType {
static var storyboardName: String { get }
}
{{accessModifier}} extension StoryboardType {
static var storyboard: {{prefix}}Storyboard {
let name = {% if isAppKit %}NSStoryboard.Name({% endif %}self.storyboardName{% if isAppKit %}){% endif %}
{% if param.lookupFunction %}
return {{param.lookupFunction}}(name)
{% else %}
return {{prefix}}Storyboard(name: name, bundle: {{param.bundle|default:"BundleToken.bundle"}})
{% endif %}
}
}
{{accessModifier}} struct SceneType<T{% if not isAppKit %}: UIViewController{% endif %}> {
{{accessModifier}} let storyboard: StoryboardType.Type
{{accessModifier}} let identifier: String
{{accessModifier}} func instantiate() -> T {
let identifier = {% if isAppKit %}NSStoryboard.SceneIdentifier({% endif %}self.identifier{% if isAppKit %}){% endif %}
guard let controller = storyboard.storyboard.instantiate{{controller}}(withIdentifier: identifier) as? T else {
fatalError("{{controller}} '\(identifier)' is not of the expected class \(T.self).")
}
return controller
}
{% if isAppKit %}
@available(macOS 10.15, *)
{{accessModifier}} func instantiate(creator block: @escaping (NSCoder) -> T?) -> T where T: NSViewController {
let identifier = NSStoryboard.SceneIdentifier(self.identifier)
return storyboard.storyboard.instantiate{{controller}}(identifier: identifier, creator: block)
}
@available(macOS 10.15, *)
{{accessModifier}} func instantiate(creator block: @escaping (NSCoder) -> T?) -> T where T: NSWindowController {
let identifier = NSStoryboard.SceneIdentifier(self.identifier)
return storyboard.storyboard.instantiate{{controller}}(identifier: identifier, creator: block)
}
{% else %}
@available(iOS 13.0, tvOS 13.0, *)
{{accessModifier}} func instantiate(creator block: @escaping (NSCoder) -> T?) -> T {
return storyboard.storyboard.instantiate{{controller}}(identifier: identifier, creator: block)
}
{% endif %}
}
{{accessModifier}} struct InitialSceneType<T{% if not isAppKit %}: UIViewController{% endif %}> {
{{accessModifier}} let storyboard: StoryboardType.Type
{{accessModifier}} func instantiate() -> T {
guard let controller = storyboard.storyboard.instantiateInitial{{controller}}() as? T else {
fatalError("{{controller}} is not of the expected class \(T.self).")
}
return controller
}
{% if isAppKit %}
@available(macOS 10.15, *)
{{accessModifier}} func instantiate(creator block: @escaping (NSCoder) -> T?) -> T where T: NSViewController {
guard let controller = storyboard.storyboard.instantiateInitial{{controller}}(creator: block) else {
fatalError("Storyboard \(storyboard.storyboardName) does not have an initial scene.")
}
return controller
}
@available(macOS 10.15, *)
{{accessModifier}} func instantiate(creator block: @escaping (NSCoder) -> T?) -> T where T: NSWindowController {
guard let controller = storyboard.storyboard.instantiateInitial{{controller}}(creator: block) else {
fatalError("Storyboard \(storyboard.storyboardName) does not have an initial scene.")
}
return controller
}
{% else %}
@available(iOS 13.0, tvOS 13.0, *)
{{accessModifier}} func instantiate(creator block: @escaping (NSCoder) -> T?) -> T {
guard let controller = storyboard.storyboard.instantiateInitial{{controller}}(creator: block) else {
fatalError("Storyboard \(storyboard.storyboardName) does not have an initial scene.")
}
return controller
}
{% endif %}
}
{% if not param.bundle and not param.lookupFunction %}
// swiftlint:disable convenience_type
private final class BundleToken {
static let bundle: Bundle = {
#if SWIFT_PACKAGE
return Bundle.module
#else
return Bundle(for: BundleToken.self)
#endif
}()
}
// swiftlint:enable convenience_type
{% endif %}
{% elif storyboards %}
// Mixed AppKit and UIKit storyboard files found, please invoke swiftgen with these separately
{% else %}
// No storyboard found
{% endif %}

View file

@ -0,0 +1,60 @@
// swiftlint:disable all
// Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen
{% if platform and storyboards %}
{% set accessModifier %}{% if param.publicAccess %}public{% else %}internal{% endif %}{% endset %}
{% set isAppKit %}{% if platform == "macOS" %}true{% endif %}{% endset %}
// swiftlint:disable sorted_imports
import Foundation
{% for module in modules where module != env.PRODUCT_MODULE_NAME and module != param.module %}
import {{module}}
{% endfor %}
// swiftlint:disable superfluous_disable_command
// swiftlint:disable file_length
// MARK: - Storyboard Segues
// swiftlint:disable explicit_type_interface identifier_name line_length type_body_length type_name
{{accessModifier}} enum {{param.enumName|default:"StoryboardSegue"}} {
{% for storyboard in storyboards where storyboard.segues %}
{{accessModifier}} enum {{storyboard.name|swiftIdentifier:"pretty"|escapeReservedKeywords}}: String, SegueType {
{% for segue in storyboard.segues %}
{% set segueID %}{{segue.identifier|swiftIdentifier:"pretty"|lowerFirstWord}}{% endset %}
case {{segueID|escapeReservedKeywords}}{% if segueID != segue.identifier %} = "{{segue.identifier}}"{% endif %}
{% endfor %}
}
{% endfor %}
}
// swiftlint:enable explicit_type_interface identifier_name line_length type_body_length type_name
// MARK: - Implementation Details
{{accessModifier}} protocol SegueType: RawRepresentable {}
{{accessModifier}} extension {% if isAppKit %}NSSeguePerforming{% else %}UIViewController{% endif %} {
func perform<S: SegueType>(segue: S, sender: Any? = nil) where S.RawValue == String {
let identifier = {% if isAppKit %}NSStoryboardSegue.Identifier({% endif %}segue.rawValue{% if isAppKit %}){% endif %}
performSegue{% if isAppKit %}?{% endif %}(withIdentifier: identifier, sender: sender)
}
}
{{accessModifier}} extension SegueType where RawValue == String {
init?(_ segue: {% if isAppKit %}NS{% else %}UI{% endif %}StoryboardSegue) {
{% if isAppKit %}
#if swift(>=4.2)
guard let identifier = segue.identifier else { return nil }
#else
guard let identifier = segue.identifier?.rawValue else { return nil }
#endif
{% else %}
guard let identifier = segue.identifier else { return nil }
{% endif %}
self.init(rawValue: identifier)
}
}
{% elif storyboards %}
// Mixed AppKit and UIKit storyboard files found, please invoke swiftgen with these separately
{% else %}
// No storyboard found
{% endif %}

View file

@ -0,0 +1,60 @@
// swiftlint:disable all
// Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen
{% if platform and storyboards %}
{% set accessModifier %}{% if param.publicAccess %}public{% else %}internal{% endif %}{% endset %}
{% set isAppKit %}{% if platform == "macOS" %}true{% endif %}{% endset %}
// swiftlint:disable sorted_imports
import Foundation
{% for module in modules where module != env.PRODUCT_MODULE_NAME and module != param.module %}
import {{module}}
{% endfor %}
// swiftlint:disable superfluous_disable_command
// swiftlint:disable file_length
// MARK: - Storyboard Segues
// swiftlint:disable explicit_type_interface identifier_name line_length type_body_length type_name
{{accessModifier}} enum {{param.enumName|default:"StoryboardSegue"}} {
{% for storyboard in storyboards where storyboard.segues %}
{{accessModifier}} enum {{storyboard.name|swiftIdentifier:"pretty"|escapeReservedKeywords}}: String, SegueType {
{% for segue in storyboard.segues %}
{% set segueID %}{{segue.identifier|swiftIdentifier:"pretty"|lowerFirstWord}}{% endset %}
case {{segueID|escapeReservedKeywords}}{% if segueID != segue.identifier %} = "{{segue.identifier}}"{% endif %}
{% endfor %}
}
{% endfor %}
}
// swiftlint:enable explicit_type_interface identifier_name line_length type_body_length type_name
// MARK: - Implementation Details
{{accessModifier}} protocol SegueType: RawRepresentable {}
{{accessModifier}} extension {% if isAppKit %}NSSeguePerforming{% else %}UIViewController{% endif %} {
func perform<S: SegueType>(segue: S, sender: Any? = nil) where S.RawValue == String {
let identifier = {% if isAppKit %}NSStoryboardSegue.Identifier({% endif %}segue.rawValue{% if isAppKit %}){% endif %}
performSegue{% if isAppKit %}?{% endif %}(withIdentifier: identifier, sender: sender)
}
}
{{accessModifier}} extension SegueType where RawValue == String {
init?(_ segue: {% if isAppKit %}NS{% else %}UI{% endif %}StoryboardSegue) {
{% if isAppKit %}
#if swift(>=4.2)
guard let identifier = segue.identifier else { return nil }
#else
guard let identifier = segue.identifier?.rawValue else { return nil }
#endif
{% else %}
guard let identifier = segue.identifier else { return nil }
{% endif %}
self.init(rawValue: identifier)
}
}
{% elif storyboards %}
// Mixed AppKit and UIKit storyboard files found, please invoke swiftgen with these separately
{% else %}
// No storyboard found
{% endif %}

View file

@ -0,0 +1,82 @@
// swiftlint:disable all
// Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen
{% if files %}
{% set accessModifier %}{% if param.publicAccess %}public{% else %}internal{% endif %}{% endset %}
import Foundation
// swiftlint:disable superfluous_disable_command
// swiftlint:disable file_length
// MARK: - JSON Files
{% macro fileBlock file %}
{% call documentBlock file file.document %}
{% endmacro %}
{% macro documentBlock file document %}
{% set rootType %}{% call typeBlock document.metadata %}{% endset %}
{% if document.metadata.type == "Array" %}
{{accessModifier}} static let items: {{rootType}} = {% call valueBlock document.data document.metadata %}
{% elif document.metadata.type == "Dictionary" %}
{% for key,value in document.metadata.properties %}
{{accessModifier}} {% call propertyBlock key value document.data %}
{% endfor %}
{% else %}
{{accessModifier}} static let value: {{rootType}} = {% call valueBlock document.data document.metadata %}
{% endif %}
{% endmacro %}
{% macro typeBlock metadata %}{% filter removeNewlines:"leading" %}
{% if metadata.type == "Array" %}
[{% call typeBlock metadata.element %}]
{% elif metadata.type == "Dictionary" %}
[String: Any]
{% elif metadata.type == "Optional" %}
Any?
{% else %}
{{metadata.type}}
{% endif %}
{% endfilter %}{% endmacro %}
{% macro propertyBlock key metadata data %}{% filter removeNewlines:"leading" %}
{% set propertyName %}{{key|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}}{% endset %}
{% set propertyType %}{% call typeBlock metadata %}{% endset %}
static let {{propertyName}}: {{propertyType}} = {% call valueBlock data[key] metadata %}
{% endfilter %}{% endmacro %}
{% macro valueBlock value metadata %}{% filter removeNewlines:"leading" %}
{% if metadata.type == "String" %}
"{{ value }}"
{% elif metadata.type == "Optional" %}
nil
{% elif metadata.type == "Array" and value %}
[{% for value in value %}
{% call valueBlock value metadata.element.items[forloop.counter0]|default:metadata.element %}
{{ ", " if not forloop.last }}
{% endfor %}]
{% elif metadata.type == "Dictionary" %}
[{% for key,value in value %}
"{{key}}": {% call valueBlock value metadata.properties[key] %}
{{ ", " if not forloop.last }}
{% empty %}
:
{% endfor %}]
{% elif metadata.type == "Bool" %}
{% if value %}true{% else %}false{% endif %}
{% else %}
{{ value }}
{% endif %}
{% endfilter %}{% endmacro %}
// swiftlint:disable identifier_name line_length number_separator type_body_length
{{accessModifier}} enum {{param.enumName|default:"JSONFiles"}} {
{% if files.count > 1 or param.forceFileNameEnum %}
{% for file in files %}
{{accessModifier}} enum {{file.name|swiftIdentifier:"pretty"|escapeReservedKeywords}} {
{% filter indent:2 %}{% call fileBlock file %}{% endfilter %}
}
{% endfor %}
{% else %}
{% call fileBlock files.first %}
{% endif %}
}
// swiftlint:enable identifier_name line_length number_separator type_body_length
{% else %}
// No files found
{% endif %}

View file

@ -0,0 +1,82 @@
// swiftlint:disable all
// Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen
{% if files %}
{% set accessModifier %}{% if param.publicAccess %}public{% else %}internal{% endif %}{% endset %}
import Foundation
// swiftlint:disable superfluous_disable_command
// swiftlint:disable file_length
// MARK: - JSON Files
{% macro fileBlock file %}
{% call documentBlock file file.document %}
{% endmacro %}
{% macro documentBlock file document %}
{% set rootType %}{% call typeBlock document.metadata %}{% endset %}
{% if document.metadata.type == "Array" %}
{{accessModifier}} static let items: {{rootType}} = {% call valueBlock document.data document.metadata %}
{% elif document.metadata.type == "Dictionary" %}
{% for key,value in document.metadata.properties %}
{{accessModifier}} {% call propertyBlock key value document.data %}
{% endfor %}
{% else %}
{{accessModifier}} static let value: {{rootType}} = {% call valueBlock document.data document.metadata %}
{% endif %}
{% endmacro %}
{% macro typeBlock metadata %}{% filter removeNewlines:"leading" %}
{% if metadata.type == "Array" %}
[{% call typeBlock metadata.element %}]
{% elif metadata.type == "Dictionary" %}
[String: Any]
{% elif metadata.type == "Optional" %}
Any?
{% else %}
{{metadata.type}}
{% endif %}
{% endfilter %}{% endmacro %}
{% macro propertyBlock key metadata data %}{% filter removeNewlines:"leading" %}
{% set propertyName %}{{key|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}}{% endset %}
{% set propertyType %}{% call typeBlock metadata %}{% endset %}
static let {{propertyName}}: {{propertyType}} = {% call valueBlock data[key] metadata %}
{% endfilter %}{% endmacro %}
{% macro valueBlock value metadata %}{% filter removeNewlines:"leading" %}
{% if metadata.type == "String" %}
"{{ value }}"
{% elif metadata.type == "Optional" %}
nil
{% elif metadata.type == "Array" and value %}
[{% for value in value %}
{% call valueBlock value metadata.element.items[forloop.counter0]|default:metadata.element %}
{{ ", " if not forloop.last }}
{% endfor %}]
{% elif metadata.type == "Dictionary" %}
[{% for key,value in value %}
"{{key}}": {% call valueBlock value metadata.properties[key] %}
{{ ", " if not forloop.last }}
{% empty %}
:
{% endfor %}]
{% elif metadata.type == "Bool" %}
{% if value %}true{% else %}false{% endif %}
{% else %}
{{ value }}
{% endif %}
{% endfilter %}{% endmacro %}
// swiftlint:disable identifier_name line_length number_separator type_body_length
{{accessModifier}} enum {{param.enumName|default:"JSONFiles"}} {
{% if files.count > 1 or param.forceFileNameEnum %}
{% for file in files %}
{{accessModifier}} enum {{file.name|swiftIdentifier:"pretty"|escapeReservedKeywords}} {
{% filter indent:2 %}{% call fileBlock file %}{% endfilter %}
}
{% endfor %}
{% else %}
{% call fileBlock files.first %}
{% endif %}
}
// swiftlint:enable identifier_name line_length number_separator type_body_length
{% else %}
// No files found
{% endif %}

View file

@ -0,0 +1,112 @@
// swiftlint:disable all
// Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen
{% if files %}
{% set accessModifier %}{% if param.publicAccess %}public{% else %}internal{% endif %}{% endset %}
import Foundation
// swiftlint:disable superfluous_disable_command
// swiftlint:disable file_length
// MARK: - JSON Files
{% macro fileBlock file %}
{% call documentBlock file file.document %}
{% endmacro %}
{% macro documentBlock file document %}
{% set rootType %}{% call typeBlock document.metadata %}{% endset %}
{% if document.metadata.type == "Array" %}
{{accessModifier}} static let items: {{rootType}} = objectFromJSON(at: "{% call transformPath file.path %}")
{% elif document.metadata.type == "Dictionary" %}
private static let _document = JSONDocument(path: "{% call transformPath file.path %}")
{% for key,value in document.metadata.properties %}
{{accessModifier}} {% call propertyBlock key value %}
{% endfor %}
{% else %}
{{accessModifier}} static let value: {{rootType}} = objectFromJSON(at: "{% call transformPath file.path %}")
{% endif %}
{% endmacro %}
{% macro typeBlock metadata %}{% filter removeNewlines:"leading" %}
{% if metadata.type == "Array" %}
[{% call typeBlock metadata.element %}]
{% elif metadata.type == "Dictionary" %}
[String: Any]
{% elif metadata.type == "Optional" %}
Any?
{% else %}
{{metadata.type}}
{% endif %}
{% endfilter %}{% endmacro %}
{% macro propertyBlock key metadata %}{% filter removeNewlines:"leading" %}
{% set propertyName %}{{key|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}}{% endset %}
{% set propertyType %}{% call typeBlock metadata %}{% endset %}
static let {{propertyName}}: {{propertyType}} = _document["{{key}}"]
{% endfilter %}{% endmacro %}
{% macro transformPath path %}{% filter removeNewlines %}
{% if param.preservePath %}
{{path}}
{% else %}
{{path|basename}}
{% endif %}
{% endfilter %}{% endmacro %}
// swiftlint:disable identifier_name line_length type_body_length
{{accessModifier}} enum {{param.enumName|default:"JSONFiles"}} {
{% if files.count > 1 or param.forceFileNameEnum %}
{% for file in files %}
{{accessModifier}} enum {{file.name|swiftIdentifier:"pretty"|escapeReservedKeywords}} {
{% filter indent:2 %}{% call fileBlock file %}{% endfilter %}
}
{% endfor %}
{% else %}
{% call fileBlock files.first %}
{% endif %}
}
// swiftlint:enable identifier_name line_length type_body_length
// MARK: - Implementation Details
private func objectFromJSON<T>(at path: String) -> T {
{% if param.lookupFunction %}
guard let url = {{param.lookupFunction}}(path),
{% else %}
guard let url = {{param.bundle|default:"BundleToken.bundle"}}.url(forResource: path, withExtension: nil),
{% endif %}
let json = try? JSONSerialization.jsonObject(with: Data(contentsOf: url), options: []),
let result = json as? T else {
fatalError("Unable to load JSON at path: \(path)")
}
return result
}
private struct JSONDocument {
let data: [String: Any]
init(path: String) {
self.data = objectFromJSON(at: path)
}
subscript<T>(key: String) -> T {
guard let result = data[key] as? T else {
fatalError("Property '\(key)' is not of type \(T.self)")
}
return result
}
}
{% if not param.bundle and not param.lookupFunction %}
// swiftlint:disable convenience_type
private final class BundleToken {
static let bundle: Bundle = {
#if SWIFT_PACKAGE
return Bundle.module
#else
return Bundle(for: BundleToken.self)
#endif
}()
}
// swiftlint:enable convenience_type
{% endif %}
{% else %}
// No files found
{% endif %}

View file

@ -0,0 +1,112 @@
// swiftlint:disable all
// Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen
{% if files %}
{% set accessModifier %}{% if param.publicAccess %}public{% else %}internal{% endif %}{% endset %}
import Foundation
// swiftlint:disable superfluous_disable_command
// swiftlint:disable file_length
// MARK: - JSON Files
{% macro fileBlock file %}
{% call documentBlock file file.document %}
{% endmacro %}
{% macro documentBlock file document %}
{% set rootType %}{% call typeBlock document.metadata %}{% endset %}
{% if document.metadata.type == "Array" %}
{{accessModifier}} static let items: {{rootType}} = objectFromJSON(at: "{% call transformPath file.path %}")
{% elif document.metadata.type == "Dictionary" %}
private static let _document = JSONDocument(path: "{% call transformPath file.path %}")
{% for key,value in document.metadata.properties %}
{{accessModifier}} {% call propertyBlock key value %}
{% endfor %}
{% else %}
{{accessModifier}} static let value: {{rootType}} = objectFromJSON(at: "{% call transformPath file.path %}")
{% endif %}
{% endmacro %}
{% macro typeBlock metadata %}{% filter removeNewlines:"leading" %}
{% if metadata.type == "Array" %}
[{% call typeBlock metadata.element %}]
{% elif metadata.type == "Dictionary" %}
[String: Any]
{% elif metadata.type == "Optional" %}
Any?
{% else %}
{{metadata.type}}
{% endif %}
{% endfilter %}{% endmacro %}
{% macro propertyBlock key metadata %}{% filter removeNewlines:"leading" %}
{% set propertyName %}{{key|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}}{% endset %}
{% set propertyType %}{% call typeBlock metadata %}{% endset %}
static let {{propertyName}}: {{propertyType}} = _document["{{key}}"]
{% endfilter %}{% endmacro %}
{% macro transformPath path %}{% filter removeNewlines %}
{% if param.preservePath %}
{{path}}
{% else %}
{{path|basename}}
{% endif %}
{% endfilter %}{% endmacro %}
// swiftlint:disable identifier_name line_length type_body_length
{{accessModifier}} enum {{param.enumName|default:"JSONFiles"}} {
{% if files.count > 1 or param.forceFileNameEnum %}
{% for file in files %}
{{accessModifier}} enum {{file.name|swiftIdentifier:"pretty"|escapeReservedKeywords}} {
{% filter indent:2 %}{% call fileBlock file %}{% endfilter %}
}
{% endfor %}
{% else %}
{% call fileBlock files.first %}
{% endif %}
}
// swiftlint:enable identifier_name line_length type_body_length
// MARK: - Implementation Details
private func objectFromJSON<T>(at path: String) -> T {
{% if param.lookupFunction %}
guard let url = {{param.lookupFunction}}(path),
{% else %}
guard let url = {{param.bundle|default:"BundleToken.bundle"}}.url(forResource: path, withExtension: nil),
{% endif %}
let json = try? JSONSerialization.jsonObject(with: Data(contentsOf: url), options: []),
let result = json as? T else {
fatalError("Unable to load JSON at path: \(path)")
}
return result
}
private struct JSONDocument {
let data: [String: Any]
init(path: String) {
self.data = objectFromJSON(at: path)
}
subscript<T>(key: String) -> T {
guard let result = data[key] as? T else {
fatalError("Property '\(key)' is not of type \(T.self)")
}
return result
}
}
{% if not param.bundle and not param.lookupFunction %}
// swiftlint:disable convenience_type
private final class BundleToken {
static let bundle: Bundle = {
#if SWIFT_PACKAGE
return Bundle.module
#else
return Bundle(for: BundleToken.self)
#endif
}()
}
// swiftlint:enable convenience_type
{% endif %}
{% else %}
// No files found
{% endif %}

View file

@ -0,0 +1,82 @@
// swiftlint:disable all
// Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen
{% if files %}
{% set accessModifier %}{% if param.publicAccess %}public{% else %}internal{% endif %}{% endset %}
import Foundation
// swiftlint:disable superfluous_disable_command
// swiftlint:disable file_length
// MARK: - Plist Files
{% macro fileBlock file %}
{% call documentBlock file file.document %}
{% endmacro %}
{% macro documentBlock file document %}
{% set rootType %}{% call typeBlock document.metadata %}{% endset %}
{% if document.metadata.type == "Array" %}
{{accessModifier}} static let items: {{rootType}} = {% call valueBlock document.data document.metadata %}
{% elif document.metadata.type == "Dictionary" %}
{% for key,value in document.metadata.properties %}
{{accessModifier}} {% call propertyBlock key value document.data %}
{% endfor %}
{% else %}
{{accessModifier}} static let value: {{rootType}} = {% call valueBlock document.data document.metadata %}
{% endif %}
{% endmacro %}
{% macro typeBlock metadata %}{% filter removeNewlines:"leading" %}
{% if metadata.type == "Array" %}
[{% call typeBlock metadata.element %}]
{% elif metadata.type == "Dictionary" %}
[String: Any]
{% else %}
{{metadata.type}}
{% endif %}
{% endfilter %}{% endmacro %}
{% macro propertyBlock key metadata data %}{% filter removeNewlines:"leading" %}
{% set propertyName %}{{key|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}}{% endset %}
{% set propertyType %}{% call typeBlock metadata %}{% endset %}
static let {{propertyName}}: {{propertyType}} = {% call valueBlock data[key] metadata %}
{% endfilter %}{% endmacro %}
{% macro valueBlock value metadata %}{% filter removeNewlines:"leading" %}
{% if metadata.type == "String" %}
"{{ value }}"
{% elif metadata.type == "Date" %}
Date(timeIntervalSinceReferenceDate: {{ value.timeIntervalSinceReferenceDate }})
{% elif metadata.type == "Optional" %}
nil
{% elif metadata.type == "Array" and value %}
[{% for value in value %}
{% call valueBlock value metadata.element.items[forloop.counter0]|default:metadata.element %}
{{ ", " if not forloop.last }}
{% endfor %}]
{% elif metadata.type == "Dictionary" %}
[{% for key,value in value %}
"{{key}}": {% call valueBlock value metadata.properties[key] %}
{{ ", " if not forloop.last }}
{% empty %}
:
{% endfor %}]
{% elif metadata.type == "Bool" %}
{% if value %}true{% else %}false{% endif %}
{% else %}
{{ value }}
{% endif %}
{% endfilter %}{% endmacro %}
// swiftlint:disable identifier_name line_length number_separator type_body_length
{{accessModifier}} enum {{param.enumName|default:"PlistFiles"}} {
{% if files.count > 1 or param.forceFileNameEnum %}
{% for file in files %}
{{accessModifier}} enum {{file.name|swiftIdentifier:"pretty"|escapeReservedKeywords}} {
{% filter indent:2 %}{% call fileBlock file %}{% endfilter %}
}
{% endfor %}
{% else %}
{% call fileBlock files.first %}
{% endif %}
}
// swiftlint:enable identifier_name line_length number_separator type_body_length
{% else %}
// No files found
{% endif %}

View file

@ -0,0 +1,82 @@
// swiftlint:disable all
// Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen
{% if files %}
{% set accessModifier %}{% if param.publicAccess %}public{% else %}internal{% endif %}{% endset %}
import Foundation
// swiftlint:disable superfluous_disable_command
// swiftlint:disable file_length
// MARK: - Plist Files
{% macro fileBlock file %}
{% call documentBlock file file.document %}
{% endmacro %}
{% macro documentBlock file document %}
{% set rootType %}{% call typeBlock document.metadata %}{% endset %}
{% if document.metadata.type == "Array" %}
{{accessModifier}} static let items: {{rootType}} = {% call valueBlock document.data document.metadata %}
{% elif document.metadata.type == "Dictionary" %}
{% for key,value in document.metadata.properties %}
{{accessModifier}} {% call propertyBlock key value document.data %}
{% endfor %}
{% else %}
{{accessModifier}} static let value: {{rootType}} = {% call valueBlock document.data document.metadata %}
{% endif %}
{% endmacro %}
{% macro typeBlock metadata %}{% filter removeNewlines:"leading" %}
{% if metadata.type == "Array" %}
[{% call typeBlock metadata.element %}]
{% elif metadata.type == "Dictionary" %}
[String: Any]
{% else %}
{{metadata.type}}
{% endif %}
{% endfilter %}{% endmacro %}
{% macro propertyBlock key metadata data %}{% filter removeNewlines:"leading" %}
{% set propertyName %}{{key|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}}{% endset %}
{% set propertyType %}{% call typeBlock metadata %}{% endset %}
static let {{propertyName}}: {{propertyType}} = {% call valueBlock data[key] metadata %}
{% endfilter %}{% endmacro %}
{% macro valueBlock value metadata %}{% filter removeNewlines:"leading" %}
{% if metadata.type == "String" %}
"{{ value }}"
{% elif metadata.type == "Date" %}
Date(timeIntervalSinceReferenceDate: {{ value.timeIntervalSinceReferenceDate }})
{% elif metadata.type == "Optional" %}
nil
{% elif metadata.type == "Array" and value %}
[{% for value in value %}
{% call valueBlock value metadata.element.items[forloop.counter0]|default:metadata.element %}
{{ ", " if not forloop.last }}
{% endfor %}]
{% elif metadata.type == "Dictionary" %}
[{% for key,value in value %}
"{{key}}": {% call valueBlock value metadata.properties[key] %}
{{ ", " if not forloop.last }}
{% empty %}
:
{% endfor %}]
{% elif metadata.type == "Bool" %}
{% if value %}true{% else %}false{% endif %}
{% else %}
{{ value }}
{% endif %}
{% endfilter %}{% endmacro %}
// swiftlint:disable identifier_name line_length number_separator type_body_length
{{accessModifier}} enum {{param.enumName|default:"PlistFiles"}} {
{% if files.count > 1 or param.forceFileNameEnum %}
{% for file in files %}
{{accessModifier}} enum {{file.name|swiftIdentifier:"pretty"|escapeReservedKeywords}} {
{% filter indent:2 %}{% call fileBlock file %}{% endfilter %}
}
{% endfor %}
{% else %}
{% call fileBlock files.first %}
{% endif %}
}
// swiftlint:enable identifier_name line_length number_separator type_body_length
{% else %}
// No files found
{% endif %}

View file

@ -0,0 +1,117 @@
// swiftlint:disable all
// Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen
{% if files %}
{% set accessModifier %}{% if param.publicAccess %}public{% else %}internal{% endif %}{% endset %}
import Foundation
// swiftlint:disable superfluous_disable_command
// swiftlint:disable file_length
// MARK: - Plist Files
{% macro fileBlock file %}
{% call documentBlock file file.document %}
{% endmacro %}
{% macro documentBlock file document %}
{% set rootType %}{% call typeBlock document.metadata %}{% endset %}
{% if document.metadata.type == "Array" %}
{{accessModifier}} static let items: {{rootType}} = arrayFromPlist(at: "{% call transformPath file.path %}")
{% elif document.metadata.type == "Dictionary" %}
private static let _document = PlistDocument(path: "{% call transformPath file.path %}")
{% for key,value in document.metadata.properties %}
{{accessModifier}} {% call propertyBlock key value %}
{% endfor %}
{% else %}
// Unsupported root type `{{rootType}}`
{% endif %}
{% endmacro %}
{% macro typeBlock metadata %}{% filter removeNewlines:"leading" %}
{% if metadata.type == "Array" %}
[{% call typeBlock metadata.element %}]
{% elif metadata.type == "Dictionary" %}
[String: Any]
{% else %}
{{metadata.type}}
{% endif %}
{% endfilter %}{% endmacro %}
{% macro propertyBlock key metadata %}{% filter removeNewlines:"leading" %}
{% set propertyName %}{{key|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}}{% endset %}
{% set propertyType %}{% call typeBlock metadata %}{% endset %}
static let {{propertyName}}: {{propertyType}} = _document["{{key}}"]
{% endfilter %}{% endmacro %}
{% macro transformPath path %}{% filter removeNewlines %}
{% if param.preservePath %}
{{path}}
{% else %}
{{path|basename}}
{% endif %}
{% endfilter %}{% endmacro %}
// swiftlint:disable identifier_name line_length type_body_length
{{accessModifier}} enum {{param.enumName|default:"PlistFiles"}} {
{% if files.count > 1 or param.forceFileNameEnum %}
{% for file in files %}
{{accessModifier}} enum {{file.name|swiftIdentifier:"pretty"|escapeReservedKeywords}} {
{% filter indent:2 %}{% call fileBlock file %}{% endfilter %}
}
{% endfor %}
{% else %}
{% call fileBlock files.first %}
{% endif %}
}
// swiftlint:enable identifier_name line_length type_body_length
// MARK: - Implementation Details
private func arrayFromPlist<T>(at path: String) -> [T] {
{% if param.lookupFunction %}
guard let url = {{param.lookupFunction}}(path),
{% else %}
guard let url = {{param.bundle|default:"BundleToken.bundle"}}.url(forResource: path, withExtension: nil),
{% endif %}
let data = NSArray(contentsOf: url) as? [T] else {
fatalError("Unable to load PLIST at path: \(path)")
}
return data
}
private struct PlistDocument {
let data: [String: Any]
init(path: String) {
{% if param.lookupFunction %}
guard let url = {{param.lookupFunction}}(path),
{% else %}
guard let url = {{param.bundle|default:"BundleToken.bundle"}}.url(forResource: path, withExtension: nil),
{% endif %}
let data = NSDictionary(contentsOf: url) as? [String: Any] else {
fatalError("Unable to load PLIST at path: \(path)")
}
self.data = data
}
subscript<T>(key: String) -> T {
guard let result = data[key] as? T else {
fatalError("Property '\(key)' is not of type \(T.self)")
}
return result
}
}
{% if not param.bundle and not param.lookupFunction %}
// swiftlint:disable convenience_type
private final class BundleToken {
static let bundle: Bundle = {
#if SWIFT_PACKAGE
return Bundle.module
#else
return Bundle(for: BundleToken.self)
#endif
}()
}
// swiftlint:enable convenience_type
{% endif %}
{% else %}
// No files found
{% endif %}

View file

@ -0,0 +1,117 @@
// swiftlint:disable all
// Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen
{% if files %}
{% set accessModifier %}{% if param.publicAccess %}public{% else %}internal{% endif %}{% endset %}
import Foundation
// swiftlint:disable superfluous_disable_command
// swiftlint:disable file_length
// MARK: - Plist Files
{% macro fileBlock file %}
{% call documentBlock file file.document %}
{% endmacro %}
{% macro documentBlock file document %}
{% set rootType %}{% call typeBlock document.metadata %}{% endset %}
{% if document.metadata.type == "Array" %}
{{accessModifier}} static let items: {{rootType}} = arrayFromPlist(at: "{% call transformPath file.path %}")
{% elif document.metadata.type == "Dictionary" %}
private static let _document = PlistDocument(path: "{% call transformPath file.path %}")
{% for key,value in document.metadata.properties %}
{{accessModifier}} {% call propertyBlock key value %}
{% endfor %}
{% else %}
// Unsupported root type `{{rootType}}`
{% endif %}
{% endmacro %}
{% macro typeBlock metadata %}{% filter removeNewlines:"leading" %}
{% if metadata.type == "Array" %}
[{% call typeBlock metadata.element %}]
{% elif metadata.type == "Dictionary" %}
[String: Any]
{% else %}
{{metadata.type}}
{% endif %}
{% endfilter %}{% endmacro %}
{% macro propertyBlock key metadata %}{% filter removeNewlines:"leading" %}
{% set propertyName %}{{key|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}}{% endset %}
{% set propertyType %}{% call typeBlock metadata %}{% endset %}
static let {{propertyName}}: {{propertyType}} = _document["{{key}}"]
{% endfilter %}{% endmacro %}
{% macro transformPath path %}{% filter removeNewlines %}
{% if param.preservePath %}
{{path}}
{% else %}
{{path|basename}}
{% endif %}
{% endfilter %}{% endmacro %}
// swiftlint:disable identifier_name line_length type_body_length
{{accessModifier}} enum {{param.enumName|default:"PlistFiles"}} {
{% if files.count > 1 or param.forceFileNameEnum %}
{% for file in files %}
{{accessModifier}} enum {{file.name|swiftIdentifier:"pretty"|escapeReservedKeywords}} {
{% filter indent:2 %}{% call fileBlock file %}{% endfilter %}
}
{% endfor %}
{% else %}
{% call fileBlock files.first %}
{% endif %}
}
// swiftlint:enable identifier_name line_length type_body_length
// MARK: - Implementation Details
private func arrayFromPlist<T>(at path: String) -> [T] {
{% if param.lookupFunction %}
guard let url = {{param.lookupFunction}}(path),
{% else %}
guard let url = {{param.bundle|default:"BundleToken.bundle"}}.url(forResource: path, withExtension: nil),
{% endif %}
let data = NSArray(contentsOf: url) as? [T] else {
fatalError("Unable to load PLIST at path: \(path)")
}
return data
}
private struct PlistDocument {
let data: [String: Any]
init(path: String) {
{% if param.lookupFunction %}
guard let url = {{param.lookupFunction}}(path),
{% else %}
guard let url = {{param.bundle|default:"BundleToken.bundle"}}.url(forResource: path, withExtension: nil),
{% endif %}
let data = NSDictionary(contentsOf: url) as? [String: Any] else {
fatalError("Unable to load PLIST at path: \(path)")
}
self.data = data
}
subscript<T>(key: String) -> T {
guard let result = data[key] as? T else {
fatalError("Property '\(key)' is not of type \(T.self)")
}
return result
}
}
{% if not param.bundle and not param.lookupFunction %}
// swiftlint:disable convenience_type
private final class BundleToken {
static let bundle: Bundle = {
#if SWIFT_PACKAGE
return Bundle.module
#else
return Bundle(for: BundleToken.self)
#endif
}()
}
// swiftlint:enable convenience_type
{% endif %}
{% else %}
// No files found
{% endif %}

View file

@ -0,0 +1,99 @@
// swiftlint:disable all
// Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen
{% if tables.count > 0 %}
{% set accessModifier %}{% if param.publicAccess %}public{% else %}internal{% endif %}{% endset %}
import Foundation
// swiftlint:disable superfluous_disable_command file_length implicit_return
// MARK: - Strings
{% macro parametersBlock types %}{% filter removeNewlines:"leading" %}
{% for type in types %}
{% if type == "String" %}
_ p{{forloop.counter}}: Any
{% else %}
_ p{{forloop.counter}}: {{type}}
{% endif %}
{{ ", " if not forloop.last }}
{% endfor %}
{% endfilter %}{% endmacro %}
{% macro argumentsBlock types %}{% filter removeNewlines:"leading" %}
{% for type in types %}
{% if type == "String" %}
String(describing: p{{forloop.counter}})
{% elif type == "UnsafeRawPointer" %}
Int(bitPattern: p{{forloop.counter}})
{% else %}
p{{forloop.counter}}
{% endif %}
{{ ", " if not forloop.last }}
{% endfor %}
{% endfilter %}{% endmacro %}
{% macro recursiveBlock table item %}
{% for string in item.strings %}
{% if not param.noComments %}
{% for line in string.translation|split:"\n" %}
/// {{line}}
{% endfor %}
{% endif %}
{% if string.types %}
{{accessModifier}} static func {{string.key|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}}({% call parametersBlock string.types %}) -> String {
return {{enumName}}.tr("{{table}}", "{{string.key}}", {% call argumentsBlock string.types %})
}
{% elif param.lookupFunction %}
{# custom localization function is mostly used for in-app lang selection, so we want the loc to be recomputed at each call for those (hence the computed var) #}
{{accessModifier}} static var {{string.key|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}}: String { return {{enumName}}.tr("{{table}}", "{{string.key}}") }
{% else %}
{{accessModifier}} static let {{string.key|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}} = {{enumName}}.tr("{{table}}", "{{string.key}}")
{% endif %}
{% endfor %}
{% for child in item.children %}
{% call recursiveBlock table child %}
{% endfor %}
{% endmacro %}
// swiftlint:disable function_parameter_count identifier_name line_length type_body_length
{% set enumName %}{{param.enumName|default:"L10n"}}{% endset %}
{{accessModifier}} enum {{enumName}} {
{% if tables.count > 1 or param.forceFileNameEnum %}
{% for table in tables %}
{{accessModifier}} enum {{table.name|swiftIdentifier:"pretty"|escapeReservedKeywords}} {
{% filter indent:2 %}{% call recursiveBlock table.name table.levels %}{% endfilter %}
}
{% endfor %}
{% else %}
{% call recursiveBlock tables.first.name tables.first.levels %}
{% endif %}
}
// swiftlint:enable function_parameter_count identifier_name line_length type_body_length
// MARK: - Implementation Details
extension {{enumName}} {
private static func tr(_ table: String, _ key: String, _ args: CVarArg...) -> String {
{% if param.lookupFunction %}
let format = {{ param.lookupFunction }}(key, table)
{% else %}
let format = {{param.bundle|default:"BundleToken.bundle"}}.localizedString(forKey: key, value: nil, table: table)
{% endif %}
return String(format: format, locale: Locale.current, arguments: args)
}
}
{% if not param.bundle and not param.lookupFunction %}
// swiftlint:disable convenience_type
private final class BundleToken {
static let bundle: Bundle = {
#if SWIFT_PACKAGE
return Bundle.module
#else
return Bundle(for: BundleToken.self)
#endif
}()
}
// swiftlint:enable convenience_type
{% endif %}
{% else %}
// No string found
{% endif %}

View file

@ -0,0 +1,99 @@
// swiftlint:disable all
// Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen
{% if tables.count > 0 %}
{% set accessModifier %}{% if param.publicAccess %}public{% else %}internal{% endif %}{% endset %}
import Foundation
// swiftlint:disable superfluous_disable_command file_length implicit_return
// MARK: - Strings
{% macro parametersBlock types %}{% filter removeNewlines:"leading" %}
{% for type in types %}
{% if type == "String" %}
_ p{{forloop.counter}}: Any
{% else %}
_ p{{forloop.counter}}: {{type}}
{% endif %}
{{ ", " if not forloop.last }}
{% endfor %}
{% endfilter %}{% endmacro %}
{% macro argumentsBlock types %}{% filter removeNewlines:"leading" %}
{% for type in types %}
{% if type == "String" %}
String(describing: p{{forloop.counter}})
{% elif type == "UnsafeRawPointer" %}
Int(bitPattern: p{{forloop.counter}})
{% else %}
p{{forloop.counter}}
{% endif %}
{{ ", " if not forloop.last }}
{% endfor %}
{% endfilter %}{% endmacro %}
{% macro recursiveBlock table item %}
{% for string in item.strings %}
{% if not param.noComments %}
{% for line in string.translation|split:"\n" %}
/// {{line}}
{% endfor %}
{% endif %}
{% if string.types %}
{{accessModifier}} static func {{string.key|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}}({% call parametersBlock string.types %}) -> String {
return {{enumName}}.tr("{{table}}", "{{string.key}}", {% call argumentsBlock string.types %})
}
{% elif param.lookupFunction %}
{# custom localization function is mostly used for in-app lang selection, so we want the loc to be recomputed at each call for those (hence the computed var) #}
{{accessModifier}} static var {{string.key|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}}: String { return {{enumName}}.tr("{{table}}", "{{string.key}}") }
{% else %}
{{accessModifier}} static let {{string.key|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}} = {{enumName}}.tr("{{table}}", "{{string.key}}")
{% endif %}
{% endfor %}
{% for child in item.children %}
{% call recursiveBlock table child %}
{% endfor %}
{% endmacro %}
// swiftlint:disable function_parameter_count identifier_name line_length type_body_length
{% set enumName %}{{param.enumName|default:"L10n"}}{% endset %}
{{accessModifier}} enum {{enumName}} {
{% if tables.count > 1 or param.forceFileNameEnum %}
{% for table in tables %}
{{accessModifier}} enum {{table.name|swiftIdentifier:"pretty"|escapeReservedKeywords}} {
{% filter indent:2 %}{% call recursiveBlock table.name table.levels %}{% endfilter %}
}
{% endfor %}
{% else %}
{% call recursiveBlock tables.first.name tables.first.levels %}
{% endif %}
}
// swiftlint:enable function_parameter_count identifier_name line_length type_body_length
// MARK: - Implementation Details
extension {{enumName}} {
private static func tr(_ table: String, _ key: String, _ args: CVarArg...) -> String {
{% if param.lookupFunction %}
let format = {{ param.lookupFunction }}(key, table)
{% else %}
let format = {{param.bundle|default:"BundleToken.bundle"}}.localizedString(forKey: key, value: nil, table: table)
{% endif %}
return String(format: format, locale: Locale.current, arguments: args)
}
}
{% if not param.bundle and not param.lookupFunction %}
// swiftlint:disable convenience_type
private final class BundleToken {
static let bundle: Bundle = {
#if SWIFT_PACKAGE
return Bundle.module
#else
return Bundle(for: BundleToken.self)
#endif
}()
}
// swiftlint:enable convenience_type
{% endif %}
{% else %}
// No string found
{% endif %}

View file

@ -0,0 +1,68 @@
// Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen
{% if tables.count > 0 %}
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
{% macro parametersBlock types %}{% filter removeNewlines:"leading" %}
{% for type in types %}
({% call paramTranslate type %})p{{ forloop.counter }}{{ " :" if not forloop.last }}
{% endfor %}
{% endfilter %}{% endmacro %}
{% macro argumentsBlock types %}{% filter removeNewlines:"leading" %}
{% for type in types %}
p{{forloop.counter}}{{ ", " if not forloop.last }}
{% endfor %}
{% endfilter %}{% endmacro %}
{% macro paramTranslate swiftType %}
{% if swiftType == "Any" %}
id
{% elif swiftType == "CChar" %}
char
{% elif swiftType == "Float" %}
float
{% elif swiftType == "Int" %}
NSInteger
{% elif swiftType == "String" %}
id
{% elif swiftType == "UnsafePointer<CChar>" %}
char*
{% elif swiftType == "UnsafeRawPointer" %}
void*
{% else %}
objc-h.stencil is missing '{{swiftType}}'
{% endif %}
{% endmacro %}
{% macro emitOneMethod table item %}
{% for string in item.strings %}
{% if not param.noComments %}
{% for line in string.translation|split:"\n" %}
/// {{line}}
{% endfor %}
{% endif %}
{% if string.types %}
{% if string.types.count == 1 %}
+ (NSString*){{string.key|swiftIdentifier:"pretty"|lowerFirstWord}}WithValue:{% call parametersBlock string.types %};
{% else %}
+ (NSString*){{string.key|swiftIdentifier:"pretty"|lowerFirstWord}}WithValues:{% call parametersBlock string.types %};
{% endif %}
{% else %}
+ (NSString*){{string.key|swiftIdentifier:"pretty"|lowerFirstWord}};
{% endif %}
{% endfor %}
{% for child in item.children %}
{% call emitOneMethod table child %}
{% endfor %}
{% endmacro %}
{% for table in tables %}
@interface {{ table.name }} : NSObject
{% call emitOneMethod table.name table.levels %}
@end
{% endfor %}
NS_ASSUME_NONNULL_END
{% else %}
// No strings found
{% endif %}

View file

@ -0,0 +1,90 @@
// Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen
{% if tables.count > 0 %}
#import "{{ param.headerName|default:"Localizable.h" }}"
{% if not param.bundle %}
@interface BundleToken : NSObject
@end
@implementation BundleToken
@end
{% endif %}
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wformat-security"
static NSString* tr(NSString *tableName, NSString *key, ...) {
NSBundle *bundle = {{param.bundle|default:"[NSBundle bundleForClass:BundleToken.class]"}};
NSString *format = [bundle localizedStringForKey:key value:nil table:tableName];
NSLocale *locale = [NSLocale currentLocale];
va_list args;
va_start(args, key);
NSString *result = [[NSString alloc] initWithFormat:format locale:locale arguments:args];
va_end(args);
return result;
};
#pragma clang diagnostic pop
{% macro parametersBlock types %}{% filter removeNewlines:"leading" %}
{% for type in types %}
({% call paramTranslate type %})p{{ forloop.counter }}{{ " :" if not forloop.last }}
{% endfor %}
{% endfilter %}{% endmacro %}
{% macro argumentsBlock types %}{% filter removeNewlines:"leading" %}
{% for type in types %}
p{{forloop.counter}}{{ ", " if not forloop.last }}
{% endfor %}
{% endfilter %}{% endmacro %}
{% macro paramTranslate swiftType %}
{% if swiftType == "Any" %}
id
{% elif swiftType == "CChar" %}
char
{% elif swiftType == "Float" %}
float
{% elif swiftType == "Int" %}
NSInteger
{% elif swiftType == "String" %}
id
{% elif swiftType == "UnsafePointer<CChar>" %}
char*
{% elif swiftType == "UnsafeRawPointer" %}
void*
{% else %}
objc-m.stencil is missing '{{swiftType}}'
{% endif %}
{% endmacro %}
{% macro tableContents table item %}
{% for string in item.strings %}
{% if string.types %}
{% if string.types.count == 1 %}
+ (NSString*){{string.key|swiftIdentifier:"pretty"|lowerFirstWord}}WithValue:{% call parametersBlock string.types %}
{% else %}
+ (NSString*){{string.key|swiftIdentifier:"pretty"|lowerFirstWord}}WithValues:{% call parametersBlock string.types %}
{% endif %}
{
return tr(@"{{table}}", @"{{string.key}}", {% call argumentsBlock string.types %});
}
{% else %}
+ (NSString*){{string.key|swiftIdentifier:"pretty"|lowerFirstWord}} {
return tr(@"{{table}}", @"{{string.key}}");
}
{% endif %}
{% endfor %}
{% for child in item.children %}
{% call tableContents table child %}
{% endfor %}
{% endmacro %}
{% for table in tables %}
{% set tableName %}{{table.name|default:"Localized"}}{% endset %}
@implementation {{ tableName }} : NSObject
{% call tableContents table.name table.levels %}
@end
{% endfor %}
{% else %}
// No strings found
{% endif %}

View file

@ -0,0 +1,104 @@
// swiftlint:disable all
// Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen
{% if tables.count > 0 %}
{% set accessModifier %}{% if param.publicAccess %}public{% else %}internal{% endif %}{% endset %}
import Foundation
// swiftlint:disable superfluous_disable_command file_length implicit_return
// MARK: - Strings
{% macro parametersBlock types %}{% filter removeNewlines:"leading" %}
{% for type in types %}
{% if type == "String" %}
_ p{{forloop.counter}}: Any
{% else %}
_ p{{forloop.counter}}: {{type}}
{% endif %}
{{ ", " if not forloop.last }}
{% endfor %}
{% endfilter %}{% endmacro %}
{% macro argumentsBlock types %}{% filter removeNewlines:"leading" %}
{% for type in types %}
{% if type == "String" %}
String(describing: p{{forloop.counter}})
{% elif type == "UnsafeRawPointer" %}
Int(bitPattern: p{{forloop.counter}})
{% else %}
p{{forloop.counter}}
{% endif %}
{{ ", " if not forloop.last }}
{% endfor %}
{% endfilter %}{% endmacro %}
{% macro recursiveBlock table item %}
{% for string in item.strings %}
{% if not param.noComments %}
{% for line in string.translation|split:"\n" %}
/// {{line}}
{% endfor %}
{% endif %}
{% if string.types %}
{{accessModifier}} static func {{string.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}}({% call parametersBlock string.types %}) -> String {
return {{enumName}}.tr("{{table}}", "{{string.key}}", {% call argumentsBlock string.types %})
}
{% elif param.lookupFunction %}
{# custom localization function is mostly used for in-app lang selection, so we want the loc to be recomputed at each call for those (hence the computed var) #}
{{accessModifier}} static var {{string.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}}: String { return {{enumName}}.tr("{{table}}", "{{string.key}}") }
{% else %}
{{accessModifier}} static let {{string.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}} = {{enumName}}.tr("{{table}}", "{{string.key}}")
{% endif %}
{% endfor %}
{% for child in item.children %}
{{accessModifier}} enum {{child.name|swiftIdentifier:"pretty"|escapeReservedKeywords}} {
{% filter indent:2 %}{% call recursiveBlock table child %}{% endfilter %}
}
{% endfor %}
{% endmacro %}
// swiftlint:disable explicit_type_interface function_parameter_count identifier_name line_length
// swiftlint:disable nesting type_body_length type_name vertical_whitespace_opening_braces
{% set enumName %}{{param.enumName|default:"L10n"}}{% endset %}
{{accessModifier}} enum {{enumName}} {
{% if tables.count > 1 or param.forceFileNameEnum %}
{% for table in tables %}
{{accessModifier}} enum {{table.name|swiftIdentifier:"pretty"|escapeReservedKeywords}} {
{% filter indent:2 %}{% call recursiveBlock table.name table.levels %}{% endfilter %}
}
{% endfor %}
{% else %}
{% call recursiveBlock tables.first.name tables.first.levels %}
{% endif %}
}
// swiftlint:enable explicit_type_interface function_parameter_count identifier_name line_length
// swiftlint:enable nesting type_body_length type_name vertical_whitespace_opening_braces
// MARK: - Implementation Details
extension {{enumName}} {
private static func tr(_ table: String, _ key: String, _ args: CVarArg...) -> String {
{% if param.lookupFunction %}
let format = {{ param.lookupFunction }}(key, table)
{% else %}
let format = {{param.bundle|default:"BundleToken.bundle"}}.localizedString(forKey: key, value: nil, table: table)
{% endif %}
return String(format: format, locale: Locale.current, arguments: args)
}
}
{% if not param.bundle and not param.lookupFunction %}
// swiftlint:disable convenience_type
private final class BundleToken {
static let bundle: Bundle = {
#if SWIFT_PACKAGE
return Bundle.module
#else
return Bundle(for: BundleToken.self)
#endif
}()
}
// swiftlint:enable convenience_type
{% endif %}
{% else %}
// No string found
{% endif %}

View file

@ -0,0 +1,104 @@
// swiftlint:disable all
// Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen
{% if tables.count > 0 %}
{% set accessModifier %}{% if param.publicAccess %}public{% else %}internal{% endif %}{% endset %}
import Foundation
// swiftlint:disable superfluous_disable_command file_length implicit_return
// MARK: - Strings
{% macro parametersBlock types %}{% filter removeNewlines:"leading" %}
{% for type in types %}
{% if type == "String" %}
_ p{{forloop.counter}}: Any
{% else %}
_ p{{forloop.counter}}: {{type}}
{% endif %}
{{ ", " if not forloop.last }}
{% endfor %}
{% endfilter %}{% endmacro %}
{% macro argumentsBlock types %}{% filter removeNewlines:"leading" %}
{% for type in types %}
{% if type == "String" %}
String(describing: p{{forloop.counter}})
{% elif type == "UnsafeRawPointer" %}
Int(bitPattern: p{{forloop.counter}})
{% else %}
p{{forloop.counter}}
{% endif %}
{{ ", " if not forloop.last }}
{% endfor %}
{% endfilter %}{% endmacro %}
{% macro recursiveBlock table item %}
{% for string in item.strings %}
{% if not param.noComments %}
{% for line in string.translation|split:"\n" %}
/// {{line}}
{% endfor %}
{% endif %}
{% if string.types %}
{{accessModifier}} static func {{string.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}}({% call parametersBlock string.types %}) -> String {
return {{enumName}}.tr("{{table}}", "{{string.key}}", {% call argumentsBlock string.types %})
}
{% elif param.lookupFunction %}
{# custom localization function is mostly used for in-app lang selection, so we want the loc to be recomputed at each call for those (hence the computed var) #}
{{accessModifier}} static var {{string.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}}: String { return {{enumName}}.tr("{{table}}", "{{string.key}}") }
{% else %}
{{accessModifier}} static let {{string.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}} = {{enumName}}.tr("{{table}}", "{{string.key}}")
{% endif %}
{% endfor %}
{% for child in item.children %}
{{accessModifier}} enum {{child.name|swiftIdentifier:"pretty"|escapeReservedKeywords}} {
{% filter indent:2 %}{% call recursiveBlock table child %}{% endfilter %}
}
{% endfor %}
{% endmacro %}
// swiftlint:disable explicit_type_interface function_parameter_count identifier_name line_length
// swiftlint:disable nesting type_body_length type_name vertical_whitespace_opening_braces
{% set enumName %}{{param.enumName|default:"L10n"}}{% endset %}
{{accessModifier}} enum {{enumName}} {
{% if tables.count > 1 or param.forceFileNameEnum %}
{% for table in tables %}
{{accessModifier}} enum {{table.name|swiftIdentifier:"pretty"|escapeReservedKeywords}} {
{% filter indent:2 %}{% call recursiveBlock table.name table.levels %}{% endfilter %}
}
{% endfor %}
{% else %}
{% call recursiveBlock tables.first.name tables.first.levels %}
{% endif %}
}
// swiftlint:enable explicit_type_interface function_parameter_count identifier_name line_length
// swiftlint:enable nesting type_body_length type_name vertical_whitespace_opening_braces
// MARK: - Implementation Details
extension {{enumName}} {
private static func tr(_ table: String, _ key: String, _ args: CVarArg...) -> String {
{% if param.lookupFunction %}
let format = {{ param.lookupFunction }}(key, table)
{% else %}
let format = {{param.bundle|default:"BundleToken.bundle"}}.localizedString(forKey: key, value: nil, table: table)
{% endif %}
return String(format: format, locale: Locale.current, arguments: args)
}
}
{% if not param.bundle and not param.lookupFunction %}
// swiftlint:disable convenience_type
private final class BundleToken {
static let bundle: Bundle = {
#if SWIFT_PACKAGE
return Bundle.module
#else
return Bundle(for: BundleToken.self)
#endif
}()
}
// swiftlint:enable convenience_type
{% endif %}
{% else %}
// No string found
{% endif %}

View file

@ -0,0 +1,329 @@
// swiftlint:disable all
// Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen
{% if catalogs %}
{% set enumName %}{{param.enumName|default:"Asset"}}{% endset %}
{% set arResourceGroupType %}{{param.arResourceGroupTypeName|default:"ARResourceGroupAsset"}}{% endset %}
{% set colorType %}{{param.colorTypeName|default:"ColorAsset"}}{% endset %}
{% set dataType %}{{param.dataTypeName|default:"DataAsset"}}{% endset %}
{% set imageType %}{{param.imageTypeName|default:"ImageAsset"}}{% endset %}
{% set symbolType %}{{param.symbolTypeName|default:"SymbolAsset"}}{% endset %}
{% set forceNamespaces %}{{param.forceProvidesNamespaces|default:"false"}}{% endset %}
{% set accessModifier %}{% if param.publicAccess %}public{% else %}internal{% endif %}{% endset %}
#if os(macOS)
import AppKit
#elseif os(iOS)
{% if resourceCount.arresourcegroup > 0 %}
import ARKit
{% endif %}
import UIKit
#elseif os(tvOS) || os(watchOS)
import UIKit
#endif
// Deprecated typealiases
{% if resourceCount.color > 0 %}
@available(*, deprecated, renamed: "{{colorType}}.Color", message: "This typealias will be removed in SwiftGen 7.0")
{{accessModifier}} typealias {{param.colorAliasName|default:"AssetColorTypeAlias"}} = {{colorType}}.Color
{% endif %}
{% if resourceCount.image > 0 %}
@available(*, deprecated, renamed: "{{imageType}}.Image", message: "This typealias will be removed in SwiftGen 7.0")
{{accessModifier}} typealias {{param.imageAliasName|default:"AssetImageTypeAlias"}} = {{imageType}}.Image
{% endif %}
// swiftlint:disable superfluous_disable_command file_length implicit_return
// MARK: - Asset Catalogs
{% macro enumBlock assets %}
{% call casesBlock assets %}
{% if param.allValues %}
// swiftlint:disable trailing_comma
{% if resourceCount.arresourcegroup > 0 %}
{{accessModifier}} static let allResourceGroups: [{{arResourceGroupType}}] = [
{% filter indent:2 %}{% call allValuesBlock assets "arresourcegroup" "" %}{% endfilter %}
]
{% endif %}
{% if resourceCount.color > 0 %}
{{accessModifier}} static let allColors: [{{colorType}}] = [
{% filter indent:2 %}{% call allValuesBlock assets "color" "" %}{% endfilter %}
]
{% endif %}
{% if resourceCount.data > 0 %}
{{accessModifier}} static let allDataAssets: [{{dataType}}] = [
{% filter indent:2 %}{% call allValuesBlock assets "data" "" %}{% endfilter %}
]
{% endif %}
{% if resourceCount.image > 0 %}
{{accessModifier}} static let allImages: [{{imageType}}] = [
{% filter indent:2 %}{% call allValuesBlock assets "image" "" %}{% endfilter %}
]
{% endif %}
{% if resourceCount.symbol > 0 %}
{{accessModifier}} static let allSymbols: [{{symbolType}}] = [
{% filter indent:2 %}{% call allValuesBlock assets "symbol" "" %}{% endfilter %}
]
{% endif %}
// swiftlint:enable trailing_comma
{% endif %}
{% endmacro %}
{% macro casesBlock assets %}
{% for asset in assets %}
{% if asset.type == "arresourcegroup" %}
{{accessModifier}} static let {{asset.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}} = {{arResourceGroupType}}(name: "{{asset.value}}")
{% elif asset.type == "color" %}
{{accessModifier}} static let {{asset.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}} = {{colorType}}(name: "{{asset.value}}")
{% elif asset.type == "data" %}
{{accessModifier}} static let {{asset.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}} = {{dataType}}(name: "{{asset.value}}")
{% elif asset.type == "image" %}
{{accessModifier}} static let {{asset.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}} = {{imageType}}(name: "{{asset.value}}")
{% elif asset.type == "symbol" %}
{{accessModifier}} static let {{asset.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}} = {{symbolType}}(name: "{{asset.value}}")
{% elif asset.items and ( forceNamespaces == "true" or asset.isNamespaced == "true" ) %}
{{accessModifier}} enum {{asset.name|swiftIdentifier:"pretty"|escapeReservedKeywords}} {
{% filter indent:2 %}{% call casesBlock asset.items %}{% endfilter %}
}
{% elif asset.items %}
{% call casesBlock asset.items %}
{% endif %}
{% endfor %}
{% endmacro %}
{% macro allValuesBlock assets filter prefix %}
{% for asset in assets %}
{% if asset.type == filter %}
{{prefix}}{{asset.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}},
{% elif asset.items and ( forceNamespaces == "true" or asset.isNamespaced == "true" ) %}
{% set prefix2 %}{{prefix}}{{asset.name|swiftIdentifier:"pretty"|escapeReservedKeywords}}.{% endset %}
{% call allValuesBlock asset.items filter prefix2 %}
{% elif asset.items %}
{% call allValuesBlock asset.items filter prefix %}
{% endif %}
{% endfor %}
{% endmacro %}
// swiftlint:disable identifier_name line_length nesting type_body_length type_name
{{accessModifier}} enum {{enumName}} {
{% if catalogs.count > 1 or param.forceFileNameEnum %}
{% for catalog in catalogs %}
{{accessModifier}} enum {{catalog.name|swiftIdentifier:"pretty"|escapeReservedKeywords}} {
{% filter indent:2 %}{% call enumBlock catalog.assets %}{% endfilter %}
}
{% endfor %}
{% else %}
{% call enumBlock catalogs.first.assets %}
{% endif %}
}
// swiftlint:enable identifier_name line_length nesting type_body_length type_name
// MARK: - Implementation Details
{% if resourceCount.arresourcegroup > 0 %}
{{accessModifier}} struct {{arResourceGroupType}} {
{{accessModifier}} fileprivate(set) var name: String
#if os(iOS)
@available(iOS 11.3, *)
{{accessModifier}} var referenceImages: Set<ARReferenceImage> {
return ARReferenceImage.referenceImages(in: self)
}
@available(iOS 12.0, *)
{{accessModifier}} var referenceObjects: Set<ARReferenceObject> {
return ARReferenceObject.referenceObjects(in: self)
}
#endif
}
#if os(iOS)
@available(iOS 11.3, *)
{{accessModifier}} extension ARReferenceImage {
static func referenceImages(in asset: {{arResourceGroupType}}) -> Set<ARReferenceImage> {
let bundle = {{param.bundle|default:"BundleToken.bundle"}}
return referenceImages(inGroupNamed: asset.name, bundle: bundle) ?? Set()
}
}
@available(iOS 12.0, *)
{{accessModifier}} extension ARReferenceObject {
static func referenceObjects(in asset: {{arResourceGroupType}}) -> Set<ARReferenceObject> {
let bundle = {{param.bundle|default:"BundleToken.bundle"}}
return referenceObjects(inGroupNamed: asset.name, bundle: bundle) ?? Set()
}
}
#endif
{% endif %}
{% if resourceCount.color > 0 %}
{{accessModifier}} final class {{colorType}} {
{{accessModifier}} fileprivate(set) var name: String
#if os(macOS)
{{accessModifier}} typealias Color = NSColor
#elseif os(iOS) || os(tvOS) || os(watchOS)
{{accessModifier}} typealias Color = UIColor
#endif
@available(iOS 11.0, tvOS 11.0, watchOS 4.0, macOS 10.13, *)
{{accessModifier}} private(set) lazy var color: Color = Color(asset: self)
#if os(iOS) || os(tvOS)
@available(iOS 11.0, tvOS 11.0, *)
{{accessModifier}} func color(compatibleWith traitCollection: UITraitCollection) -> Color {
let bundle = {{param.bundle|default:"BundleToken.bundle"}}
guard let color = Color(named: name, in: bundle, compatibleWith: traitCollection) else {
fatalError("Unable to load color asset named \(name).")
}
return color
}
#endif
fileprivate init(name: String) {
self.name = name
}
}
{{accessModifier}} extension {{colorType}}.Color {
@available(iOS 11.0, tvOS 11.0, watchOS 4.0, macOS 10.13, *)
convenience init!(asset: {{colorType}}) {
let bundle = {{param.bundle|default:"BundleToken.bundle"}}
#if os(iOS) || os(tvOS)
self.init(named: asset.name, in: bundle, compatibleWith: nil)
#elseif os(macOS)
self.init(named: NSColor.Name(asset.name), bundle: bundle)
#elseif os(watchOS)
self.init(named: asset.name)
#endif
}
}
{% endif %}
{% if resourceCount.data > 0 %}
{{accessModifier}} struct {{dataType}} {
{{accessModifier}} fileprivate(set) var name: String
@available(iOS 9.0, tvOS 9.0, watchOS 6.0, macOS 10.11, *)
{{accessModifier}} var data: NSDataAsset {
return NSDataAsset(asset: self)
}
}
@available(iOS 9.0, tvOS 9.0, watchOS 6.0, macOS 10.11, *)
{{accessModifier}} extension NSDataAsset {
convenience init!(asset: {{dataType}}) {
let bundle = {{param.bundle|default:"BundleToken.bundle"}}
#if os(iOS) || os(tvOS) || os(watchOS)
self.init(name: asset.name, bundle: bundle)
#elseif os(macOS)
self.init(name: NSDataAsset.Name(asset.name), bundle: bundle)
#endif
}
}
{% endif %}
{% if resourceCount.image > 0 %}
{{accessModifier}} struct {{imageType}} {
{{accessModifier}} fileprivate(set) var name: String
#if os(macOS)
{{accessModifier}} typealias Image = NSImage
#elseif os(iOS) || os(tvOS) || os(watchOS)
{{accessModifier}} typealias Image = UIImage
#endif
@available(iOS 8.0, tvOS 9.0, watchOS 2.0, macOS 10.7, *)
{{accessModifier}} var image: Image {
let bundle = {{param.bundle|default:"BundleToken.bundle"}}
#if os(iOS) || os(tvOS)
let image = Image(named: name, in: bundle, compatibleWith: nil)
#elseif os(macOS)
let name = NSImage.Name(self.name)
let image = (bundle == .main) ? NSImage(named: name) : bundle.image(forResource: name)
#elseif os(watchOS)
let image = Image(named: name)
#endif
guard let result = image else {
fatalError("Unable to load image asset named \(name).")
}
return result
}
#if os(iOS) || os(tvOS)
@available(iOS 8.0, tvOS 9.0, *)
{{accessModifier}} func image(compatibleWith traitCollection: UITraitCollection) -> Image {
let bundle = {{param.bundle|default:"BundleToken.bundle"}}
guard let result = Image(named: name, in: bundle, compatibleWith: traitCollection) else {
fatalError("Unable to load image asset named \(name).")
}
return result
}
#endif
}
{{accessModifier}} extension {{imageType}}.Image {
@available(iOS 8.0, tvOS 9.0, watchOS 2.0, *)
@available(macOS, deprecated,
message: "This initializer is unsafe on macOS, please use the {{imageType}}.image property")
convenience init!(asset: {{imageType}}) {
#if os(iOS) || os(tvOS)
let bundle = {{param.bundle|default:"BundleToken.bundle"}}
self.init(named: asset.name, in: bundle, compatibleWith: nil)
#elseif os(macOS)
self.init(named: NSImage.Name(asset.name))
#elseif os(watchOS)
self.init(named: asset.name)
#endif
}
}
{% endif %}
{% if resourceCount.symbol > 0 %}
{{accessModifier}} struct {{symbolType}} {
{{accessModifier}} fileprivate(set) var name: String
#if os(iOS) || os(tvOS) || os(watchOS)
@available(iOS 13.0, tvOS 13.0, watchOS 6.0, *)
{{accessModifier}} typealias Configuration = UIImage.SymbolConfiguration
{{accessModifier}} typealias Image = UIImage
@available(iOS 12.0, tvOS 12.0, watchOS 5.0, *)
{{accessModifier}} var image: Image {
let bundle = {{param.bundle|default:"BundleToken.bundle"}}
#if os(iOS) || os(tvOS)
let image = Image(named: name, in: bundle, compatibleWith: nil)
#elseif os(watchOS)
let image = Image(named: name)
#endif
guard let result = image else {
fatalError("Unable to load symbol asset named \(name).")
}
return result
}
@available(iOS 13.0, tvOS 13.0, watchOS 6.0, *)
{{accessModifier}} func image(with configuration: Configuration) -> Image {
let bundle = {{param.bundle|default:"BundleToken.bundle"}}
guard let result = Image(named: name, in: bundle, with: configuration) else {
fatalError("Unable to load symbol asset named \(name).")
}
return result
}
#endif
}
{% endif %}
{% if not param.bundle %}
// swiftlint:disable convenience_type
private final class BundleToken {
static let bundle: Bundle = {
#if SWIFT_PACKAGE
return Bundle.module
#else
return Bundle(for: BundleToken.self)
#endif
}()
}
// swiftlint:enable convenience_type
{% endif %}
{% else %}
// No assets found
{% endif %}

View file

@ -0,0 +1,337 @@
// swiftlint:disable all
// Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen
{% if catalogs %}
{% set enumName %}{{param.enumName|default:"Asset"}}{% endset %}
{% set arResourceGroupType %}{{param.arResourceGroupTypeName|default:"ARResourceGroupAsset"}}{% endset %}
{% set colorType %}{{param.colorTypeName|default:"ColorAsset"}}{% endset %}
{% set dataType %}{{param.dataTypeName|default:"DataAsset"}}{% endset %}
{% set imageType %}{{param.imageTypeName|default:"ImageAsset"}}{% endset %}
{% set symbolType %}{{param.symbolTypeName|default:"SymbolAsset"}}{% endset %}
{% set forceNamespaces %}{{param.forceProvidesNamespaces|default:"false"}}{% endset %}
{% set accessModifier %}{% if param.publicAccess %}public{% else %}internal{% endif %}{% endset %}
#if os(macOS)
import AppKit
#elseif os(iOS)
{% if resourceCount.arresourcegroup > 0 %}
import ARKit
{% endif %}
import UIKit
#elseif os(tvOS) || os(watchOS)
import UIKit
#endif
// Deprecated typealiases
{% if resourceCount.color > 0 %}
@available(*, deprecated, renamed: "{{colorType}}.Color", message: "This typealias will be removed in SwiftGen 7.0")
{{accessModifier}} typealias {{param.colorAliasName|default:"AssetColorTypeAlias"}} = {{colorType}}.Color
{% endif %}
{% if resourceCount.image > 0 %}
@available(*, deprecated, renamed: "{{imageType}}.Image", message: "This typealias will be removed in SwiftGen 7.0")
{{accessModifier}} typealias {{param.imageAliasName|default:"AssetImageTypeAlias"}} = {{imageType}}.Image
{% endif %}
// swiftlint:disable superfluous_disable_command file_length implicit_return
// MARK: - Asset Catalogs
{% macro enumBlock assets %}
{% call casesBlock assets %}
{% if param.allValues %}
// swiftlint:disable trailing_comma
{% if resourceCount.arresourcegroup > 0 %}
{{accessModifier}} static let allResourceGroups: [{{arResourceGroupType}}] = [
{% filter indent:2 %}{% call allValuesBlock assets "arresourcegroup" "" %}{% endfilter %}
]
{% endif %}
{% if resourceCount.color > 0 %}
{{accessModifier}} static let allColors: [{{colorType}}] = [
{% filter indent:2 %}{% call allValuesBlock assets "color" "" %}{% endfilter %}
]
{% endif %}
{% if resourceCount.data > 0 %}
{{accessModifier}} static let allDataAssets: [{{dataType}}] = [
{% filter indent:2 %}{% call allValuesBlock assets "data" "" %}{% endfilter %}
]
{% endif %}
{% if resourceCount.image > 0 %}
{{accessModifier}} static let allImages: [{{imageType}}] = [
{% filter indent:2 %}{% call allValuesBlock assets "image" "" %}{% endfilter %}
]
{% endif %}
{% if resourceCount.symbol > 0 %}
{{accessModifier}} static let allSymbols: [{{symbolType}}] = [
{% filter indent:2 %}{% call allValuesBlock assets "symbol" "" %}{% endfilter %}
]
{% endif %}
// swiftlint:enable trailing_comma
{% endif %}
{% endmacro %}
{% macro casesBlock assets %}
{% for asset in assets %}
{% if asset.type == "arresourcegroup" %}
{{accessModifier}} static let {{asset.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}} = {{arResourceGroupType}}(name: "{{asset.value}}")
{% elif asset.type == "color" %}
{{accessModifier}} static let {{asset.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}} = {{colorType}}(name: "{{asset.value}}")
{% elif asset.type == "data" %}
{{accessModifier}} static let {{asset.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}} = {{dataType}}(name: "{{asset.value}}")
{% elif asset.type == "image" %}
{{accessModifier}} static let {{asset.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}} = {{imageType}}(name: "{{asset.value}}")
{% elif asset.type == "symbol" %}
{{accessModifier}} static let {{asset.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}} = {{symbolType}}(name: "{{asset.value}}")
{% elif asset.items and ( forceNamespaces == "true" or asset.isNamespaced == "true" ) %}
{{accessModifier}} enum {{asset.name|swiftIdentifier:"pretty"|escapeReservedKeywords}} {
{% filter indent:2 %}{% call casesBlock asset.items %}{% endfilter %}
}
{% elif asset.items %}
{% call casesBlock asset.items %}
{% endif %}
{% endfor %}
{% endmacro %}
{% macro allValuesBlock assets filter prefix %}
{% for asset in assets %}
{% if asset.type == filter %}
{{prefix}}{{asset.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}},
{% elif asset.items and ( forceNamespaces == "true" or asset.isNamespaced == "true" ) %}
{% set prefix2 %}{{prefix}}{{asset.name|swiftIdentifier:"pretty"|escapeReservedKeywords}}.{% endset %}
{% call allValuesBlock asset.items filter prefix2 %}
{% elif asset.items %}
{% call allValuesBlock asset.items filter prefix %}
{% endif %}
{% endfor %}
{% endmacro %}
// swiftlint:disable identifier_name line_length nesting type_body_length type_name
{{accessModifier}} enum {{enumName}} {
{% if catalogs.count > 1 or param.forceFileNameEnum %}
{% for catalog in catalogs %}
{{accessModifier}} enum {{catalog.name|swiftIdentifier:"pretty"|escapeReservedKeywords}} {
{% filter indent:2 %}{% call enumBlock catalog.assets %}{% endfilter %}
}
{% endfor %}
{% else %}
{% call enumBlock catalogs.first.assets %}
{% endif %}
}
// swiftlint:enable identifier_name line_length nesting type_body_length type_name
// MARK: - Implementation Details
{% if resourceCount.arresourcegroup > 0 %}
{{accessModifier}} struct {{arResourceGroupType}} {
{{accessModifier}} fileprivate(set) var name: String
#if os(iOS)
@available(iOS 11.3, *)
{{accessModifier}} var referenceImages: Set<ARReferenceImage> {
return ARReferenceImage.referenceImages(in: self)
}
@available(iOS 12.0, *)
{{accessModifier}} var referenceObjects: Set<ARReferenceObject> {
return ARReferenceObject.referenceObjects(in: self)
}
#endif
}
#if os(iOS)
@available(iOS 11.3, *)
{{accessModifier}} extension ARReferenceImage {
static func referenceImages(in asset: {{arResourceGroupType}}) -> Set<ARReferenceImage> {
let bundle = {{param.bundle|default:"BundleToken.bundle"}}
return referenceImages(inGroupNamed: asset.name, bundle: bundle) ?? Set()
}
}
@available(iOS 12.0, *)
{{accessModifier}} extension ARReferenceObject {
static func referenceObjects(in asset: {{arResourceGroupType}}) -> Set<ARReferenceObject> {
let bundle = {{param.bundle|default:"BundleToken.bundle"}}
return referenceObjects(inGroupNamed: asset.name, bundle: bundle) ?? Set()
}
}
#endif
{% endif %}
{% if resourceCount.color > 0 %}
{{accessModifier}} final class {{colorType}} {
{{accessModifier}} fileprivate(set) var name: String
#if os(macOS)
{{accessModifier}} typealias Color = NSColor
#elseif os(iOS) || os(tvOS) || os(watchOS)
{{accessModifier}} typealias Color = UIColor
#endif
@available(iOS 11.0, tvOS 11.0, watchOS 4.0, macOS 10.13, *)
{{accessModifier}} private(set) lazy var color: Color = {
guard let color = Color(asset: self) else {
fatalError("Unable to load color asset named \(name).")
}
return color
}()
#if os(iOS) || os(tvOS)
@available(iOS 11.0, tvOS 11.0, *)
{{accessModifier}} func color(compatibleWith traitCollection: UITraitCollection) -> Color {
let bundle = {{param.bundle|default:"BundleToken.bundle"}}
guard let color = Color(named: name, in: bundle, compatibleWith: traitCollection) else {
fatalError("Unable to load color asset named \(name).")
}
return color
}
#endif
fileprivate init(name: String) {
self.name = name
}
}
{{accessModifier}} extension {{colorType}}.Color {
@available(iOS 11.0, tvOS 11.0, watchOS 4.0, macOS 10.13, *)
convenience init?(asset: {{colorType}}) {
let bundle = {{param.bundle|default:"BundleToken.bundle"}}
#if os(iOS) || os(tvOS)
self.init(named: asset.name, in: bundle, compatibleWith: nil)
#elseif os(macOS)
self.init(named: NSColor.Name(asset.name), bundle: bundle)
#elseif os(watchOS)
self.init(named: asset.name)
#endif
}
}
{% endif %}
{% if resourceCount.data > 0 %}
{{accessModifier}} struct {{dataType}} {
{{accessModifier}} fileprivate(set) var name: String
@available(iOS 9.0, tvOS 9.0, watchOS 6.0, macOS 10.11, *)
{{accessModifier}} var data: NSDataAsset {
guard let data = NSDataAsset(asset: self) else {
fatalError("Unable to load data asset named \(name).")
}
return data
}
}
@available(iOS 9.0, tvOS 9.0, watchOS 6.0, macOS 10.11, *)
{{accessModifier}} extension NSDataAsset {
convenience init?(asset: {{dataType}}) {
let bundle = {{param.bundle|default:"BundleToken.bundle"}}
#if os(iOS) || os(tvOS) || os(watchOS)
self.init(name: asset.name, bundle: bundle)
#elseif os(macOS)
self.init(name: NSDataAsset.Name(asset.name), bundle: bundle)
#endif
}
}
{% endif %}
{% if resourceCount.image > 0 %}
{{accessModifier}} struct {{imageType}} {
{{accessModifier}} fileprivate(set) var name: String
#if os(macOS)
{{accessModifier}} typealias Image = NSImage
#elseif os(iOS) || os(tvOS) || os(watchOS)
{{accessModifier}} typealias Image = UIImage
#endif
@available(iOS 8.0, tvOS 9.0, watchOS 2.0, macOS 10.7, *)
{{accessModifier}} var image: Image {
let bundle = {{param.bundle|default:"BundleToken.bundle"}}
#if os(iOS) || os(tvOS)
let image = Image(named: name, in: bundle, compatibleWith: nil)
#elseif os(macOS)
let name = NSImage.Name(self.name)
let image = (bundle == .main) ? NSImage(named: name) : bundle.image(forResource: name)
#elseif os(watchOS)
let image = Image(named: name)
#endif
guard let result = image else {
fatalError("Unable to load image asset named \(name).")
}
return result
}
#if os(iOS) || os(tvOS)
@available(iOS 8.0, tvOS 9.0, *)
{{accessModifier}} func image(compatibleWith traitCollection: UITraitCollection) -> Image {
let bundle = {{param.bundle|default:"BundleToken.bundle"}}
guard let result = Image(named: name, in: bundle, compatibleWith: traitCollection) else {
fatalError("Unable to load image asset named \(name).")
}
return result
}
#endif
}
{{accessModifier}} extension {{imageType}}.Image {
@available(iOS 8.0, tvOS 9.0, watchOS 2.0, *)
@available(macOS, deprecated,
message: "This initializer is unsafe on macOS, please use the {{imageType}}.image property")
convenience init?(asset: {{imageType}}) {
#if os(iOS) || os(tvOS)
let bundle = {{param.bundle|default:"BundleToken.bundle"}}
self.init(named: asset.name, in: bundle, compatibleWith: nil)
#elseif os(macOS)
self.init(named: NSImage.Name(asset.name))
#elseif os(watchOS)
self.init(named: asset.name)
#endif
}
}
{% endif %}
{% if resourceCount.symbol > 0 %}
{{accessModifier}} struct {{symbolType}} {
{{accessModifier}} fileprivate(set) var name: String
#if os(iOS) || os(tvOS) || os(watchOS)
@available(iOS 13.0, tvOS 13.0, watchOS 6.0, *)
{{accessModifier}} typealias Configuration = UIImage.SymbolConfiguration
{{accessModifier}} typealias Image = UIImage
@available(iOS 12.0, tvOS 12.0, watchOS 5.0, *)
{{accessModifier}} var image: Image {
let bundle = {{param.bundle|default:"BundleToken.bundle"}}
#if os(iOS) || os(tvOS)
let image = Image(named: name, in: bundle, compatibleWith: nil)
#elseif os(watchOS)
let image = Image(named: name)
#endif
guard let result = image else {
fatalError("Unable to load symbol asset named \(name).")
}
return result
}
@available(iOS 13.0, tvOS 13.0, watchOS 6.0, *)
{{accessModifier}} func image(with configuration: Configuration) -> Image {
let bundle = {{param.bundle|default:"BundleToken.bundle"}}
guard let result = Image(named: name, in: bundle, with: configuration) else {
fatalError("Unable to load symbol asset named \(name).")
}
return result
}
#endif
}
{% endif %}
{% if not param.bundle %}
// swiftlint:disable convenience_type
private final class BundleToken {
static let bundle: Bundle = {
#if SWIFT_PACKAGE
return Bundle.module
#else
return Bundle(for: BundleToken.self)
#endif
}()
}
// swiftlint:enable convenience_type
{% endif %}
{% else %}
// No assets found
{% endif %}

View file

@ -0,0 +1,92 @@
// swiftlint:disable all
// Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen
{% if files %}
{% set accessModifier %}{% if param.publicAccess %}public{% else %}internal{% endif %}{% endset %}
{% set documentPrefix %}{{param.documentName|default:"Document"}}{% endset %}
import Foundation
// swiftlint:disable superfluous_disable_command
// swiftlint:disable file_length
// MARK: - YAML Files
{% macro fileBlock file %}
{% if file.documents.count > 1 %}
{% for document in file.documents %}
{% set documentName %}{{documentPrefix}}{{forloop.counter}}{% endset %}
{{accessModifier}} enum {{documentName|swiftIdentifier:"pretty"|escapeReservedKeywords}} {
{% filter indent:2 %}{% call documentBlock file document %}{% endfilter %}
}
{% endfor %}
{% else %}
{% call documentBlock file file.documents.first %}
{% endif %}
{% endmacro %}
{% macro documentBlock file document %}
{% set rootType %}{% call typeBlock document.metadata %}{% endset %}
{% if document.metadata.type == "Array" %}
{{accessModifier}} static let items: {{rootType}} = {% call valueBlock document.data document.metadata %}
{% elif document.metadata.type == "Dictionary" %}
{% for key,value in document.metadata.properties %}
{{accessModifier}} {% call propertyBlock key value document.data %}
{% endfor %}
{% else %}
{{accessModifier}} static let value: {{rootType}} = {% call valueBlock document.data document.metadata %}
{% endif %}
{% endmacro %}
{% macro typeBlock metadata %}{% filter removeNewlines:"leading" %}
{% if metadata.type == "Array" %}
[{% call typeBlock metadata.element %}]
{% elif metadata.type == "Dictionary" %}
[String: Any]
{% elif metadata.type == "Optional" %}
Any?
{% else %}
{{metadata.type}}
{% endif %}
{% endfilter %}{% endmacro %}
{% macro propertyBlock key metadata data %}{% filter removeNewlines:"leading" %}
{% set propertyName %}{{key|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}}{% endset %}
{% set propertyType %}{% call typeBlock metadata %}{% endset %}
static let {{propertyName}}: {{propertyType}} = {% call valueBlock data[key] metadata %}
{% endfilter %}{% endmacro %}
{% macro valueBlock value metadata %}{% filter removeNewlines:"leading" %}
{% if metadata.type == "String" %}
"{{ value }}"
{% elif metadata.type == "Optional" %}
nil
{% elif metadata.type == "Array" and value %}
[{% for value in value %}
{% call valueBlock value metadata.element.items[forloop.counter0]|default:metadata.element %}
{{ ", " if not forloop.last }}
{% endfor %}]
{% elif metadata.type == "Dictionary" %}
[{% for key,value in value %}
"{{key}}": {% call valueBlock value metadata.properties[key] %}
{{ ", " if not forloop.last }}
{% empty %}
:
{% endfor %}]
{% elif metadata.type == "Bool" %}
{% if value %}true{% else %}false{% endif %}
{% else %}
{{ value }}
{% endif %}
{% endfilter %}{% endmacro %}
// swiftlint:disable identifier_name line_length number_separator type_body_length
{{accessModifier}} enum {{param.enumName|default:"YAMLFiles"}} {
{% if files.count > 1 or param.forceFileNameEnum %}
{% for file in files %}
{{accessModifier}} enum {{file.name|swiftIdentifier:"pretty"|escapeReservedKeywords}} {
{% filter indent:2 %}{% call fileBlock file %}{% endfilter %}
}
{% endfor %}
{% else %}
{% call fileBlock files.first %}
{% endif %}
}
// swiftlint:enable identifier_name line_length number_separator type_body_length
{% else %}
// No files found
{% endif %}

View file

@ -0,0 +1,92 @@
// swiftlint:disable all
// Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen
{% if files %}
{% set accessModifier %}{% if param.publicAccess %}public{% else %}internal{% endif %}{% endset %}
{% set documentPrefix %}{{param.documentName|default:"Document"}}{% endset %}
import Foundation
// swiftlint:disable superfluous_disable_command
// swiftlint:disable file_length
// MARK: - YAML Files
{% macro fileBlock file %}
{% if file.documents.count > 1 %}
{% for document in file.documents %}
{% set documentName %}{{documentPrefix}}{{forloop.counter}}{% endset %}
{{accessModifier}} enum {{documentName|swiftIdentifier:"pretty"|escapeReservedKeywords}} {
{% filter indent:2 %}{% call documentBlock file document %}{% endfilter %}
}
{% endfor %}
{% else %}
{% call documentBlock file file.documents.first %}
{% endif %}
{% endmacro %}
{% macro documentBlock file document %}
{% set rootType %}{% call typeBlock document.metadata %}{% endset %}
{% if document.metadata.type == "Array" %}
{{accessModifier}} static let items: {{rootType}} = {% call valueBlock document.data document.metadata %}
{% elif document.metadata.type == "Dictionary" %}
{% for key,value in document.metadata.properties %}
{{accessModifier}} {% call propertyBlock key value document.data %}
{% endfor %}
{% else %}
{{accessModifier}} static let value: {{rootType}} = {% call valueBlock document.data document.metadata %}
{% endif %}
{% endmacro %}
{% macro typeBlock metadata %}{% filter removeNewlines:"leading" %}
{% if metadata.type == "Array" %}
[{% call typeBlock metadata.element %}]
{% elif metadata.type == "Dictionary" %}
[String: Any]
{% elif metadata.type == "Optional" %}
Any?
{% else %}
{{metadata.type}}
{% endif %}
{% endfilter %}{% endmacro %}
{% macro propertyBlock key metadata data %}{% filter removeNewlines:"leading" %}
{% set propertyName %}{{key|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}}{% endset %}
{% set propertyType %}{% call typeBlock metadata %}{% endset %}
static let {{propertyName}}: {{propertyType}} = {% call valueBlock data[key] metadata %}
{% endfilter %}{% endmacro %}
{% macro valueBlock value metadata %}{% filter removeNewlines:"leading" %}
{% if metadata.type == "String" %}
"{{ value }}"
{% elif metadata.type == "Optional" %}
nil
{% elif metadata.type == "Array" and value %}
[{% for value in value %}
{% call valueBlock value metadata.element.items[forloop.counter0]|default:metadata.element %}
{{ ", " if not forloop.last }}
{% endfor %}]
{% elif metadata.type == "Dictionary" %}
[{% for key,value in value %}
"{{key}}": {% call valueBlock value metadata.properties[key] %}
{{ ", " if not forloop.last }}
{% empty %}
:
{% endfor %}]
{% elif metadata.type == "Bool" %}
{% if value %}true{% else %}false{% endif %}
{% else %}
{{ value }}
{% endif %}
{% endfilter %}{% endmacro %}
// swiftlint:disable identifier_name line_length number_separator type_body_length
{{accessModifier}} enum {{param.enumName|default:"YAMLFiles"}} {
{% if files.count > 1 or param.forceFileNameEnum %}
{% for file in files %}
{{accessModifier}} enum {{file.name|swiftIdentifier:"pretty"|escapeReservedKeywords}} {
{% filter indent:2 %}{% call fileBlock file %}{% endfilter %}
}
{% endfor %}
{% else %}
{% call fileBlock files.first %}
{% endif %}
}
// swiftlint:enable identifier_name line_length number_separator type_body_length
{% else %}
// No files found
{% endif %}

BIN
.swiftgen/bin/swiftgen Executable file

Binary file not shown.

View file

@ -0,0 +1,29 @@
// swiftlint:disable all
// Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen
{% if families %}
import SwiftUI
{% for family in families %}
{% set identifierName %}{{family.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}}{% endset %}
{% set styleTypeName %}{{family.name|swiftIdentifier:"pretty"|escapeReservedKeywords}}Style{% endset %}
extension Font {
public static func {{identifierName}}(_ style: {{styleTypeName}}, fixedSize: CGFloat) -> Font {
return Font.custom(style.rawValue, fixedSize: fixedSize)
}
public static func {{identifierName}}(_ style: {{styleTypeName}}, size: CGFloat, relativeTo textStyle: TextStyle = .body) -> Font {
return Font.custom(style.rawValue, size: size, relativeTo: textStyle)
}
public enum {{styleTypeName}}: String {
{% for font in family.fonts %}
case {{font.style|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}} = "{{font.name}}"
{% endfor %}
}
}
{% endfor %}
{% else %}
// No fonts found
{% endif %}

View file

@ -0,0 +1,84 @@
// swiftlint:disable all
// Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen
{% if tables.count > 0 %}
{% set accessModifier %}{% if param.publicAccess %}public{% else %}internal{% endif %}{% endset %}
import Foundation
// swiftlint:disable superfluous_disable_command file_length implicit_return
// MARK: - Strings
{% macro parametersBlock types %}{% filter removeNewlines:"leading" %}
{% for type in types %}
{% if type == "String" %}
_ p{{forloop.counter}}: Any
{% else %}
_ p{{forloop.counter}}: {{type}}
{% endif %}
{{ ", " if not forloop.last }}
{% endfor %}
{% endfilter %}{% endmacro %}
{% macro argumentsBlock types %}{% filter removeNewlines:"leading" %}
{% for type in types %}
{% if type == "String" %}
String(describing: p{{forloop.counter}})
{% elif type == "UnsafeRawPointer" %}
Int(bitPattern: p{{forloop.counter}})
{% else %}
p{{forloop.counter}}
{% endif %}
{{ ", " if not forloop.last }}
{% endfor %}
{% endfilter %}{% endmacro %}
{% macro recursiveBlock table item %}
{% for string in item.strings %}
{% if not param.noComments %}
{% for line in string.translation|split:"\n" %}
/// {{line}}
{% endfor %}
{% endif %}
{% if string.types %}
{{accessModifier}} static func {{string.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}}({% call parametersBlock string.types %}) -> String {
{{enumName}}.tr("{{table}}", "{{string.key}}", {% call argumentsBlock string.types %})
}
{% else %}
{{accessModifier}} static var {{string.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}}: String { {{enumName}}.tr("{{table}}", "{{string.key}}") }
{% endif %}
{% endfor %}
{% for child in item.children %}
{{accessModifier}} enum {{child.name|swiftIdentifier:"pretty"|escapeReservedKeywords}} {
{% filter indent:2 %}{% call recursiveBlock table child %}{% endfilter %}
}
{% endfor %}
{% endmacro %}
// swiftlint:disable explicit_type_interface function_parameter_count identifier_name line_length
// swiftlint:disable nesting type_body_length type_name vertical_whitespace_opening_braces
{% set enumName %}{{param.enumName|default:"L10n"}}{% endset %}
{{accessModifier}} enum {{enumName}} {
{% if tables.count > 1 or param.forceFileNameEnum %}
{% for table in tables %}
{{accessModifier}} enum {{table.name|swiftIdentifier:"pretty"|escapeReservedKeywords}} {
{% filter indent:2 %}{% call recursiveBlock table.name table.levels %}{% endfilter %}
}
{% endfor %}
{% else %}
{% call recursiveBlock tables.first.name tables.first.levels %}
{% endif %}
}
// swiftlint:enable explicit_type_interface function_parameter_count identifier_name line_length
// swiftlint:enable nesting type_body_length type_name vertical_whitespace_opening_braces
// MARK: - Implementation Details
import Localize_Swift
extension {{enumName}} {
static func tr(_ table: String, _ key: String, _ args: CVarArg...) -> String {
let selectedLanguage = Localize.currentLanguage()
guard let path = Bundle.main.path(forResource: selectedLanguage, ofType: "lproj"),
let bundle = Bundle(path: path) else { return "Setup language error" }
return NSLocalizedString(key, tableName: table, bundle: bundle, comment: "")
}
}
{% endif %}

View file

@ -0,0 +1,47 @@
// swiftlint:disable all
// Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen
{% if catalogs %}
import SwiftUI
{% macro casesBlock assets %}
{% for asset in assets %}
{% if asset.items and asset.isNamespaced == "true" %}
public enum {{asset.name|swiftIdentifier:"pretty"|escapeReservedKeywords}} {
{% filter indent:2 %}{% call casesBlock asset.items %}{% endfilter %}
}
{% elif asset.items %}
{% call casesBlock asset.items %}
{% elif asset.type == "color" %}
public static let {{asset.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}} = Color("{{asset.value}}")
{% elif asset.type == "image" %}
public static let {{asset.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}} = Image("{{asset.value}}")
{% endif %}
{% endfor %}
{% endmacro %}
{% for catalog in catalogs %}
{% if catalog.name == "Colors" %}
extension Color {
{% for catalog in catalogs %}
{% if catalog.name == "Colors" %}
{% call casesBlock catalog.assets %}
{% endif %}
{% endfor %}
}
{% endif %}
{% endfor %}
{% for catalog in catalogs %}
{% if catalog.name == "Images" %}
extension Image {
{% for catalog in catalogs %}
{% if catalog.name == "Images" %}
{% call casesBlock catalog.assets %}
{% endif %}
{% endfor %}
}
{% endif %}
{% endfor %}
{% else %}
// No assets found
{% endif %}

View file

@ -0,0 +1,35 @@
// swiftlint:disable all
// Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen
{% if catalogs %}
import Foundation
typealias AssetStrings = String
{% macro casesBlock assets %}
{% for asset in assets %}
{% if asset.items and asset.isNamespaced == "true" %}
public enum {{asset.name|swiftIdentifier:"pretty"|escapeReservedKeywords}} {
{% filter indent:2 %}{% call casesBlock asset.items %}{% endfilter %}
}
{% elif asset.items %}
{% call casesBlock asset.items %}
{% elif asset.type == "image" %}
public static let {{asset.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}} = String("{{asset.value}}")
{% endif %}
{% endfor %}
{% endmacro %}
{% for catalog in catalogs %}
{% if catalog.name == "Images" %}
extension String {
{% for catalog in catalogs %}
{% if catalog.name == "Images" %}
{% call casesBlock catalog.assets %}
{% endif %}
{% endfor %}
}
{% endif %}
{% endfor %}
{% else %}
// No assets found
{% endif %}

116
.swiftlint.yml Normal file
View file

@ -0,0 +1,116 @@
---
colon:
severity: error
line_length:
ignores_comments: true
warning: 260
error: 300
type_body_length:
warning: 300
error: 500
file_length:
warning: 800
error: 1000
function_parameter_count:
warning: 20
error: 30
function_body_length:
warning: 120
error: 150
cyclomatic_complexity:
warning: 40
error: 50
nesting:
type_level:
warning: 3
error: 6
function_level:
warning: 5
error: 10
vertical_parameter_alignment:
severity: warning
implicitly_unwrapped_optional:
severity: warning
force_unwrapping:
severity: error
vertical_whitespace:
severity: error
force_try:
severity: error
trailing_semicolon:
severity: error
type_name:
min_length: 3
max_length: 60
error: 80
identifier_name:
min_length: 3
max_length: 60
validates_start_with_lowercase: true
allowed_symbols: "_"
excluded:
- iv
- id
- ip
- on
- ui
- x
- y
- tz
- to
# Disable rules from the default enabled set.
disabled_rules:
- trailing_whitespace
- implicit_getter
- redundant_string_enum_value
- switch_case_alignment
# Enable rules not from the default set.
opt_in_rules:
# - function_default_parameter_at_end
- empty_count
- indentation_width
# - index_at_zero
- legacy_constant
# - implicitly_unwrapped_optional
- force_unwrapping
# - no header
- file_header
# - for force unwrapping
- implicitly_unwrapped_optional
- vertical_parameter_alignment_on_call
- vertical_whitespace_between_cases
- vertical_whitespace_closing_braces
- vertical_whitespace_opening_braces
# Acts as a whitelist, only the rules specified in this list will be enabled. Can not be specified alongside disabled_rules or opt_in_rules.
only_rules:
# This is an entirely separate list of rules that are only run by the analyze command. All analyzer rules are opt-in, so this is the only configurable rule list (there is no disabled/whitelist equivalent).
analyzer_rules:
- unused_import
- unused_declaration
unused_declaration:
include_public_and_open: true
# paths to ignore during linting. Takes precedence over `included`.
excluded:
- Snikket/Generated
- old

View file

@ -1 +0,0 @@

9
Packages/Engine/.gitignore vendored Normal file
View file

@ -0,0 +1,9 @@
.DS_Store
/.build
/Packages
/*.xcodeproj
xcuserdata/
DerivedData/
.swiftpm/config/registries.json
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
.netrc

View file

@ -0,0 +1,50 @@
{
"pins" : [
{
"identity" : "libsignal",
"kind" : "remoteSourceControl",
"location" : "https://github.com/tigase/libsignal",
"state" : {
"revision" : "d23d5af0d729cf66b93cea607f3f84a34b9fddfd",
"version" : "1.0.0"
}
},
{
"identity" : "martin",
"kind" : "remoteSourceControl",
"location" : "https://github.com/tigase/Martin",
"state" : {
"revision" : "1d70e9e7eb51a7faa500832be6400a39f86083f7",
"version" : "3.2.4"
}
},
{
"identity" : "martinomemo",
"kind" : "remoteSourceControl",
"location" : "https://github.com/tigase/MartinOMEMO.git",
"state" : {
"revision" : "3c162154d646aa258c9a86c0a07655a536e55a94",
"version" : "2.2.3"
}
},
{
"identity" : "sqlite.swift",
"kind" : "remoteSourceControl",
"location" : "https://github.com/stephencelis/SQLite.swift.git",
"state" : {
"revision" : "7a2e3cd27de56f6d396e84f63beefd0267b55ccb",
"version" : "0.14.1"
}
},
{
"identity" : "tigase-logging.swift",
"kind" : "remoteSourceControl",
"location" : "https://github.com/tigase/tigase-logging.swift",
"state" : {
"revision" : "382e2e85e64f8b1e3fcb71a996a030bf1b62ecb3",
"version" : "1.0.0"
}
}
],
"version" : 2
}

View file

@ -0,0 +1,22 @@
// swift-tools-version: 5.8
import PackageDescription
let package = Package(
name: "Engine",
products: [
.library(
name: "Engine",
targets: ["Engine"]),
],
dependencies: [
.package(url: "https://github.com/stephencelis/SQLite.swift.git", from: "0.14.0"),
.package(url: "https://github.com/tigase/MartinOMEMO.git", from: "2.0.0")
],
targets: [
.target(
name: "Engine",
dependencies: []),
]
)

View file

@ -0,0 +1,3 @@
# Engine
Database and Tigase Martin XMPP wrapper for app.

View file

@ -0,0 +1,10 @@
public struct Engine {
public private(set) var text = "Hello, World!"
public init() {
}
public func testme() {
print("test done!")
}
}

View file

@ -1,39 +0,0 @@
//
// NotificationCategory.swift
//
// Siskin IM
// Copyright (C) 2019 "Tigase, Inc." <office@tigase.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. Look for COPYING file in the top folder.
// If not, see https://www.gnu.org/licenses/.
//
import Foundation
public enum NotificationCategory: String {
case UNKNOWN
case ERROR
case MESSAGE
case SUBSCRIPTION_REQUEST
case MUC_ROOM_INVITATION
case CALL
case UNSENT_MESSAGES
public static func from(identifier: String?) -> NotificationCategory {
guard let str = identifier else {
return .UNKNOWN;
}
return NotificationCategory(rawValue: str) ?? .UNKNOWN;
}
}

View file

@ -1,54 +0,0 @@
//
// DBConnection_main.swift
//
// Siskin IM
// Copyright (C) 2019 "Tigase, Inc." <office@tigase.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. Look for COPYING file in the top folder.
// If not, see https://www.gnu.org/licenses/.
//
import Foundation
extension DBConnection {
public static func mainDbURL() -> URL {
let containerURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.snikket.shared")!;
return containerURL.appendingPathComponent("snikket_main.db");
}
public private(set) static var createIfNotExist: Bool = false;
public static func migrateToGroupIfNeeded() throws {
let dbURL = mainDbURL();
if !FileManager.default.fileExists(atPath: dbURL.path) {
let paths = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true);
let documentDirectory = paths[0];
let path = documentDirectory.appending("/mobile_messenger1.db");
if FileManager.default.fileExists(atPath: path) {
try FileManager.default.moveItem(atPath: path, toPath: dbURL.path);
}
}
createIfNotExist = true;
}
public static func initialize(dbPath: String) throws -> DBConnection {
let conn = try DBConnection(dbPath: dbPath);
try? conn.execute("PRAGMA busy_timeout = 2")
try DBSchemaManager(dbConnection: conn).upgradeSchema();
return conn;
}
}

View file

@ -1,590 +0,0 @@
//
// DBManager.swift
//
// Siskin IM
// Copyright (C) 2016 "Tigase, Inc." <office@tigase.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. Look for COPYING file in the top folder.
// If not, see https://www.gnu.org/licenses/.
//
import Foundation
import UIKit
import TigaseSwift
import SQLite3
let SQLITE_TRANSIENT = unsafeBitCast(-1, to: sqlite3_destructor_type.self)
open class DBConnection {
fileprivate var handle_:OpaquePointer? = nil;
open var handle:OpaquePointer {
get {
return handle_!;
}
}
public let dispatcher: QueueDispatcher;
open var lastInsertRowId: Int? {
let rowid = sqlite3_last_insert_rowid(handle);
return rowid > 0 ? Int(rowid) : nil;
}
open var changesCount: Int {
return Int(sqlite3_changes(handle));
}
convenience public init(dbUrl: URL) throws {
try self.init(dbPath: dbUrl.path);
}
public init(dbPath: String) throws {
dispatcher = QueueDispatcher(label: "db_queue");
try dispatcher.sync {
let flags = SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE;
_ = try self.check(sqlite3_open_v2(dbPath, &self.handle_, flags | SQLITE_OPEN_FULLMUTEX, nil));
}
}
deinit {
sqlite3_close(handle);
}
open func execute(_ query: String) throws {
try dispatcher.sync {
_ = try self.check(sqlite3_exec(self.handle, query, nil, nil, nil));
}
}
open func prepareStatement(_ query: String) throws -> DBStatement {
return try dispatcher.sync {
return try DBStatement(connection: self, query: query);
}
}
fileprivate func check(_ result:Int32, statement:DBStatement? = nil) throws -> Int32 {
guard let error = DBResult(errorCode: result, connection: self, statement: statement) else {
return result;
}
throw error;
}
}
public enum DBResult: Error {
fileprivate static let successCodes = [ SQLITE_OK, SQLITE_ROW, SQLITE_DONE ];
case error(message:String, code: Int32, statement:DBStatement?)
init?(errorCode: Int32, connection: DBConnection, statement:DBStatement?) {
guard !DBResult.successCodes.contains(errorCode) else {
return nil;
}
let tmp = sqlite3_errmsg(connection.handle);
let message = String(cString: tmp!);
self = .error(message: message, code: errorCode, statement: statement);
}
}
open class DBStatement {
fileprivate var handle:OpaquePointer? = nil;
fileprivate let connection:DBConnection;
open lazy var columnCount:Int = Int(sqlite3_column_count(self.handle));
open lazy var columnNames:[String] = (0..<Int32(self.columnCount)).map { (idx:Int32) -> String in
return String(cString: sqlite3_column_name(self.handle, idx)!);
}
open lazy var cursor:DBCursor = DBCursor(statement: self);
public let dispatcher: QueueDispatcher;
open var lastInsertRowId: Int? {
return connection.lastInsertRowId;
}
open var changesCount: Int {
return connection.changesCount;
}
init(connection:DBConnection, query:String, dispatcher: QueueDispatcher = QueueDispatcher(label: "DBStatementDispatcher")) throws {
self.connection = connection;
self.dispatcher = dispatcher;
_ = try connection.check(sqlite3_prepare_v2(connection.handle, query, -1, &handle, nil));
}
deinit {
sqlite3_finalize(handle);
}
fileprivate func step(_ expect: Int32 = SQLITE_ROW) throws -> Bool {
return try connection.dispatcher.sync() {
let result = try self.connection.check(sqlite3_step(self.handle));
return result == expect;
}
}
fileprivate func bind(_ params:Any?...) throws -> DBStatement {
_ = try bind(params);
return self;
}
fileprivate func bind(_ params:[String:Any?]) throws -> DBStatement {
reset()
for (k,v) in params {
let pos = sqlite3_bind_parameter_index(handle, ":"+k);
if pos == 0 {
print("got pos = 0, while parameter count = ", sqlite3_bind_parameter_count(handle));
}
try bind(v, pos: pos);
}
return self;
}
fileprivate func bind(_ params:[Any?]) throws -> DBStatement {
reset()
for pos in 1...params.count {
_ = try bind(params[pos-1], atIndex: pos);
}
return self;
}
fileprivate func bind(_ value:Any?, atIndex:Int) throws -> DBStatement {
try bind(value, pos: Int32(atIndex));
return self;
}
fileprivate func bind(_ value_:Any?, pos:Int32) throws {
var r:Int32 = SQLITE_OK;
if value_ == nil {
r = sqlite3_bind_null(handle, pos);
} else if let value:Any = value_ {
switch value {
case let v as [UInt8]:
r = sqlite3_bind_blob(handle, pos, v, Int32(v.count), SQLITE_TRANSIENT);
case let v as Data:
r = v.withUnsafeBytes() { (bytes) -> Int32 in
return sqlite3_bind_blob(handle, pos, bytes.baseAddress!, Int32(v.count), SQLITE_TRANSIENT);
}
case let v as Double:
r = sqlite3_bind_double(handle, pos, v);
case let v as UInt32:
r = sqlite3_bind_int(handle, pos, Int32(bitPattern: v));
case let v as Int32:
r = sqlite3_bind_int(handle, pos, v);
case let v as Int:
r = sqlite3_bind_int64(handle, pos, Int64(v));
case let v as Bool:
r = sqlite3_bind_int(handle, pos, Int32(v ? 1 : 0));
case let v as String:
r = sqlite3_bind_text(handle, pos, v, -1, SQLITE_TRANSIENT);
case let v as Date:
let timestamp = Int64(v.timeIntervalSince1970 * 1000);
r = sqlite3_bind_int64(handle, pos, timestamp);
case let v as StringValue:
r = sqlite3_bind_text(handle, pos, v.stringValue, -1, SQLITE_TRANSIENT);
default:
throw DBResult.error(message: "Unsupported type \(value.self) for parameter \(pos)", code: SQLITE_FAIL, statement: self);
}
} else {
sqlite3_bind_null(handle, pos)
}
_ = try check(r);
}
fileprivate func execute(_ params:[String:Any?]) throws -> DBStatement? {
_ = try bind(params);
return try execute();
}
fileprivate func execute(_ params:Any?...) throws -> DBStatement? {
return try execute(params);
}
fileprivate func execute(_ params:[Any?]) throws -> DBStatement? {
if params.count > 0 {
_ = try bind(params);
}
reset(false);
return try step() ? self : nil;
}
// open func query(_ params:[String:Any?]) throws -> DBCursor? {
// return try execute(params)?.cursor;
// }
//
// open func query(_ params:Any?...) throws -> DBCursor? {
// return try execute(params)?.cursor;
// }
open func findFirst<T>(_ params: [String:Any?], map: (DBCursor)-> T?) throws -> T? {
return try dispatcher.sync {
guard let cursor = try execute(params)?.cursor else {
return nil;
}
return map(cursor);
}
}
open func findFirst<T>(_ params: Any?..., map: (DBCursor)-> T?) throws -> T? {
return try dispatcher.sync {
guard let cursor = try execute(params)?.cursor else {
return nil;
}
return map(cursor);
}
}
open func query(_ params:[String:Any?], forEach: (DBCursor)->Void) throws {
try dispatcher.sync {
if let cursor = try execute(params)?.cursor {
repeat {
forEach(cursor);
} while cursor.next();
}
}
}
open func query(_ params:Any?..., forEach: (DBCursor)->Void) throws {
try dispatcher.sync {
if let cursor = try execute(params)?.cursor {
repeat {
forEach(cursor);
} while cursor.next();
}
}
}
open func queryFirstMatching<T>(_ params:[String:Any?], forEachRowUntil: (DBCursor)->T?) throws -> T? {
return try dispatcher.sync {
if let cursor = try execute(params)?.cursor {
var result: T?;
repeat {
result = forEachRowUntil(cursor);
} while result == nil && cursor.next();
return result;
}
return nil;
}
}
open func queryFirstMatching<T>(_ params:Any?..., forEachRowUntil: (DBCursor)->T?) throws -> T? {
var result: T? = nil;
try dispatcher.sync {
if let cursor = try execute(params)?.cursor {
repeat {
result = forEachRowUntil(cursor);
} while result == nil && cursor.next();
}
}
return result;
}
open func query<T>(_ params:[String:Any?], map: (DBCursor)->T?) throws -> [T] {
var result = [T]();
try dispatcher.sync {
var tmp: T? = nil;
if let cursor = try execute(params)?.cursor {
repeat {
tmp = map(cursor);
if tmp != nil {
result.append(tmp!);
}
} while cursor.next();
}
}
return result;
}
open func query<T>(_ params:Any?..., map: (DBCursor)->T?) throws -> [T] {
var result = [T]();
try dispatcher.sync {
var tmp: T? = nil;
if let cursor = try execute(params)?.cursor {
repeat {
tmp = map(cursor);
if tmp != nil {
result.append(tmp!);
}
} while cursor.next();
}
}
return result;
}
open func insert(_ params:Any?...) throws -> Int? {
return try connection.dispatcher.sync {
if params.count > 0 {
_ = try self.bind(params);
}
self.reset(false);
if try self.step(SQLITE_DONE) {
return self.lastInsertRowId;
}
return nil;
}
}
open func insert(_ params:[String:Any?]) throws -> Int? {
return try connection.dispatcher.sync {
_ = try self.bind(params);
self.reset(false);
if try self.step(SQLITE_DONE) {
return self.lastInsertRowId;
}
return nil;
}
}
open func update(_ params:Any?...) throws -> Int {
return try connection.dispatcher.sync {
_ = try self.execute(params);
return self.changesCount;
}
}
open func update(_ params:[String:Any?]) throws -> Int {
return try connection.dispatcher.sync {
_ = try self.execute(params);
return self.changesCount;
}
}
open func scalar(_ params:Any?...) throws -> Int? {
return try dispatcher.sync {
let cursor = try self.execute(params)?.cursor;
return cursor?[0];
}
}
open func scalar(_ params:[String:Any?]) throws -> Int? {
return try dispatcher.sync {
let cursor = try self.execute(params)?.cursor;
return cursor?[0];
}
}
open func scalar(_ params:Any?..., columnName: String) throws -> Int? {
return try dispatcher.sync {
let cursor = try self.execute(params)?.cursor;
return cursor?[columnName];
}
}
open func scalar(_ params:[String:Any?], columnName: String) throws -> Int? {
return try dispatcher.sync {
let cursor = try self.execute(params)?.cursor;
return cursor?[columnName];
}
}
fileprivate func reset(_ bindings:Bool=true) {
sqlite3_reset(handle);
if bindings {
sqlite3_clear_bindings(handle);
}
}
fileprivate func check(_ result:Int32) throws -> Int32 {
return try connection.check(result, statement: self);
}
}
open class DBCursor {
fileprivate let connection: DBConnection;
fileprivate let handle:OpaquePointer;
open lazy var columnCount:Int = Int(sqlite3_column_count(self.handle));
open lazy var columnNames:[String] = (0..<Int32(self.columnCount)).map { (idx:Int32) -> String in
return String(cString: sqlite3_column_name(self.handle, idx)!);
}
public init(statement:DBStatement) {
self.connection = statement.connection;
self.handle = statement.handle!;
}
open subscript(index: Int) -> Double {
return sqlite3_column_double(handle, Int32(index));
}
open subscript(index: Int) -> Int {
return Int(sqlite3_column_int64(handle, Int32(index)));
}
open subscript(index: Int) -> Int32 {
return sqlite3_column_int(handle, Int32(index));
}
open subscript(index: Int) -> String? {
let ptr = sqlite3_column_text(handle, Int32(index));
if ptr == nil {
return nil;
}
return String(cString: UnsafePointer(ptr!));
}
open subscript(index: Int) -> Bool {
return sqlite3_column_int64(handle, Int32(index)) != 0;
}
open subscript(index: Int) -> [UInt8]? {
let idx = Int32(index);
let origPtr = sqlite3_column_blob(handle, idx);
if origPtr == nil {
return nil;
}
let count = Int(sqlite3_column_bytes(handle, idx));
let ptr = origPtr?.assumingMemoryBound(to: UInt8.self)
return DBCursor.convert(count, data: ptr!);
}
open subscript(index: Int) -> Data? {
let idx = Int32(index);
let origPtr = sqlite3_column_blob(handle, idx);
if origPtr == nil {
return nil;
}
let count = Int(sqlite3_column_bytes(handle, idx));
return Data(bytes: origPtr!, count: count);
}
open subscript(index: Int) -> Date {
let timestamp = Double(sqlite3_column_int64(handle, Int32(index))) / 1000;
return Date(timeIntervalSince1970: timestamp);
}
open subscript(index: Int) -> JID? {
if let str:String = self[index] {
return JID(str);
}
return nil;
}
open subscript(index: Int) -> BareJID? {
if let str:String = self[index] {
return BareJID(str);
}
return nil;
}
open subscript(column: String) -> Double? {
return forColumn(column) {
return self[$0];
}
}
open subscript(column: String) -> Int? {
// return forColumn(column) {
// let v:Int? = self[$0];
// print("for \(column), position \($0) got \(v)")
// return v;
// }
if let idx = columnNames.firstIndex(of: column) {
return self[idx];
}
return nil;
}
open subscript(column: String) -> Int32? {
// return forColumn(column) {
// let v:Int? = self[$0];
// print("for \(column), position \($0) got \(v)")
// return v;
// }
if let idx = columnNames.firstIndex(of: column) {
return self[idx];
}
return nil;
}
open subscript(column: String) -> String? {
return forColumn(column) {
return self[$0];
}
}
open subscript(column: String) -> Bool? {
return forColumn(column) {
return self[$0];
}
}
open subscript(column: String) -> [UInt8]? {
return forColumn(column) {
return self[$0];
}
}
open subscript(column: String) -> Data? {
return forColumn(column) {
return self[$0];
}
}
open subscript(column: String) -> Date? {
return forColumn(column) {
return self[$0];
}
}
open subscript(column: String) -> JID? {
return forColumn(column) {
return self[$0];
}
}
open subscript(column: String) -> BareJID? {
return forColumn(column) {
return self[$0];
}
}
fileprivate func forColumn<T>(_ column:String, exec:(Int)->T?) -> T? {
if let idx = columnNames.firstIndex(of: column) {
return exec(idx);
}
return nil;
}
fileprivate static func convert<T>(_ count: Int, data: UnsafePointer<T>) -> [T] {
let buffer = UnsafeBufferPointer(start: data, count: count);
return Array(buffer)
}
open func next() -> Bool {
return connection.dispatcher.sync {
return sqlite3_step(self.handle) == SQLITE_ROW;
}
}
open func next() -> DBCursor? {
return next() ? self : nil;
}
}

View file

@ -1,121 +0,0 @@
//
// DBSchemaManager.swift
//
// Siskin IM
// Copyright (C) 2017 "Tigase, Inc." <office@tigase.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. Look for COPYING file in the top folder.
// If not, see https://www.gnu.org/licenses/.
//
import Foundation
import TigaseSwift
public class DBSchemaManager {
static let CURRENT_VERSION = 15;
fileprivate let dbConnection: DBConnection;
public init(dbConnection: DBConnection) {
self.dbConnection = dbConnection;
}
open func upgradeSchema() throws {
var version = try! getSchemaVersion();
while (version < DBSchemaManager.CURRENT_VERSION) {
switch version {
case 0:
try loadSchemaFile(fileName: "/db-schema-1.sql");
do {
try dbConnection.execute("select preview from chat_history");
} catch {
try dbConnection.execute("ALTER TABLE chat_history ADD COLUMN preview TEXT");
}
try cleanUpDuplicatedChats();
case 1:
try loadSchemaFile(fileName: "/db-schema-2.sql");
try cleanUpDuplicatedChats();
default:
try loadSchemaFile(fileName: "/db-schema-\(version + 1).sql");
break;
}
version = try! getSchemaVersion();
}
let journalMode = try dbConnection.prepareStatement("pragma journal_mode").findFirst(map: { cursor -> String? in
return cursor["journal_mode"];
})!;
if journalMode != "wal" {
try dbConnection.execute("PRAGMA journal_mode=WAL");
}
// need to make sure that "error" column exists as there was an issue with db-schema-2.sql
// which did not create this column
do {
try dbConnection.execute("select error from chat_history");
} catch {
try dbConnection.execute("ALTER TABLE chat_history ADD COLUMN error TEXT;");
}
let toRemove: [(String,String,Int32)] = try dbConnection.prepareStatement("SELECT sess.account as account, sess.name as name, sess.device_id as deviceId FROM omemo_sessions sess WHERE NOT EXISTS (select 1 FROM omemo_identities i WHERE i.account = sess.account and i.name = sess.name and i.device_id = sess.device_id)").query([:] as [String: Any?], map: { (cursor:DBCursor) -> (String, String, Int32)? in
return (cursor["account"]!, cursor["name"]!, cursor["deviceId"]!);
});
try toRemove.forEach { tuple in
let (account, name, device) = tuple;
_ = try dbConnection.prepareStatement("DELETE FROM omemo_sessions WHERE account = :account AND name = :name AND device_id = :deviceId").update(["account": account, "name": name, "deviceId": device] as [String: Any?]);
}
}
open func getSchemaVersion() throws -> Int {
return try self.dbConnection.prepareStatement("PRAGMA user_version").scalar() ?? 0;
}
fileprivate func loadSchemaFile(fileName: String) throws {
guard let bundle = Bundle.allFrameworks.first(where: { (bundle) -> Bool in
guard let resourcePath = bundle.resourcePath else {
return false;
}
return FileManager.default.fileExists(atPath: resourcePath.appending(fileName));
}) else {
return;
}
let resourcePath = bundle.resourcePath! + fileName;
print("loading SQL from file", resourcePath);
let dbSchema = try String(contentsOfFile: resourcePath, encoding: String.Encoding.utf8);
print("read schema:", dbSchema);
try dbConnection.execute(dbSchema);
print("loaded schema from file", fileName);
}
fileprivate func cleanUpDuplicatedChats() throws {
// deal with duplicated chats for the same bare jid
print("looking for duplicated chats...");
let duplicates: [(String, String, Int)] = try dbConnection.prepareStatement("select min(c.id) as id, c.account, c.jid from (select count(id) as count, account, jid from chats group by account, jid) x inner join chats c on c.account = x.account and c.jid = x.jid where count > 1 group by c.account, c.jid").query() { (cursor) -> (String, String, Int) in
let account: String = cursor["account"]!;
let jid: String = cursor["jid"]!;
let id: Int = cursor["id"] ?? 0;
print("account", account, "jid", jid, "id", id);
return (account, jid, id);
}
print("found duplicates", duplicates);
try duplicates.forEach({ (account, jid, idToLeave) in
let removed = try dbConnection.prepareStatement("delete from chats where account = ? and jid = ? and id <> :id").scalar(account, jid, idToLeave)!;
print("for account", account, "and jid", jid, "removed", removed, "duplicated chats");
});
print("duplicated chats cleanup finished!");
}
}

View file

@ -1,39 +0,0 @@
//
// NotificationEncryptionKeys.swift
//
// Siskin IM
// Copyright (C) 2019 "Tigase, Inc." <office@tigase.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. Look for COPYING file in the top folder.
// If not, see https://www.gnu.org/licenses/.
//
import Foundation
import TigaseSwift
public class NotificationEncryptionKeys {
private static let storage = UserDefaults(suiteName: "group.snikket.notifications")!;
public static func key(for account: BareJID) -> Data? {
storage.data(forKey: account.stringValue)
}
public static func set(key: Data?, for account: BareJID) {
storage.setValue(key, forKey: account.stringValue);
}
}

View file

@ -1,28 +0,0 @@
//
// AccountTableViewCell.swift
//
// Siskin IM
// Copyright (C) 2017 "Tigase, Inc." <office@tigase.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. Look for COPYING file in the top folder.
// If not, see https://www.gnu.org/licenses/.
//
import UIKit
class AccountTableViewCell: UITableViewCell {
@IBOutlet var accountLabel: UILabel!;
}

View file

@ -1,90 +0,0 @@
//
// AccountsTableViewController.swift
//
// Siskin IM
// Copyright (C) 2017 "Tigase, Inc." <office@tigase.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. Look for COPYING file in the top folder.
// If not, see https://www.gnu.org/licenses/.
//
import UIKit
class AccountsTableViewController: UITableViewController {
var accounts: [String] = [];
var delegate: ShareViewController?;
var selected: String? = nil;
override func viewDidLoad() {
accounts = getAccounts();
super.viewDidLoad();
//tableView.register(AccountTableViewCell.self, forCellReuseIdentifier: "accountTableViewCell");
}
func getAccounts() -> [String] {
var accounts = [String]();
let query = [ String(kSecClass) : kSecClassGenericPassword, String(kSecMatchLimit) : kSecMatchLimitAll, String(kSecReturnAttributes) : kCFBooleanTrue as Any, String(kSecAttrService) : "xmpp" ] as [String : Any];
var result:AnyObject?;
let lastResultCode: OSStatus = withUnsafeMutablePointer(to: &result) {
SecItemCopyMatching(query as CFDictionary, UnsafeMutablePointer($0));
}
if lastResultCode == noErr {
if let results = result as? [[String:NSObject]] {
for r in results {
let name = r[String(kSecAttrAccount)] as! String;
if let data = r[String(kSecAttrGeneric)] as? NSData {
let dict = NSKeyedUnarchiver.unarchiveObject(with: data as Data) as? [String:AnyObject];
if dict!["active"] as? Bool ?? false {
accounts.append(name);
}
}
}
}
}
return accounts;
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1;
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return accounts.count;
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "accountTableViewCell", for: indexPath) as! AccountTableViewCell;
let name = accounts[indexPath.row];
cell.accountLabel.text = name;
if selected != nil && selected! == name {
cell.accessoryType = .checkmark;
} else {
cell.accessoryType = .none;
}
return cell;
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let account = accounts[indexPath.row];
selected = account;
delegate!.accountSelection(account: account);
navigationController?.popViewController(animated: true);
}
}

View file

@ -1,29 +0,0 @@
//
// RecipientTableViewCell.swift
//
// Siskin IM
// Copyright (C) 2017 "Tigase, Inc." <office@tigase.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. Look for COPYING file in the top folder.
// If not, see https://www.gnu.org/licenses/.
//
import UIKit
class RecipientTableViewCell: UITableViewCell {
@IBOutlet var name: UILabel!;
@IBOutlet var jid: UILabel!;
}

View file

@ -1,123 +0,0 @@
//
// RecipientsSelectionViewController.swift
//
// Siskin IM
// Copyright (C) 2017 "Tigase, Inc." <office@tigase.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. Look for COPYING file in the top folder.
// If not, see https://www.gnu.org/licenses/.
//
import UIKit
import TigaseSwift
class RecipientsSelectionViewController: UITableViewController {
var selected: [JID] = [];
var allItems = [JID:RosterItem]();
var items: [RosterItem] = [];
var xmppClient: XMPPClient! {
didSet {
let store = RosterModule.getRosterStore(xmppClient.sessionObject) as! DefaultRosterStore;
self.allItems.removeAll();
store.getJids().forEach({(jid) in
if let item = store.get(for: jid) {
allItems[jid] = item;
}
});
updateItem(item: nil);
}
}
var delegate: ShareViewController?;
var sharedDefaults = UserDefaults(suiteName: "group.snikket.share");
fileprivate let indicator = UIActivityIndicatorView(frame: CGRect(x: 0, y: 0, width: 80, height: 80));
override func viewDidLoad() {
super.viewDidLoad();
indicator.style = .gray;
indicator.backgroundColor = UIColor.white;
indicator.hidesWhenStopped = true;
self.view.addSubview(indicator);
}
override func viewWillAppear(_ animated: Bool) {
if xmppClient.state == .connecting {
indicator.startAnimating();
}
super.viewWillAppear(animated);
let view = self.parent!.view!;
indicator.center = CGPoint(x: view.bounds.width / 2, y: view.bounds.height / 2);
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1;
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items.count;
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "recipientTableViewCell", for: indexPath) as! RecipientTableViewCell;
let item = items[indexPath.row];
cell.name.text = item.name ?? item.jid.stringValue;
if selected.contains(item.jid) {
cell.accessoryType = .checkmark;
} else {
cell.accessoryType = .none;
}
return cell;
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let jid = items[indexPath.row].jid;
if let idx = selected.firstIndex(of: jid) {
selected.remove(at: idx);
} else {
selected.append(jid);
}
delegate?.recipientsChanged(selected);
tableView.reloadData();
}
func hideIndicator() {
DispatchQueue.main.async {
if self.indicator.isAnimating {
self.indicator.stopAnimating();
}
}
}
func updateItem(item: RosterItem?) {
if item != nil {
allItems[item!.jid] = item!;
}
let showHidden = sharedDefaults!.bool(forKey: "RosterDisplayHiddenGroup");
let tmp: [RosterItem] = allItems.values.filter({ (ri) -> Bool in
return showHidden || !ri.groups.contains("Hidden");
});
items = tmp.sorted { (r1, r2) -> Bool in
return (r1.name ?? r1.jid.stringValue).compare(r2.name ?? r2.jid.stringValue) == .orderedAscending;
}
tableView.reloadData();
if item != nil {
hideIndicator();
}
}
}

View file

@ -1,43 +0,0 @@
{
"object": {
"pins": [
{
"package": "HSLuvSwift",
"repositoryURL": "https://github.com/hsluv/hsluv-swift.git",
"state": {
"branch": null,
"revision": "9dee4378180f2a9a33c96bc20284cf64158dbe1b",
"version": "2.1.0"
}
},
{
"package": "libsignal",
"repositoryURL": "https://github.com/tigase/libsignal",
"state": {
"branch": null,
"revision": "d23d5af0d729cf66b93cea607f3f84a34b9fddfd",
"version": "1.0.0"
}
},
{
"package": "TigaseSwift",
"repositoryURL": "https://github.com/tigase/tigase-swift",
"state": {
"branch": null,
"revision": "d3953dcea80010ad433fa96d7ca6b989bf58850c",
"version": "2.1.3"
}
},
{
"package": "TigaseSwiftOMEMO",
"repositoryURL": "https://github.com/tigase/tigase-swift-omemo/",
"state": {
"branch": null,
"revision": "4c997df9a3a686b7e522ddffa4d2f2c070a94fa0",
"version": "1.1.3"
}
}
]
},
"version": 1
}

View file

@ -0,0 +1,5 @@
enum AppAction: Codable {
case flushState
case changeFlow(_ flow: AppFlow)
case tempAction(_ action: TempAction)
}

View file

@ -0,0 +1,3 @@
enum TempAction: Codable {
case dumb
}

View file

@ -0,0 +1,94 @@
/*
In 99,99% of time YOU DON'T NEEDED TO CHANGE ANYTHING in this file!
This file declare global state object for whole app
and reducers/actions/middleware types. Core of AppCore.
*/
import Foundation
import Combine
typealias Stateable = Codable & Equatable
typealias AppStore = Store<AppState, AppAction>
typealias Reducer<State: Stateable, Action: Codable> = (inout State, Action) -> Void
typealias Middleware<State: Stateable, Action: Codable> = (State, Action) -> AnyPublisher<Action, Never>?
final class Store<State: Stateable, Action: Codable>: ObservableObject {
// Fake variable for be able to trigger SwiftUI redraw after app state completely changed
// this hack is needed because @Published wrapper sends signals on "willSet:"
@Published private var dumbVar: UUID = UUID()
// State is read-only (changes only over reducers)
private(set) var state: State {
didSet {
DispatchQueue.main.async { [weak self] in
self?.dumbVar = UUID()
}
} // signal to SwiftUI only when new state did set
}
// Serial queue for performing any actions sequentially
private let serialQueue = DispatchQueue(label: "im.narayana.snikket.core.serial.queue", qos: .userInteractive)
private let reducer: Reducer<State, Action>
private let middlewares: [Middleware<State, Action>]
private var middlewareCancellables: Set<AnyCancellable> = []
// Init
init(
initialState: State,
reducer: @escaping Reducer<State, Action>,
middlewares: [Middleware<State, Action>] = []) {
state = initialState
self.reducer = reducer
self.middlewares = middlewares
}
// Run reducers/middlewares
func dispatch(_ action: Action) {
serialQueue.sync { [weak self] in
guard let wSelf = self else { return }
let newState = wSelf.dispatch(wSelf.state, action)
wSelf.state = newState
}
}
private func dispatch(_ currentState: State, _ action: Action) -> State {
let startTime = CFAbsoluteTimeGetCurrent()
// Do reducing
var newState = currentState
reducer(&newState, action)
// Dispatch all middleware functions
for middleware in middlewares {
guard let middleware = middleware(newState, action) else {
break
}
middleware
.receive(on: DispatchQueue.main)
.sink(receiveValue: dispatch)
.store(in: &middlewareCancellables)
}
// Check performance
let timeElapsed = CFAbsoluteTimeGetCurrent() - startTime
if timeElapsed > 0.05 {
#if DEBUG
print(
"""
--
(Ignore this warning ONLY in case, when execution is paused by your breakpoint)
🕐Execution time: \(timeElapsed)
WARNING! Some reducers/middlewares work too long! It will lead to issues in production build!
Because of execution each action is synchronous the any stuck will reduce performance dramatically.
Probably you need check which part of reducer/middleware should be async (wrapped with Futures, as example)
--
"""
)
#else
#endif
}
return newState
}
}

View file

@ -0,0 +1,36 @@
import Foundation
import Combine
let isConsoleLoggingEnabled = false
#if DEBUG
func loggerMiddleware() -> Middleware<AppState, AppAction> {
{ state, action in
let timeStr = dateFormatter.string(from: Date())
var actionStr = "\(action)"
actionStr = String(actionStr.prefix(200)) + " ..."
var stateStr = "\(state)"
stateStr = String(stateStr.prefix(200)) + " ..."
let str = "\(timeStr) ➡️ \(actionStr)\n\(timeStr)\(stateStr)\n"
print(str)
if isConsoleLoggingEnabled {
NSLog(str)
}
return Empty().eraseToAnyPublisher()
}
}
#else
func loggerMiddleware() -> Middleware<AppState, AppAction> {
{ _, _ in
Empty().eraseToAnyPublisher()
}
}
#endif
private var dateFormatter: DateFormatter {
let formatter = DateFormatter()
formatter.locale = NSLocale(localeIdentifier: "en_US_POSIX") as Locale
formatter.dateFormat = "MM-dd HH:mm:ss.SSS"
return formatter
}

View file

@ -0,0 +1,16 @@
import Combine
final class TempMiddleware {
static let shared = TempMiddleware()
func middleware(state: AppState, action: AppAction) -> AnyPublisher<AppAction, Never> {
switch action {
case .tempAction(.dumb):
return Just(AppAction.flushState)
.eraseToAnyPublisher()
default:
return Empty().eraseToAnyPublisher()
}
}
}

View file

@ -0,0 +1,3 @@
struct TempModel: Stateable {
var some: Bool
}

View file

@ -0,0 +1,16 @@
import Foundation
extension AppState {
static func reducer(state: inout AppState, action: AppAction) {
switch action {
case .flushState:
state = AppState()
case .changeFlow(let flow):
state.currentFlow = flow
case .tempAction(let action):
TempState.reducer(state: &state.tempState, action: action)
}
}
}

View file

@ -0,0 +1,9 @@
extension TempState {
static func reducer(state: inout TempState, action: TempAction) {
switch action {
case .dumb:
state = .init()
state.someModel = .init(some: true)
}
}
}

View file

@ -0,0 +1,22 @@
import Foundation
enum AppFlow: Codable {
case start
}
struct AppState: Stateable {
var appVersion: String
var currentFlow: AppFlow
var tempState: TempState
}
// MARK: Init
extension AppState {
init() {
appVersion = Const.appVersion
currentFlow = .start
tempState = .init()
}
}

View file

@ -0,0 +1,18 @@
import Foundation
enum TempNavigationState: Stateable {
case main
case details
}
struct TempState: Stateable {
var navigation: TempNavigationState
var someModel: TempModel?
}
// MARK: Init
extension TempState {
init() {
navigation = .main
}
}

2
Snikket/Generated/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
*
!.gitignore

View file

@ -0,0 +1,9 @@
import Foundation
extension AppState {
func json() -> String {
let encoder = JSONEncoder()
guard let data = try? encoder.encode(self) else { return "AppState encoding error" }
return String(data: data, encoding: .utf8) ?? "AppState encoding error"
}
}

View file

@ -0,0 +1,7 @@
import Foundation
extension Bool {
var intValue: Int {
self ? 1 : 0
}
}

View file

@ -0,0 +1,24 @@
import Foundation
struct Const {
// Network
#if DEBUG
static let baseUrl = "staging.some.com/api"
#else
static let baseUrl = "prod.some.com/api"
#endif
static let requestTimeout = 15.0
static let networkLogging = true
// App
static var appVersion: String {
let info = Bundle.main.infoDictionary
let appVersion = info?["CFBundleShortVersionString"] as? String ?? "Unknown"
let appBuild = info?[kCFBundleVersionKey as String] as? String ?? "Unknown"
return "v \(appVersion)(\(appBuild))"
}
static var appName: String {
Bundle.main.bundleIdentifier ?? "Snikket iOS"
}
}

View file

@ -0,0 +1,23 @@
import Foundation
@propertyWrapper
struct Storage<T> {
private let key: String
private let defaultValue: T
init(key: String, defaultValue: T) {
self.key = key
self.defaultValue = defaultValue
}
var wrappedValue: T {
get {
// Read value from UserDefaults
return UserDefaults.standard.object(forKey: key) as? T ?? defaultValue
}
set {
// Set value to UserDefaults
UserDefaults.standard.set(newValue, forKey: key)
}
}
}

View file

@ -0,0 +1,9 @@
{
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"provides-namespace" : true
}
}

View file

@ -0,0 +1,20 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.180",
"green" : "0.180",
"red" : "0.180"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View file

@ -0,0 +1,20 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.471",
"green" : "0.471",
"red" : "0.471"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View file

@ -0,0 +1,20 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.902",
"green" : "0.902",
"red" : "0.902"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View file

@ -0,0 +1,20 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.973",
"green" : "0.973",
"red" : "0.973"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View file

@ -0,0 +1,20 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.741",
"green" : "0.741",
"red" : "0.741"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View file

@ -0,0 +1,20 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "1.000",
"green" : "1.000",
"red" : "1.000"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View file

@ -0,0 +1,9 @@
{
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"provides-namespace" : true
}
}

View file

@ -0,0 +1,20 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.976",
"green" : "0.792",
"red" : "0.565"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View file

@ -0,0 +1,20 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.965",
"green" : "0.710",
"red" : "0.392"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View file

@ -0,0 +1,20 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.953",
"green" : "0.588",
"red" : "0.129"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View file

@ -0,0 +1,20 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.824",
"green" : "0.463",
"red" : "0.098"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View file

@ -0,0 +1,20 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.855",
"green" : "0.659",
"red" : "0.624"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View file

@ -0,0 +1,20 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.796",
"green" : "0.525",
"red" : "0.475"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View file

@ -0,0 +1,20 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.710",
"green" : "0.318",
"red" : "0.247"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View file

@ -0,0 +1,20 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.624",
"green" : "0.247",
"red" : "0.188"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View file

@ -0,0 +1,20 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.980",
"green" : "0.831",
"red" : "0.506"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View file

@ -0,0 +1,20 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.969",
"green" : "0.765",
"red" : "0.310"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View file

@ -0,0 +1,20 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.957",
"green" : "0.663",
"red" : "0.012"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View file

@ -0,0 +1,20 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.820",
"green" : "0.533",
"red" : "0.008"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View file

@ -0,0 +1,20 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.643",
"green" : "0.667",
"red" : "0.737"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View file

@ -0,0 +1,20 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.498",
"green" : "0.533",
"red" : "0.631"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View file

@ -0,0 +1,20 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.282",
"green" : "0.333",
"red" : "0.475"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View file

@ -0,0 +1,20 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.216",
"green" : "0.251",
"red" : "0.365"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View file

@ -0,0 +1,20 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.655",
"green" : "0.839",
"red" : "0.647"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Some files were not shown because too many files have changed in this diff Show more