diff --git a/Demo/.figmagen.yml b/Demo/.figmagen.yml index e2d9fbc..72f7f09 100644 --- a/Demo/.figmagen.yml +++ b/Demo/.figmagen.yml @@ -27,6 +27,7 @@ images: assets: FigmaGenDemo/Resources/Images.xcassets/Generated destination: FigmaGenDemo/Generated/Images.swift groupByFrame: true + groupByComponentSet: true templateOptions: publicAccess: true diff --git a/Sources/FigmaGen/Commands/ImagesCommand.swift b/Sources/FigmaGen/Commands/ImagesCommand.swift index 492e5b1..32bffb8 100644 --- a/Sources/FigmaGen/Commands/ImagesCommand.swift +++ b/Sources/FigmaGen/Commands/ImagesCommand.swift @@ -152,7 +152,17 @@ final class ImagesCommand: AsyncExecutableCommand, GenerationConfigurableCommand let groupByFrame = Flag( "--groupByFrame", description: """ - Groupу generated assets and resources into folders with name of parent frame. + Group generated assets and resources into folders with name of parent frame. + By default without grouping. + """ + ) + + let groupByComponentSet = Flag( + "--groupByComponentSet", + description: """ + Group generated assets and resources into folders with name of component set. + Only for components with variants. + By default without grouping. """ ) @@ -226,6 +236,7 @@ final class ImagesCommand: AsyncExecutableCommand, GenerationConfigurableCommand useAbsoluteBounds: useAbsoluteBounds.value, preserveVectorData: preserveVectorData.value, groupByFrame: groupByFrame.value, + groupByComponentSet: groupByComponentSet.value, namingStyle: resolveNamingStyle() ) } diff --git a/Sources/FigmaGen/Generators/Images/DefaultImagesGenerator.swift b/Sources/FigmaGen/Generators/Images/DefaultImagesGenerator.swift index 9789489..7c20937 100644 --- a/Sources/FigmaGen/Generators/Images/DefaultImagesGenerator.swift +++ b/Sources/FigmaGen/Generators/Images/DefaultImagesGenerator.swift @@ -65,6 +65,7 @@ extension ImagesConfiguration { useAbsoluteBounds: useAbsoluteBounds, preserveVectorData: preserveVectorData, groupByFrame: groupByFrame, + groupByComponentSet: groupByComponentSet, namingStyle: namingStyle ) } diff --git a/Sources/FigmaGen/Models/Configuration/ImagesConfiguration.swift b/Sources/FigmaGen/Models/Configuration/ImagesConfiguration.swift index 9985ca2..be27d81 100644 --- a/Sources/FigmaGen/Models/Configuration/ImagesConfiguration.swift +++ b/Sources/FigmaGen/Models/Configuration/ImagesConfiguration.swift @@ -14,6 +14,7 @@ struct ImagesConfiguration: Decodable { case useAbsoluteBounds case preserveVectorData case groupByFrame + case groupByComponentSet case namingStyle } @@ -29,6 +30,7 @@ struct ImagesConfiguration: Decodable { let useAbsoluteBounds: Bool let preserveVectorData: Bool let groupByFrame: Bool + let groupByComponentSet: Bool let namingStyle: ImageNamingStyle // MARK: - Initializers @@ -44,6 +46,7 @@ struct ImagesConfiguration: Decodable { useAbsoluteBounds: Bool, preserveVectorData: Bool, groupByFrame: Bool, + groupByComponentSet: Bool, namingStyle: ImageNamingStyle ) { self.generatation = generatation @@ -56,6 +59,7 @@ struct ImagesConfiguration: Decodable { self.useAbsoluteBounds = useAbsoluteBounds self.preserveVectorData = preserveVectorData self.groupByFrame = groupByFrame + self.groupByComponentSet = groupByComponentSet self.namingStyle = namingStyle } @@ -72,6 +76,7 @@ struct ImagesConfiguration: Decodable { useAbsoluteBounds = try container.decodeIfPresent(forKey: .useAbsoluteBounds) ?? false preserveVectorData = try container.decodeIfPresent(forKey: .preserveVectorData) ?? false groupByFrame = try container.decodeIfPresent(forKey: .groupByFrame) ?? false + groupByComponentSet = try container.decodeIfPresent(forKey: .groupByComponentSet) ?? false namingStyle = try container.decodeIfPresent(forKey: .namingStyle) ?? .camelCase generatation = try GenerationConfiguration(from: decoder) @@ -91,6 +96,7 @@ struct ImagesConfiguration: Decodable { useAbsoluteBounds: useAbsoluteBounds, preserveVectorData: preserveVectorData, groupByFrame: groupByFrame, + groupByComponentSet: groupByComponentSet, namingStyle: namingStyle ) } diff --git a/Sources/FigmaGen/Models/Parameters/ImagesParameters.swift b/Sources/FigmaGen/Models/Parameters/ImagesParameters.swift index 4f89f4d..2080938 100644 --- a/Sources/FigmaGen/Models/Parameters/ImagesParameters.swift +++ b/Sources/FigmaGen/Models/Parameters/ImagesParameters.swift @@ -13,5 +13,6 @@ struct ImagesParameters { let useAbsoluteBounds: Bool let preserveVectorData: Bool let groupByFrame: Bool + let groupByComponentSet: Bool let namingStyle: ImageNamingStyle } diff --git a/Sources/FigmaGen/Providers/Images/Assets/DefaultImageAssetsProvider.swift b/Sources/FigmaGen/Providers/Images/Assets/DefaultImageAssetsProvider.swift index 0c9b29e..c4902a5 100644 --- a/Sources/FigmaGen/Providers/Images/Assets/DefaultImageAssetsProvider.swift +++ b/Sources/FigmaGen/Providers/Images/Assets/DefaultImageAssetsProvider.swift @@ -45,6 +45,7 @@ final class DefaultImageAssetsProvider: ImageAssetsProvider, ImagesFolderPathRes let folderPath = resolveFolderPath( groupByFrame: parameters.groupByFrame, + groupByComponentSet: parameters.groupByComponentSet, setNode: setNode, folderPath: folderPath ) @@ -113,6 +114,7 @@ final class DefaultImageAssetsProvider: ImageAssetsProvider, ImagesFolderPathRes private func saveAssetFolders( assets: [ImageComponentSetAsset: AssetFolder], groupByFrame: Bool, + groupByComponentSet: Bool, in folderPath: String ) throws -> Promise { let folderPath = Path(folderPath) @@ -124,7 +126,12 @@ final class DefaultImageAssetsProvider: ImageAssetsProvider, ImagesFolderPathRes let promises = assets.map { asset, folder in assetsProvider.saveAssetFolder( folder, - in: resolveFolderPath(groupByFrame: groupByFrame, setAsset: asset, folderPath: folderPath).string + in: resolveFolderPath( + groupByFrame: groupByFrame, + groupByComponentSet: groupByComponentSet, + setAsset: asset, + folderPath: folderPath + ).string ) } @@ -163,7 +170,12 @@ final class DefaultImageAssetsProvider: ImageAssetsProvider, ImagesFolderPathRes ) } }.then { assets in - try self.saveAssetFolders(assets: assets, groupByFrame: parameters.groupByFrame, in: folderPath) + try self.saveAssetFolders( + assets: assets, + groupByFrame: parameters.groupByFrame, + groupByComponentSet: parameters.groupByComponentSet, + in: folderPath + ) }.then { self.saveImageFiles(assets: assets) } diff --git a/Sources/FigmaGen/Providers/Images/DefaultImagesProvider.swift b/Sources/FigmaGen/Providers/Images/DefaultImagesProvider.swift index bc0097c..889dc92 100644 --- a/Sources/FigmaGen/Providers/Images/DefaultImagesProvider.swift +++ b/Sources/FigmaGen/Providers/Images/DefaultImagesProvider.swift @@ -163,19 +163,13 @@ final class DefaultImagesProvider: ImagesProvider { private func saveResourceImagesIfNeeded( nodes: [ImageComponentSetRenderedNode], - groupByFrame: Bool, - format: ImageFormat, - postProcessor: String?, - namingStyle: ImageNamingStyle, + parameters: ImagesParameters, in resources: String? ) -> Promise<[ImageRenderedNode: ImageResource]> { resources.map { folderPath in imageResourcesProvider.saveImages( nodes: nodes, - groupByFrame: groupByFrame, - format: format, - postProcessor: postProcessor, - namingStyle: namingStyle, + parameters: parameters, in: folderPath ) } ?? .value([:]) @@ -193,10 +187,7 @@ final class DefaultImagesProvider: ImagesProvider { ), self.saveResourceImagesIfNeeded( nodes: nodes, - groupByFrame: parameters.groupByFrame, - format: parameters.format, - postProcessor: parameters.postProcessor, - namingStyle: parameters.namingStyle, + parameters: parameters, in: parameters.resources ) ) diff --git a/Sources/FigmaGen/Providers/Images/ImagesFolderPathResolving.swift b/Sources/FigmaGen/Providers/Images/ImagesFolderPathResolving.swift index ca6a77e..6ce373b 100644 --- a/Sources/FigmaGen/Providers/Images/ImagesFolderPathResolving.swift +++ b/Sources/FigmaGen/Providers/Images/ImagesFolderPathResolving.swift @@ -7,6 +7,7 @@ protocol ImagesFolderPathResolving { func resolveFolderPath( groupByFrame: Bool, + groupByComponentSet: Bool, parentNodeName: String?, isSingleComponent: Bool, nodeName: String, @@ -20,6 +21,7 @@ extension ImagesFolderPathResolving { func resolveFolderPath( groupByFrame: Bool, + groupByComponentSet: Bool, parentNodeName: String?, isSingleComponent: Bool, nodeName: String, @@ -31,7 +33,7 @@ extension ImagesFolderPathResolving { folderPath = folderPath.appending(name.camelized) } - if !isSingleComponent { + if groupByComponentSet, !isSingleComponent { folderPath = folderPath.appending(nodeName.camelized) } @@ -40,11 +42,13 @@ extension ImagesFolderPathResolving { func resolveFolderPath( groupByFrame: Bool, + groupByComponentSet: Bool, setNode: ImageComponentSetRenderedNode, folderPath: Path ) -> Path { resolveFolderPath( groupByFrame: groupByFrame, + groupByComponentSet: groupByComponentSet, parentNodeName: setNode.parentName, isSingleComponent: setNode.isSingleComponent, nodeName: setNode.name, @@ -54,11 +58,13 @@ extension ImagesFolderPathResolving { func resolveFolderPath( groupByFrame: Bool, + groupByComponentSet: Bool, setAsset: ImageComponentSetAsset, folderPath: Path ) -> Path { resolveFolderPath( groupByFrame: groupByFrame, + groupByComponentSet: groupByComponentSet, parentNodeName: setAsset.parentName, isSingleComponent: setAsset.isSingleComponent, nodeName: setAsset.name, diff --git a/Sources/FigmaGen/Providers/Images/Resources/DefaultImageResourcesProvider.swift b/Sources/FigmaGen/Providers/Images/Resources/DefaultImageResourcesProvider.swift index 21bcd36..05c27e5 100644 --- a/Sources/FigmaGen/Providers/Images/Resources/DefaultImageResourcesProvider.swift +++ b/Sources/FigmaGen/Providers/Images/Resources/DefaultImageResourcesProvider.swift @@ -38,14 +38,19 @@ final class DefaultImageResourcesProvider: ImageResourcesProvider, ImagesFolderP private func makeResource( for node: ImageRenderedNode, setNode: ImageComponentSetRenderedNode, - groupByFrame: Bool, - format: ImageFormat, - namingStyle: ImageNamingStyle, + parameters: ImagesParameters, folderPath: Path ) -> ImageResource { - let fileName = resolveFileName(for: node, setNode: setNode, namingStyle: namingStyle) - let folderPath = resolveFolderPath(groupByFrame: groupByFrame, setNode: setNode, folderPath: folderPath) - let fileExtension = format.fileExtension + let fileName = resolveFileName(for: node, setNode: setNode, namingStyle: parameters.namingStyle) + + let folderPath = resolveFolderPath( + groupByFrame: parameters.groupByFrame, + groupByComponentSet: parameters.groupByComponentSet, + setNode: setNode, + folderPath: folderPath + ) + + let fileExtension = parameters.format.fileExtension let filePaths = node.urls.keys.reduce(into: [:]) { result, scale in result[scale] = folderPath @@ -58,9 +63,7 @@ final class DefaultImageResourcesProvider: ImageResourcesProvider, ImagesFolderP private func makeResources( for nodes: [ImageComponentSetRenderedNode], - groupByFrame: Bool, - format: ImageFormat, - namingStyle: ImageNamingStyle, + parameters: ImagesParameters, folderPath: Path ) -> [ImageRenderedNode: ImageResource] { var resources: [ImageRenderedNode: ImageResource] = [:] @@ -70,9 +73,7 @@ final class DefaultImageResourcesProvider: ImageResourcesProvider, ImagesFolderP resources[node] = makeResource( for: node, setNode: setNode, - groupByFrame: groupByFrame, - format: format, - namingStyle: namingStyle, + parameters: parameters, folderPath: folderPath ) } @@ -121,22 +122,17 @@ final class DefaultImageResourcesProvider: ImageResourcesProvider, ImagesFolderP func saveImages( nodes: [ImageComponentSetRenderedNode], - groupByFrame: Bool, - format: ImageFormat, - postProcessor: String?, - namingStyle: ImageNamingStyle, + parameters: ImagesParameters, in folderPath: String ) -> Promise<[ImageRenderedNode: ImageResource]> { perform(on: DispatchQueue.global(qos: .userInitiated)) { self.makeResources( for: nodes, - groupByFrame: groupByFrame, - format: format, - namingStyle: namingStyle, + parameters: parameters, folderPath: Path(folderPath) ) }.nest { resources in - try self.saveImageFiles(resources: resources, postProcessor: postProcessor, in: Path(folderPath)) + try self.saveImageFiles(resources: resources, postProcessor: parameters.postProcessor, in: Path(folderPath)) } } } diff --git a/Sources/FigmaGen/Providers/Images/Resources/ImageResourcesProvider.swift b/Sources/FigmaGen/Providers/Images/Resources/ImageResourcesProvider.swift index 6cbbd9f..6651724 100644 --- a/Sources/FigmaGen/Providers/Images/Resources/ImageResourcesProvider.swift +++ b/Sources/FigmaGen/Providers/Images/Resources/ImageResourcesProvider.swift @@ -7,10 +7,7 @@ protocol ImageResourcesProvider { func saveImages( nodes: [ImageComponentSetRenderedNode], - groupByFrame: Bool, - format: ImageFormat, - postProcessor: String?, - namingStyle: ImageNamingStyle, + parameters: ImagesParameters, in folderPath: String ) -> Promise<[ImageRenderedNode: ImageResource]> }