Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save DenTelezhkin/4bffa38b9e81db02a07e96c89fe7ddd5 to your computer and use it in GitHub Desktop.
Save DenTelezhkin/4bffa38b9e81db02a07e96c89fe7ddd5 to your computer and use it in GitHub Desktop.
SwiftUI code generation template for SwiftGen

Example of generated code

internal extension Color {
  // Assets.xcassets
  static var midnightBlue : Color { Color("midnightBlue", bundle: BundleToken.bundle) }
}

internal extension Image {
// Assets.xcassets
  static var abc : Color { Image("abc", bundle: BundleToken.bundle) }
}

Usage

  Color.midnightBlue // Color
  Image.abc // Image
// swiftlint:disable all
// Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen
{% if catalogs %}
{% set forceNamespaces %}{{param.forceProvidesNamespaces|default:"false"}}{% endset %}
{% set accessModifier %}{% if param.publicAccess %}public{% else %}internal{% endif %}{% endset %}
import SwiftUI
{% macro casesBlock assets type prefix %}
{% for asset in assets %}
{% if asset.type == type %}
static var {% if prefix %}{{prefix}}{% endif %}{{asset.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}} : {{type|capitalize}} { {{type|capitalize}}("{{asset.value}}", bundle: BundleToken.bundle) }
{% elif asset.items and ( forceNamespaces == "true" or asset.isNamespaced == "true" ) %}
{% set prefixed_asset %}{% if prefix == "" %}{{asset.name|lowerFirstWord|swiftIdentifier:"pretty"}}_{% else %}{{prefix}}{{asset.name|lowerFirstWord|swiftIdentifier:"pretty"}}_{% endif %}{% endset %}
{% call casesBlock asset.items type prefixed_asset %}
{% elif asset.items %}
{% call casesBlock asset.items type prefix %}
{% endif %}
{% endfor %}
{% endmacro %}
{{accessModifier}} extension Color {
{% if catalogs.count > 1 %}
{% for catalog in catalogs %}
// {{catalog.name}}.xcassets
{% set prefixed_catalog %}{{catalog.name|swiftIdentifier:"pretty"|lowerFirstWord}}_{% endset %}
{% if forceNamespaces == "true" %} {% call casesBlock catalog.assets "color" prefixed_catalog %}{% else %}{% call casesBlock catalog.assets "color" "" %}{% endif %}
{% endfor %}
{% else %}
// {{catalogs.first.name}}.xcassets
{% set prefixed_catalog %}{{catalogs.first.name|swiftIdentifier:"pretty"|lowerFirstWord}}_{% endset %}
{% if forceNamespaces == "true" %} {% call casesBlock catalogs.first.assets "color" prefixed_catalog %}{% else %}{% call casesBlock catalogs.first.assets "color" "" %}{% endif %}
{% endif %}
}
{{accessModifier}} extension Image {
{% if catalogs.count > 1 %}
{% for catalog in catalogs %}
// {{catalog.name}}.xcassets
{% set prefixed_catalog %}{{catalog.name|swiftIdentifier:"pretty"|lowerFirstWord}}_{% endset %}
{% if forceNamespaces == "true" %} {% call casesBlock catalog.assets "image" prefixed_catalog %}{% else %}{% call casesBlock catalog.assets "image" "" %}{% endif %}
{% endfor %}
{% else %}
// {{catalogs.first.name}}.xcassets
{% set prefixed_catalog %}{{catalogs.first.name|swiftIdentifier:"pretty"|lowerFirstWord}}_{% endset %}
{% if forceNamespaces == "true" %} {% call casesBlock catalogs.first.assets "image" prefixed_catalog %}{% else %}{% call casesBlock catalogs.first.assets "image" "" %}{% endif %}
{% endif %}
}
{% if resourceCount.image > 0 %}
{% endif %}
private final class BundleToken {
static let bundle: Bundle = {
Bundle(for: BundleToken.self)
}()
}
{% else %}
// No assets found
{% endif %}
@MeteC
Copy link

MeteC commented Nov 16, 2020

Nice, thanks for this!
Note I found this causes issues when I name a colour in my xcassets file with a standard name (e.g. "Red") as this tries to create Color.red - which already exists. In my usage I made a slight change to the stencil to produce a local struct called something like AppColor, rather than extending the Color struct.

(That is I use the enumName value like {{accessModifier}} struct {{enumName}})

@DenTelezhkin
Copy link
Author

@MeteC this can work, sure. Alternatively you can rename your red color to preserve the Color.name syntax.

@DenTelezhkin
Copy link
Author

One more nice thing about extending Color and Image is getting type inference in places where it's applicable. For example:

Text("foo").foregroundColor(.carrot)

Not a major thing by any means, but still :)

@MeteC
Copy link

MeteC commented Nov 18, 2020

Ah very good point! And you're right, it's not too hard to name custom colours a little more "custom-ly" than just "Red" 😅

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment