diff --git a/CONFIG.md b/CONFIG.md index 80397169..8f7a5d6f 100644 --- a/CONFIG.md +++ b/CONFIG.md @@ -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: diff --git a/Examples/Example/figma-export.yaml b/Examples/Example/figma-export.yaml index 444107dd..925310bc 100644 --- a/Examples/Example/figma-export.yaml +++ b/Examples/Example/figma-export.yaml @@ -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 diff --git a/Examples/ExampleSwiftUI/figma-export.yaml b/Examples/ExampleSwiftUI/figma-export.yaml index 9e3f8182..b6a30d11 100644 --- a/Examples/ExampleSwiftUI/figma-export.yaml +++ b/Examples/ExampleSwiftUI/figma-export.yaml @@ -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 \ No newline at end of file + generateLabels: false diff --git a/Sources/FigmaExport/Input/Params.swift b/Sources/FigmaExport/Input/Params.swift index 8956340a..8a474894 100644 --- a/Sources/FigmaExport/Input/Params.swift +++ b/Sources/FigmaExport/Input/Params.swift @@ -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 diff --git a/Sources/FigmaExport/Resources/iOSConfig.swift b/Sources/FigmaExport/Resources/iOSConfig.swift index ff41840d..dc51da81 100644 --- a/Sources/FigmaExport/Resources/iOSConfig.swift +++ b/Sources/FigmaExport/Resources/iOSConfig.swift @@ -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: diff --git a/Sources/FigmaExport/Subcommands/ExportColors.swift b/Sources/FigmaExport/Subcommands/ExportColors.swift index af9213c7..169d1ee3 100644 --- a/Sources/FigmaExport/Subcommands/ExportColors.swift +++ b/Sources/FigmaExport/Subcommands/ExportColors.swift @@ -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) diff --git a/Sources/FigmaExport/Subcommands/ExportIcons.swift b/Sources/FigmaExport/Subcommands/ExportIcons.swift index 3ae3c64c..4f8bbe6b 100644 --- a/Sources/FigmaExport/Subcommands/ExportIcons.swift +++ b/Sources/FigmaExport/Subcommands/ExportIcons.swift @@ -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, diff --git a/Sources/FigmaExport/Subcommands/ExportImages.swift b/Sources/FigmaExport/Subcommands/ExportImages.swift index 156493fd..94ef713b 100644 --- a/Sources/FigmaExport/Subcommands/ExportImages.swift +++ b/Sources/FigmaExport/Subcommands/ExportImages.swift @@ -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) diff --git a/Sources/XcodeExport/Model/XcodeColorsOutput.swift b/Sources/XcodeExport/Model/XcodeColorsOutput.swift index 0940d784..1f6d24a1 100644 --- a/Sources/XcodeExport/Model/XcodeColorsOutput.swift +++ b/Sources/XcodeExport/Model/XcodeColorsOutput.swift @@ -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 } diff --git a/Sources/XcodeExport/Model/XcodeImagesOutput.swift b/Sources/XcodeExport/Model/XcodeImagesOutput.swift index 7ca86271..ac0f096d 100644 --- a/Sources/XcodeExport/Model/XcodeImagesOutput.swift +++ b/Sources/XcodeExport/Model/XcodeImagesOutput.swift @@ -5,6 +5,7 @@ public struct XcodeImagesOutput { let assetsFolderURL: URL let assetsInMainBundle: Bool + let assetsInSwiftPackage: Bool let preservesVectorRepresentation: [String]? let renderMode: XcodeRenderMode? @@ -20,6 +21,7 @@ public struct XcodeImagesOutput { public init( assetsFolderURL: URL, assetsInMainBundle: Bool, + assetsInSwiftPackage: Bool? = false, preservesVectorRepresentation: [String]? = nil, uiKitImageExtensionURL: URL? = nil, swiftUIImageExtensionURL: URL? = nil, @@ -27,6 +29,7 @@ public struct XcodeImagesOutput { self.assetsFolderURL = assetsFolderURL self.assetsInMainBundle = assetsInMainBundle + self.assetsInSwiftPackage = assetsInSwiftPackage ?? false self.preservesVectorRepresentation = preservesVectorRepresentation self.uiKitImageExtensionURL = uiKitImageExtensionURL self.swiftUIImageExtensionURL = swiftUIImageExtensionURL diff --git a/Sources/XcodeExport/XcodeColorExporter.swift b/Sources/XcodeExport/XcodeColorExporter.swift index 7e7a6f8d..abb0fbcc 100644 --- a/Sources/XcodeExport/XcodeColorExporter.swift +++ b/Sources/XcodeExport/XcodeColorExporter.swift @@ -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")) } @@ -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")) } diff --git a/Sources/XcodeExport/XcodeImagesExporterBase.swift b/Sources/XcodeExport/XcodeImagesExporterBase.swift index 87cd67ba..ef1aea03 100644 --- a/Sources/XcodeExport/XcodeImagesExporterBase.swift +++ b/Sources/XcodeExport/XcodeImagesExporterBase.swift @@ -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")) } @@ -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")) } diff --git a/Sources/XcodeExport/bundle_provider_swift_package.swift b/Sources/XcodeExport/bundle_provider_swift_package.swift new file mode 100644 index 00000000..43f95df8 --- /dev/null +++ b/Sources/XcodeExport/bundle_provider_swift_package.swift @@ -0,0 +1,7 @@ +let bundleProviderSwiftPackage = """ + +private class BundleProvider { + static let bundle = Bundle.module +} + +""" diff --git a/Tests/XcodeExportTests/XcodeColorExporterTests.swift b/Tests/XcodeExportTests/XcodeColorExporterTests.swift index a4abcdb6..c29b0d26 100644 --- a/Tests/XcodeExportTests/XcodeColorExporterTests.swift +++ b/Tests/XcodeExportTests/XcodeColorExporterTests.swift @@ -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) diff --git a/Tests/XcodeExportTests/XcodeIconsExporterTests.swift b/Tests/XcodeExportTests/XcodeIconsExporterTests.swift index f6e8dd5f..057f4fee 100644 --- a/Tests/XcodeExportTests/XcodeIconsExporterTests.swift +++ b/Tests/XcodeExportTests/XcodeIconsExporterTests.swift @@ -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)], @@ -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")!)