Skip to content

Commit

Permalink
Support SwiftPM: Handle Swift package asset catalogs (#73)
Browse files Browse the repository at this point in the history
  • Loading branch information
JonLz authored Feb 17, 2021
1 parent da6f3c7 commit 8381d57
Show file tree
Hide file tree
Showing 15 changed files with 119 additions and 9 deletions.
2 changes: 2 additions & 0 deletions CONFIG.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ ios:
xcassetsPath: "./Resources/Assets.xcassets"
# Is Assets.xcassets located in the main bundle?
xcassetsInMainBundle: true
# [optional] Is Assets.xcassets located in a swift package? Default value is false.
xcassetsInSwiftPackage: false

# Parameters for exporting colors
colors:
Expand Down
2 changes: 1 addition & 1 deletion Examples/Example/figma-export.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ ios:
xcassetsPath: "./UIComponents/Resource/Assets.xcassets"
# Is Assets.xcassets located in the main bundle?
xcassetsInMainBundle: false

# Parameters for exporting colors
colors:
# Should be generate color assets instead of pure swift code
Expand Down
2 changes: 1 addition & 1 deletion Examples/ExampleSwiftUI/figma-export.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,4 @@ ios:
swiftUIFontSwift: "./ExampleSwiftUI/View/Common/Font+extension.swift"

# Will FigmaExport generate UILabel for each text style (font) e.g. HeaderLabel, BodyLabel, CaptionLabel.
generateLabels: false
generateLabels: false
1 change: 1 addition & 0 deletions Sources/FigmaExport/Input/Params.swift
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ struct Params: Decodable {
let target: String
let xcassetsPath: URL
let xcassetsInMainBundle: Bool
let xcassetsInSwiftPackage: Bool?
let colors: Colors
let icons: Icons
let images: Images
Expand Down
2 changes: 2 additions & 0 deletions Sources/FigmaExport/Resources/iOSConfig.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ ios:
xcassetsPath: "./Resources/Assets.xcassets"
# Is Assets.xcassets located in the main bundle?
xcassetsInMainBundle: true
# [optional] Is Assets.xcassets located in a swift package? Default value is false.
xcassetsInSwiftPackage: false
# Parameters for exporting colors
colors:
Expand Down
1 change: 1 addition & 0 deletions Sources/FigmaExport/Subcommands/ExportColors.swift
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ extension FigmaExportCommand {
let output = XcodeColorsOutput(
assetsColorsURL: colorsURL,
assetsInMainBundle: iosParams.xcassetsInMainBundle,
assetsInSwiftPackage: iosParams.xcassetsInSwiftPackage,
colorSwiftURL: iosParams.colors.colorSwift,
swiftuiColorSwiftURL: iosParams.colors.swiftuiColorSwift)

Expand Down
1 change: 1 addition & 0 deletions Sources/FigmaExport/Subcommands/ExportIcons.swift
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ extension FigmaExportCommand {
let output = XcodeImagesOutput(
assetsFolderURL: assetsURL,
assetsInMainBundle: ios.xcassetsInMainBundle,
assetsInSwiftPackage: ios.xcassetsInSwiftPackage,
preservesVectorRepresentation: ios.icons.preservesVectorRepresentation,
uiKitImageExtensionURL: ios.icons.imageSwift,
swiftUIImageExtensionURL: ios.icons.swiftUIImageSwift,
Expand Down
1 change: 1 addition & 0 deletions Sources/FigmaExport/Subcommands/ExportImages.swift
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ extension FigmaExportCommand {
let output = XcodeImagesOutput(
assetsFolderURL: assetsURL,
assetsInMainBundle: ios.xcassetsInMainBundle,
assetsInSwiftPackage: ios.xcassetsInSwiftPackage,
uiKitImageExtensionURL: ios.images.imageSwift,
swiftUIImageExtensionURL: ios.images.swiftUIImageSwift)

Expand Down
9 changes: 8 additions & 1 deletion Sources/XcodeExport/Model/XcodeColorsOutput.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,19 @@ public struct XcodeColorsOutput {

public let assetsColorsURL: URL?
public let assetsInMainBundle: Bool
public let assetsInSwiftPackage: Bool
public let colorSwiftURL: URL?
public let swiftuiColorSwiftURL: URL?

public init(assetsColorsURL: URL?, assetsInMainBundle: Bool, colorSwiftURL: URL? = nil, swiftuiColorSwiftURL: URL? = nil) {
public init(
assetsColorsURL: URL?,
assetsInMainBundle: Bool,
assetsInSwiftPackage: Bool? = false,
colorSwiftURL: URL? = nil,
swiftuiColorSwiftURL: URL? = nil) {
self.assetsColorsURL = assetsColorsURL
self.assetsInMainBundle = assetsInMainBundle
self.assetsInSwiftPackage = assetsInSwiftPackage ?? false
self.colorSwiftURL = colorSwiftURL
self.swiftuiColorSwiftURL = swiftuiColorSwiftURL
}
Expand Down
3 changes: 3 additions & 0 deletions Sources/XcodeExport/Model/XcodeImagesOutput.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ public struct XcodeImagesOutput {

let assetsFolderURL: URL
let assetsInMainBundle: Bool
let assetsInSwiftPackage: Bool
let preservesVectorRepresentation: [String]?
let renderMode: XcodeRenderMode?

Expand All @@ -20,13 +21,15 @@ public struct XcodeImagesOutput {
public init(
assetsFolderURL: URL,
assetsInMainBundle: Bool,
assetsInSwiftPackage: Bool? = false,
preservesVectorRepresentation: [String]? = nil,
uiKitImageExtensionURL: URL? = nil,
swiftUIImageExtensionURL: URL? = nil,
renderMode: XcodeRenderMode? = nil) {

self.assetsFolderURL = assetsFolderURL
self.assetsInMainBundle = assetsInMainBundle
self.assetsInSwiftPackage = assetsInSwiftPackage ?? false
self.preservesVectorRepresentation = preservesVectorRepresentation
self.uiKitImageExtensionURL = uiKitImageExtensionURL
self.swiftUIImageExtensionURL = swiftUIImageExtensionURL
Expand Down
6 changes: 3 additions & 3 deletions Sources/XcodeExport/XcodeColorExporter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -100,12 +100,12 @@ final public class XcodeColorExporter {
return " static var \(colorPair.light.name): Color { Color(#function, bundle: BundleProvider.bundle) }"
}
}

return """
\(header)
import SwiftUI
\(output.assetsInMainBundle ? "" : bundleProvider)
\(output.assetsInMainBundle ? "" : (output.assetsInSwiftPackage ? bundleProviderSwiftPackage : bundleProvider))
public extension Color {
\(strings.joined(separator: "\n"))
}
Expand Down Expand Up @@ -157,7 +157,7 @@ final public class XcodeColorExporter {
\(header)
import UIKit
\((!output.assetsInMainBundle && formAsset) ? bundleProvider : "")
\((!output.assetsInMainBundle && formAsset) ? (output.assetsInSwiftPackage ? bundleProviderSwiftPackage : bundleProvider) : "")
public extension UIColor {
\(contents.joined(separator: "\n"))
}
Expand Down
4 changes: 2 additions & 2 deletions Sources/XcodeExport/XcodeImagesExporterBase.swift
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ public class XcodeImagesExporterBase {
\(header)
import SwiftUI
\(output.assetsInMainBundle ? "" : bundleProvider)
\(output.assetsInMainBundle ? "" : (output.assetsInSwiftPackage ? bundleProviderSwiftPackage : bundleProvider))
public extension Image {
\(images.joined(separator: "\n"))
}
Expand All @@ -113,7 +113,7 @@ public class XcodeImagesExporterBase {
\(header)
import UIKit
\(output.assetsInMainBundle ? "" : bundleProvider)
\(output.assetsInMainBundle ? "" : (output.assetsInSwiftPackage ? bundleProviderSwiftPackage : bundleProvider))
public extension UIImage {
\(images.joined(separator: "\n"))
}
Expand Down
7 changes: 7 additions & 0 deletions Sources/XcodeExport/bundle_provider_swift_package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
let bundleProviderSwiftPackage = """
private class BundleProvider {
static let bundle = Bundle.module
}
"""
40 changes: 40 additions & 0 deletions Tests/XcodeExportTests/XcodeColorExporterTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,46 @@ final class XcodeColorExporterTests: XCTestCase {
"""
XCTAssertEqual(generatedCode, referenceCode)
}

func testExport_with_assets_in_swift_package() {
let output = XcodeColorsOutput(assetsColorsURL: colorsAsssetCatalog, assetsInMainBundle: false, assetsInSwiftPackage: true, colorSwiftURL: colorsFile)
let exporter = XcodeColorExporter(output: output)
let result = exporter.export(colorPairs: [colorPair1, colorPair2])

XCTAssertEqual(result.count, 4)
XCTAssertTrue(result[0].destination.url.absoluteString.hasSuffix("Colors.swift"))
XCTAssertTrue(result[1].destination.url.absoluteString.hasSuffix("Assets.xcassets/Colors/Contents.json"))
XCTAssertTrue(result[2].destination.url.absoluteString.hasSuffix("colorPair1.colorset/Contents.json"))
XCTAssertTrue(result[3].destination.url.absoluteString.hasSuffix("colorPair2.colorset/Contents.json"))

let content = result[0].data
XCTAssertNotNil(content)

let generatedCode = String(data: content!, encoding: .utf8)
let referenceCode = """
//
// The code generated using FigmaExport — Command line utility to export
// colors, typography, icons and images from Figma to Xcode project.
//
// https://github.com/RedMadRobot/figma-export
//
// Don’t edit this code manually to avoid runtime crashes
//
import UIKit
private class BundleProvider {
static let bundle = Bundle.module
}
public extension UIColor {
static var colorPair1: UIColor { UIColor(named: #function, in: BundleProvider.bundle, compatibleWith: nil)! }
static var colorPair2: UIColor { UIColor(named: #function, in: BundleProvider.bundle, compatibleWith: nil)! }
}
"""
XCTAssertEqual(generatedCode, referenceCode)
}

func testExport_swiftui() {
let output = XcodeColorsOutput(assetsColorsURL: colorsAsssetCatalog, assetsInMainBundle: true, colorSwiftURL: nil, swiftuiColorSwiftURL: colorsFile)
Expand Down
47 changes: 46 additions & 1 deletion Tests/XcodeExportTests/XcodeIconsExporterTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ final class XcodeIconsExporterTests: XCTestCase {
}

func testExportInSeparateBundle() throws {
let output = XcodeImagesOutput(assetsFolderURL: URL(string: "~/")!, assetsInMainBundle: false, uiKitImageExtensionURL: URL(string: "~/UIImage+extension.swift")!)
let output = XcodeImagesOutput(assetsFolderURL: URL(string: "~/")!, assetsInMainBundle: false, assetsInSwiftPackage: false, uiKitImageExtensionURL: URL(string: "~/UIImage+extension.swift")!)
let exporter = XcodeIconsExporter(output: output)
let result = try exporter.export(
icons: [ImagePack(image: image1), ImagePack(image: image2)],
Expand Down Expand Up @@ -98,6 +98,51 @@ final class XcodeIconsExporterTests: XCTestCase {
"""
XCTAssertEqual(generatedCode, referenceCode)
}

func testExportInSwiftPackage() throws {
let output = XcodeImagesOutput(assetsFolderURL: URL(string: "~/")!, assetsInMainBundle: false, assetsInSwiftPackage: true, uiKitImageExtensionURL: URL(string: "~/UIImage+extension.swift")!)
let exporter = XcodeIconsExporter(output: output)
let result = try exporter.export(
icons: [ImagePack(image: image1), ImagePack(image: image2)],
append: false
)

XCTAssertEqual(result.count, 6)
XCTAssertTrue(result[0].destination.url.absoluteString.hasSuffix("Contents.json"))
XCTAssertTrue(result[1].destination.url.absoluteString.hasSuffix("image1.imageset/image1.pdf"))
XCTAssertTrue(result[2].destination.url.absoluteString.hasSuffix("image1.imageset/Contents.json"))
XCTAssertTrue(result[3].destination.url.absoluteString.hasSuffix("image2.imageset/image2.pdf"))
XCTAssertTrue(result[4].destination.url.absoluteString.hasSuffix("image2.imageset/Contents.json"))
XCTAssertTrue(result[5].destination.url.absoluteString.hasSuffix("UIImage+extension.swift"))

let content = result[5].data
XCTAssertNotNil(content)

let generatedCode = String(data: content!, encoding: .utf8)
let referenceCode = """
//
// The code generated using FigmaExport — Command line utility to export
// colors, typography, icons and images from Figma to Xcode project.
//
// https://github.com/RedMadRobot/figma-export
//
// Don’t edit this code manually to avoid runtime crashes
//
import UIKit
private class BundleProvider {
static let bundle = Bundle.module
}
public extension UIImage {
static var image1: UIImage { UIImage(named: #function, in: BundleProvider.bundle, compatibleWith: nil)! }
static var image2: UIImage { UIImage(named: #function, in: BundleProvider.bundle, compatibleWith: nil)! }
}
"""
XCTAssertEqual(generatedCode, referenceCode)
}

func testExportSwiftUI() throws {
let output = XcodeImagesOutput(assetsFolderURL: URL(string: "~/")!, assetsInMainBundle: true, swiftUIImageExtensionURL: URL(string: "~/Image+extension.swift")!)
Expand Down

0 comments on commit 8381d57

Please sign in to comment.