diff --git a/Sources/FigmaGen/Commands/GenerationConfigurableCommand.swift b/Sources/FigmaGen/Commands/GenerationConfigurableCommand.swift index 57f1a70..ba0eb43 100644 --- a/Sources/FigmaGen/Commands/GenerationConfigurableCommand.swift +++ b/Sources/FigmaGen/Commands/GenerationConfigurableCommand.swift @@ -23,13 +23,19 @@ extension GenerationConfigurableCommand { // MARK: - Instance Properties + // !!! Important note !!! + // For CLI usage of FigmaGen we don't support multiple templates for any token type. var generationConfiguration: GenerationConfiguration { GenerationConfiguration( file: resolveFileConfiguration(), accessToken: resolveAccessTokenConfiguration(), - template: template.value, - templateOptions: resolveTemplateOptions(), - destination: destination.value + templates: [ + TemplateConfiguration( + template: template.value, + templateOptions: resolveTemplateOptions(), + destination: destination.value + ) + ] ) } diff --git a/Sources/FigmaGen/Commands/TokensCommand.swift b/Sources/FigmaGen/Commands/TokensCommand.swift index 03cb874..72fd130 100644 --- a/Sources/FigmaGen/Commands/TokensCommand.swift +++ b/Sources/FigmaGen/Commands/TokensCommand.swift @@ -231,49 +231,49 @@ extension TokensCommand { accessToken: resolveAccessTokenConfiguration(), templates: TokensTemplateConfiguration( colors: [ - TokensTemplateConfiguration.Template( + TemplateConfiguration( template: colorsTemplate.value, templateOptions: resolveTemplateOptions(colorsTemplateOptions.value), destination: colorsDestination.value ) ], baseColors: [ - TokensTemplateConfiguration.Template( + TemplateConfiguration( template: baseColorsTemplate.value, templateOptions: resolveTemplateOptions(baseColorsTemplateOptions.value), destination: baseColorsDestination.value ) ], fontFamilies: [ - TokensTemplateConfiguration.Template( + TemplateConfiguration( template: fontFamiliesTemplate.value, templateOptions: resolveTemplateOptions(fontFamiliesTemplateOptions.value), destination: fontFamiliesDestination.value ) ], typographies: [ - TokensTemplateConfiguration.Template( + TemplateConfiguration( template: typographiesTemplate.value, templateOptions: resolveTemplateOptions(typographiesTemplateOptions.value), destination: typographiesDestination.value ) ], boxShadows: [ - TokensTemplateConfiguration.Template( + TemplateConfiguration( template: boxShadowsTemplate.value, templateOptions: resolveTemplateOptions(boxShadowsTemplateOptions.value), destination: boxShadowsDestination.value ) ], theme: [ - TokensTemplateConfiguration.Template( + TemplateConfiguration( template: themeTemplate.value, templateOptions: resolveTemplateOptions(themeTemplateOptions.value), destination: themeDestination.value ) ], spacing: [ - TokensTemplateConfiguration.Template( + TemplateConfiguration( template: spacingTemplate.value, templateOptions: resolveTemplateOptions(spacingTemplateOptions.value), destination: spacingDestination.value diff --git a/Sources/FigmaGen/Dependencies.swift b/Sources/FigmaGen/Dependencies.swift index 6786f0d..b75800f 100644 --- a/Sources/FigmaGen/Dependencies.swift +++ b/Sources/FigmaGen/Dependencies.swift @@ -64,9 +64,14 @@ enum Dependencies { // MARK: - static let tokensResolver: TokensResolver = DefaultTokensResolver() + static let renderParametersResolver: RenderParametersResolver = DefaultRenderParametersResolver() + static let accessTokenResolver: AccessTokenResolver = DefaultAccessTokenResolver() - static let tokensGenerationParametersResolver: TokensGenerationParametersResolver - = DefaultTokensGenerationParametersResolver() + static let tokensGenerationParametersResolver: TokensGenerationParametersResolver = + DefaultTokensGenerationParametersResolver( + renderParametersResolver: renderParametersResolver, + accessTokenResolver: accessTokenResolver + ) static let colorTokensContextProvider: ColorTokensContextProvider = DefaultColorTokensContextProvider( tokensResolver: tokensResolver @@ -108,22 +113,30 @@ enum Dependencies { static let colorStylesGenerator: ColorStylesGenerator = DefaultColorStylesGenerator( colorStylesProvider: colorStylesProvider, - templateRenderer: templateRenderer + templateRenderer: templateRenderer, + accessTokenResolver: accessTokenResolver, + renderParametersResolver: renderParametersResolver ) static let textStylesGenerator: TextStylesGenerator = DefaultTextStylesGenerator( textStylesProvider: textStylesProvider, - templateRenderer: templateRenderer + templateRenderer: templateRenderer, + accessTokenResolver: accessTokenResolver, + renderParametersResolver: renderParametersResolver ) static let imagesGenerator: ImagesGenerator = DefaultImagesGenerator( imagesProvider: imagesProvider, - templateRenderer: templateRenderer + templateRenderer: templateRenderer, + accessTokenResolver: accessTokenResolver, + renderParametersResolver: renderParametersResolver ) static let shadowStylesGenerator: ShadowStylesGenerator = DefaultShadowStylesGenerator( shadowStylesProvider: shadowStylesProvider, - templateRenderer: templateRenderer + templateRenderer: templateRenderer, + accessTokenResolver: accessTokenResolver, + renderParametersResolver: renderParametersResolver ) static let colorTokensGenerator: ColorTokensGenerator = DefaultColorTokensGenerator( diff --git a/Sources/FigmaGen/Generators/ColorStyles/DefaultColorStylesGenerator.swift b/Sources/FigmaGen/Generators/ColorStyles/DefaultColorStylesGenerator.swift index 9189248..032cfb0 100644 --- a/Sources/FigmaGen/Generators/ColorStyles/DefaultColorStylesGenerator.swift +++ b/Sources/FigmaGen/Generators/ColorStyles/DefaultColorStylesGenerator.swift @@ -8,22 +8,31 @@ final class DefaultColorStylesGenerator: ColorStylesGenerator, GenerationParamet let colorStylesProvider: ColorStylesProvider let templateRenderer: TemplateRenderer + let accessTokenResolver: AccessTokenResolver + let renderParametersResolver: RenderParametersResolver let defaultTemplateType = RenderTemplateType.native(name: "ColorStyles") let defaultDestination = RenderDestination.console // MARK: - Initializers - init(colorStylesProvider: ColorStylesProvider, templateRenderer: TemplateRenderer) { + init( + colorStylesProvider: ColorStylesProvider, + templateRenderer: TemplateRenderer, + accessTokenResolver: AccessTokenResolver, + renderParametersResolver: RenderParametersResolver + ) { self.colorStylesProvider = colorStylesProvider self.templateRenderer = templateRenderer + self.accessTokenResolver = accessTokenResolver + self.renderParametersResolver = renderParametersResolver } // MARK: - Instance Methods private func generate(parameters: GenerationParameters, assets: String?) -> Promise { firstly { - self.colorStylesProvider.fetchColorStyles( + colorStylesProvider.fetchColorStyles( from: parameters.file, nodes: parameters.nodes, assets: assets @@ -31,11 +40,13 @@ final class DefaultColorStylesGenerator: ColorStylesGenerator, GenerationParamet }.map { colorStyles in ColorStylesContext(colorStyles: colorStyles) }.done { context in - try self.templateRenderer.renderTemplate( - parameters.render.template, - to: parameters.render.destination, - context: context - ) + try parameters.renderParameters.forEach { params in + try self.templateRenderer.renderTemplate( + params.template, + to: params.destination, + context: context + ) + } } } diff --git a/Sources/FigmaGen/Generators/GenerationParametersResolving.swift b/Sources/FigmaGen/Generators/GenerationParametersResolving.swift index d7974e5..2f0b10e 100644 --- a/Sources/FigmaGen/Generators/GenerationParametersResolving.swift +++ b/Sources/FigmaGen/Generators/GenerationParametersResolving.swift @@ -4,6 +4,11 @@ protocol GenerationParametersResolving { // MARK: - Instance Properties + var accessTokenResolver: AccessTokenResolver { get } + var renderParametersResolver: RenderParametersResolver { get } + + // MARK: - Instance Properties + var defaultTemplateType: RenderTemplateType { get } var defaultDestination: RenderDestination { get } @@ -14,37 +19,6 @@ protocol GenerationParametersResolving { extension GenerationParametersResolving { - // MARK: - Instance Methods - - private func resolveAccessToken(configuration: GenerationConfiguration) -> String? { - switch configuration.accessToken { - case let .value(accessToken): - return accessToken - - case let .environmentVariable(environmentVariable): - return ProcessInfo.processInfo.environment[environmentVariable] - - case nil: - return nil - } - } - - private func resolveTemplateType(configuration: GenerationConfiguration) -> RenderTemplateType { - if let templatePath = configuration.template { - return .custom(path: templatePath) - } - - return defaultTemplateType - } - - private func resolveDestination(configuration: GenerationConfiguration) -> RenderDestination { - if let destinationPath = configuration.destination { - return .file(path: destinationPath) - } - - return defaultDestination - } - // MARK: - func resolveGenerationParameters(from configuration: GenerationConfiguration) throws -> GenerationParameters { @@ -52,7 +26,9 @@ extension GenerationParametersResolving { throw GenerationParametersError.invalidFileConfiguration } - guard let accessToken = resolveAccessToken(configuration: configuration), !accessToken.isEmpty else { + let accessToken = accessTokenResolver.resolveAccessToken(from: configuration.accessToken) + + guard let accessToken, !accessToken.isEmpty else { throw GenerationParametersError.invalidAccessToken } @@ -67,16 +43,16 @@ extension GenerationParametersResolving { excludedIDs: fileConfiguration.excludedNodes ) - let templateType = resolveTemplateType(configuration: configuration) - let destination = resolveDestination(configuration: configuration) - - let template = RenderTemplate( - type: templateType, - options: configuration.templateOptions ?? [:] + let renderParametersList = renderParametersResolver.resolveRenderParameters( + templates: configuration.templates, + defaultTemplateType: defaultTemplateType, + defaultDestination: defaultDestination ) - let render = RenderParameters(template: template, destination: destination) - - return GenerationParameters(file: file, nodes: nodes, render: render) + return GenerationParameters( + file: file, + nodes: nodes, + renderParameters: renderParametersList + ) } } diff --git a/Sources/FigmaGen/Generators/Images/DefaultImagesGenerator.swift b/Sources/FigmaGen/Generators/Images/DefaultImagesGenerator.swift index ec8a4e2..7a6673d 100644 --- a/Sources/FigmaGen/Generators/Images/DefaultImagesGenerator.swift +++ b/Sources/FigmaGen/Generators/Images/DefaultImagesGenerator.swift @@ -8,15 +8,24 @@ final class DefaultImagesGenerator: ImagesGenerator, GenerationParametersResolvi let imagesProvider: ImagesProvider let templateRenderer: TemplateRenderer + let accessTokenResolver: AccessTokenResolver + let renderParametersResolver: RenderParametersResolver let defaultTemplateType = RenderTemplateType.native(name: "Images") let defaultDestination = RenderDestination.console // MARK: - Initializers - init(imagesProvider: ImagesProvider, templateRenderer: TemplateRenderer) { + init( + imagesProvider: ImagesProvider, + templateRenderer: TemplateRenderer, + accessTokenResolver: AccessTokenResolver, + renderParametersResolver: RenderParametersResolver + ) { self.imagesProvider = imagesProvider self.templateRenderer = templateRenderer + self.accessTokenResolver = accessTokenResolver + self.renderParametersResolver = renderParametersResolver } // MARK: - Instance Methods @@ -33,11 +42,13 @@ final class DefaultImagesGenerator: ImagesGenerator, GenerationParametersResolvi imageSets: imageSets.sorted { $0.name.lowercased() < $1.name.lowercased() } ) }.done { context in - try self.templateRenderer.renderTemplate( - parameters.render.template, - to: parameters.render.destination, - context: context - ) + try parameters.renderParameters.forEach { params in + try self.templateRenderer.renderTemplate( + params.template, + to: params.destination, + context: context + ) + } } } diff --git a/Sources/FigmaGen/Generators/ShadowStyles/DefaultShadowStylesGenerator.swift b/Sources/FigmaGen/Generators/ShadowStyles/DefaultShadowStylesGenerator.swift index 18b9551..0d67c66 100644 --- a/Sources/FigmaGen/Generators/ShadowStyles/DefaultShadowStylesGenerator.swift +++ b/Sources/FigmaGen/Generators/ShadowStyles/DefaultShadowStylesGenerator.swift @@ -8,15 +8,24 @@ final class DefaultShadowStylesGenerator: ShadowStylesGenerator, GenerationParam let shadowStylesProvider: ShadowStylesProvider let templateRenderer: TemplateRenderer + let accessTokenResolver: AccessTokenResolver + let renderParametersResolver: RenderParametersResolver let defaultTemplateType: RenderTemplateType = .native(name: "ShadowStyles") let defaultDestination: RenderDestination = .console // MARK: - Initializers - init(shadowStylesProvider: ShadowStylesProvider, templateRenderer: TemplateRenderer) { + init( + shadowStylesProvider: ShadowStylesProvider, + templateRenderer: TemplateRenderer, + accessTokenResolver: AccessTokenResolver, + renderParametersResolver: RenderParametersResolver + ) { self.shadowStylesProvider = shadowStylesProvider self.templateRenderer = templateRenderer + self.accessTokenResolver = accessTokenResolver + self.renderParametersResolver = renderParametersResolver } // MARK: - Instance Methods @@ -27,11 +36,13 @@ final class DefaultShadowStylesGenerator: ShadowStylesGenerator, GenerationParam }.map { shadowStyles in ShadowStylesContext(shadowStyles: shadowStyles) }.done { context in - try self.templateRenderer.renderTemplate( - parameters.render.template, - to: parameters.render.destination, - context: context - ) + try parameters.renderParameters.forEach { params in + try self.templateRenderer.renderTemplate( + params.template, + to: params.destination, + context: context + ) + } } } diff --git a/Sources/FigmaGen/Generators/TextStyles/DefaultTextStylesGenerator.swift b/Sources/FigmaGen/Generators/TextStyles/DefaultTextStylesGenerator.swift index d3d4ca3..86430aa 100644 --- a/Sources/FigmaGen/Generators/TextStyles/DefaultTextStylesGenerator.swift +++ b/Sources/FigmaGen/Generators/TextStyles/DefaultTextStylesGenerator.swift @@ -8,15 +8,24 @@ final class DefaultTextStylesGenerator: TextStylesGenerator, GenerationParameter let textStylesProvider: TextStylesProvider let templateRenderer: TemplateRenderer + let accessTokenResolver: AccessTokenResolver + let renderParametersResolver: RenderParametersResolver let defaultTemplateType = RenderTemplateType.native(name: "TextStyles") let defaultDestination = RenderDestination.console // MARK: - Initializers - init(textStylesProvider: TextStylesProvider, templateRenderer: TemplateRenderer) { + init( + textStylesProvider: TextStylesProvider, + templateRenderer: TemplateRenderer, + accessTokenResolver: AccessTokenResolver, + renderParametersResolver: RenderParametersResolver + ) { self.textStylesProvider = textStylesProvider self.templateRenderer = templateRenderer + self.accessTokenResolver = accessTokenResolver + self.renderParametersResolver = renderParametersResolver } // MARK: - Instance Methods @@ -27,11 +36,13 @@ final class DefaultTextStylesGenerator: TextStylesGenerator, GenerationParameter }.map { textStyles in TextStylesContext(textStyles: textStyles) }.done { context in - try self.templateRenderer.renderTemplate( - parameters.render.template, - to: parameters.render.destination, - context: context - ) + try parameters.renderParameters.forEach { params in + try self.templateRenderer.renderTemplate( + params.template, + to: params.destination, + context: context + ) + } } } diff --git a/Sources/FigmaGen/Generators/Tokens/GenerationParametersResolver/DefaultTokensGenerationParametersResolver.swift b/Sources/FigmaGen/Generators/Tokens/GenerationParametersResolver/DefaultTokensGenerationParametersResolver.swift index e01a7d3..9646f74 100644 --- a/Sources/FigmaGen/Generators/Tokens/GenerationParametersResolver/DefaultTokensGenerationParametersResolver.swift +++ b/Sources/FigmaGen/Generators/Tokens/GenerationParametersResolver/DefaultTokensGenerationParametersResolver.swift @@ -2,63 +2,19 @@ import Foundation final class DefaultTokensGenerationParametersResolver: TokensGenerationParametersResolver { - // MARK: - Instance Methods + // MARK: - Instance Properties - private func resolveAccessToken(configuration: TokensConfiguration) -> String? { - switch configuration.accessToken { - case let .value(accessToken): - return accessToken + let renderParametersResolver: RenderParametersResolver + let accessTokenResolver: AccessTokenResolver - case let .environmentVariable(environmentVariable): - return ProcessInfo.processInfo.environment[environmentVariable] + // MARK: - Initializers - case nil: - return nil - } - } - - private func resolveTemplateType( - template: TokensTemplateConfiguration.Template, - nativeTemplateName: String - ) -> RenderTemplateType { - if let templatePath = template.template { - return .custom(path: templatePath) - } - - return .native(name: nativeTemplateName) - } - - private func resolveDestination(template: TokensTemplateConfiguration.Template) -> RenderDestination { - if let destinationPath = template.destination { - return .file(path: destinationPath) - } - - return .console - } - - private func resolveRenderParameters( - templates: [TokensTemplateConfiguration.Template]?, - nativeTemplateName: String - ) -> [RenderParameters]? { - guard let templateConfigurations = templates else { - return nil - } - - return templateConfigurations.map { template -> RenderParameters in - let templateType = resolveTemplateType( - template: template, - nativeTemplateName: nativeTemplateName - ) - - let destination = resolveDestination(template: template) - - let template = RenderTemplate( - type: templateType, - options: template.templateOptions ?? [:] - ) - - return RenderParameters(template: template, destination: destination) - } + init( + renderParametersResolver: RenderParametersResolver, + accessTokenResolver: AccessTokenResolver + ) { + self.renderParametersResolver = renderParametersResolver + self.accessTokenResolver = accessTokenResolver } // MARK: - @@ -69,7 +25,7 @@ final class DefaultTokensGenerationParametersResolver: TokensGenerationParameter throw GenerationParametersError.invalidFileConfiguration } - guard let accessToken = resolveAccessToken(configuration: configuration) else { + guard let accessToken = accessTokenResolver.resolveAccessToken(from: configuration.accessToken) else { throw GenerationParametersError.invalidAccessToken } @@ -79,39 +35,39 @@ final class DefaultTokensGenerationParametersResolver: TokensGenerationParameter accessToken: accessToken ) - let colorRenderParameters = resolveRenderParameters( + let colorRenderParameters = renderParametersResolver.resolveRenderParameters( templates: configuration.templates?.colors, - nativeTemplateName: "ColorTokens" + defaultTemplateType: .native(name: "ColorTokens") ) - let baseColorRenderParameters = resolveRenderParameters( + let baseColorRenderParameters = renderParametersResolver.resolveRenderParameters( templates: configuration.templates?.baseColors, - nativeTemplateName: "BaseColorTokens" + defaultTemplateType: .native(name: "BaseColorTokens") ) - let fontFamilyRenderParameters = resolveRenderParameters( + let fontFamilyRenderParameters = renderParametersResolver.resolveRenderParameters( templates: configuration.templates?.fontFamilies, - nativeTemplateName: "FontFamilyTokens" + defaultTemplateType: .native(name: "FontFamilyTokens") ) - let typographyRenderParameters = resolveRenderParameters( + let typographyRenderParameters = renderParametersResolver.resolveRenderParameters( templates: configuration.templates?.typographies, - nativeTemplateName: "TypographyTokens" + defaultTemplateType: .native(name: "TypographyTokens") ) - let boxShadowRenderParameters = resolveRenderParameters( + let boxShadowRenderParameters = renderParametersResolver.resolveRenderParameters( templates: configuration.templates?.boxShadows, - nativeTemplateName: "BoxShadowTokens" + defaultTemplateType: .native(name: "BoxShadowTokens") ) - let themeRenderParameters = resolveRenderParameters( + let themeRenderParameters = renderParametersResolver.resolveRenderParameters( templates: configuration.templates?.theme, - nativeTemplateName: "Theme" + defaultTemplateType: .native(name: "Theme") ) - let spacingRenderParameters = resolveRenderParameters( + let spacingRenderParameters = renderParametersResolver.resolveRenderParameters( templates: configuration.templates?.spacing, - nativeTemplateName: "SpacingTokens" + defaultTemplateType: .native(name: "SpacingTokens") ) return TokensGenerationParameters( diff --git a/Sources/FigmaGen/Models/Configuration/GenerationConfiguration.swift b/Sources/FigmaGen/Models/Configuration/GenerationConfiguration.swift index 126e804..6be0f9f 100644 --- a/Sources/FigmaGen/Models/Configuration/GenerationConfiguration.swift +++ b/Sources/FigmaGen/Models/Configuration/GenerationConfiguration.swift @@ -8,33 +8,25 @@ struct GenerationConfiguration: Decodable { private enum CodingKeys: String, CodingKey { case file case accessToken - case template - case templateOptions - case destination + case templates } // MARK: - Instance Properties let file: FileConfiguration? let accessToken: AccessTokenConfiguration? - let template: String? - let templateOptions: [String: Any]? - let destination: String? + let templates: [TemplateConfiguration]? // MARK: - Initializers init( file: FileConfiguration?, accessToken: AccessTokenConfiguration?, - template: String?, - templateOptions: [String: Any]?, - destination: String? + templates: [TemplateConfiguration]? ) { self.file = file self.accessToken = accessToken - self.template = template - self.templateOptions = templateOptions - self.destination = destination + self.templates = templates } init(from decoder: Decoder) throws { @@ -45,13 +37,7 @@ struct GenerationConfiguration: Decodable { let container = try decoder.container(keyedBy: CodingKeys.self) - template = try container.decodeIfPresent(forKey: .template) - - templateOptions = try container - .decodeIfPresent([String: AnyCodable].self, forKey: .templateOptions)? - .mapValues { $0.value } - - destination = try container.decodeIfPresent(forKey: .destination) + templates = try container.decodeIfPresent(TemplateConfigurationWrapper.self, forKey: .templates)?.templates } // MARK: - Instance Methods @@ -64,9 +50,7 @@ struct GenerationConfiguration: Decodable { return Self( file: file ?? base.file, accessToken: accessToken ?? base.accessToken, - template: template, - templateOptions: templateOptions, - destination: destination + templates: templates ) } } diff --git a/Sources/FigmaGen/Models/Configuration/Templates/TemplateConfiguration.swift b/Sources/FigmaGen/Models/Configuration/Templates/TemplateConfiguration.swift new file mode 100644 index 0000000..1e0a454 --- /dev/null +++ b/Sources/FigmaGen/Models/Configuration/Templates/TemplateConfiguration.swift @@ -0,0 +1,50 @@ +import Foundation +import FigmaGenTools + +struct TemplateConfiguration { + + // MARK: - Instance Properties + + let template: String? + let templateOptions: [String: Any]? + let destination: String? + + // MARK: - Initializers + + init( + template: String?, + templateOptions: [String: Any]?, + destination: String? + ) { + self.template = template + self.templateOptions = templateOptions + self.destination = destination + } +} + +// MARK: - Decodable + +extension TemplateConfiguration: Decodable { + + // MARK: - Nested Types + + private enum CodingKeys: String, CodingKey { + case template + case templateOptions + case destination + } + + // MARK: - Initializers + + init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + + self.template = try container.decodeIfPresent(forKey: .template) + + self.templateOptions = try container + .decodeIfPresent([String: AnyCodable].self, forKey: .templateOptions)? + .mapValues { $0.value } + + self.destination = try container.decodeIfPresent(forKey: .destination) + } +} diff --git a/Sources/FigmaGen/Models/Configuration/Templates/TemplateConfigurationWrapper.swift b/Sources/FigmaGen/Models/Configuration/Templates/TemplateConfigurationWrapper.swift new file mode 100644 index 0000000..aeb54f1 --- /dev/null +++ b/Sources/FigmaGen/Models/Configuration/Templates/TemplateConfigurationWrapper.swift @@ -0,0 +1,22 @@ +import Foundation + +struct TemplateConfigurationWrapper: Decodable { + + // MARK: - Instance Properties + + let templates: [TemplateConfiguration]? + + // MARK: - Initializers + + init(from decoder: Decoder) throws { + let container = try decoder.singleValueContainer() + + if container.decodeNil() { + self.templates = nil + } else if let singleValue = try? container.decode(TemplateConfiguration.self) { + self.templates = [singleValue] + } else { + self.templates = try container.decode([TemplateConfiguration].self) + } + } +} diff --git a/Sources/FigmaGen/Models/Configuration/Tokens/TokensTemplateConfiguration.swift b/Sources/FigmaGen/Models/Configuration/Tokens/TokensTemplateConfiguration.swift index 161d242..a267946 100644 --- a/Sources/FigmaGen/Models/Configuration/Tokens/TokensTemplateConfiguration.swift +++ b/Sources/FigmaGen/Models/Configuration/Tokens/TokensTemplateConfiguration.swift @@ -3,38 +3,15 @@ import FigmaGenTools struct TokensTemplateConfiguration { - // MARK: - Nested Types - - struct Template { - - // MARK: - Instance Properties - - let template: String? - let templateOptions: [String: Any]? - let destination: String? - - // MARK: - Initializers - - init( - template: String?, - templateOptions: [String: Any]?, - destination: String? - ) { - self.template = template - self.templateOptions = templateOptions - self.destination = destination - } - } - // MARK: - Instance Properties - let colors: [Template]? - let baseColors: [Template]? - let fontFamilies: [Template]? - let typographies: [Template]? - let boxShadows: [Template]? - let theme: [Template]? - let spacing: [Template]? + let colors: [TemplateConfiguration]? + let baseColors: [TemplateConfiguration]? + let fontFamilies: [TemplateConfiguration]? + let typographies: [TemplateConfiguration]? + let boxShadows: [TemplateConfiguration]? + let theme: [TemplateConfiguration]? + let spacing: [TemplateConfiguration]? } // MARK: - Decodable @@ -53,65 +30,23 @@ extension TokensTemplateConfiguration: Decodable { case spacing } - private struct TemplateWrapper: Decodable { - - // MARK: - Instance Properties - - let templates: [Template]? - - // MARK: - Initializers - - init(from decoder: Decoder) throws { - let container = try decoder.singleValueContainer() - - if container.decodeNil() { - self.templates = nil - } else if let singleValue = try? container.decode(Template.self) { - self.templates = [singleValue] - } else { - self.templates = try container.decode([Template].self) - } - } - } - - // MARK: - Initializers - - init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - - self.colors = try container.decodeIfPresent(TemplateWrapper.self, forKey: .colors)?.templates - self.baseColors = try container.decodeIfPresent(TemplateWrapper.self, forKey: .baseColors)?.templates - self.fontFamilies = try container.decodeIfPresent(TemplateWrapper.self, forKey: .fontFamilies)?.templates - self.typographies = try container.decodeIfPresent(TemplateWrapper.self, forKey: .typographies)?.templates - self.boxShadows = try container.decodeIfPresent(TemplateWrapper.self, forKey: .boxShadows)?.templates - self.theme = try container.decodeIfPresent(TemplateWrapper.self, forKey: .theme)?.templates - self.spacing = try container.decodeIfPresent(TemplateWrapper.self, forKey: .spacing)?.templates - } -} - -// MARK: - - -extension TokensTemplateConfiguration.Template: Decodable { - - // MARK: - Nested Types - - private enum CodingKeys: String, CodingKey { - case template - case templateOptions - case destination - } - // MARK: - Initializers init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) - self.template = try container.decodeIfPresent(forKey: .template) - - self.templateOptions = try container - .decodeIfPresent([String: AnyCodable].self, forKey: .templateOptions)? - .mapValues { $0.value } - - self.destination = try container.decodeIfPresent(forKey: .destination) + colors = try container.decodeIfPresent(TemplateConfigurationWrapper.self, forKey: .colors)?.templates + baseColors = try container.decodeIfPresent(TemplateConfigurationWrapper.self, forKey: .baseColors)?.templates + fontFamilies = try container.decodeIfPresent( + TemplateConfigurationWrapper.self, + forKey: .fontFamilies + )?.templates + typographies = try container.decodeIfPresent( + TemplateConfigurationWrapper.self, + forKey: .typographies + )?.templates + boxShadows = try container.decodeIfPresent(TemplateConfigurationWrapper.self, forKey: .boxShadows)?.templates + theme = try container.decodeIfPresent(TemplateConfigurationWrapper.self, forKey: .theme)?.templates + spacing = try container.decodeIfPresent(TemplateConfigurationWrapper.self, forKey: .spacing)?.templates } } diff --git a/Sources/FigmaGen/Models/Parameters/GenerationParameters.swift b/Sources/FigmaGen/Models/Parameters/GenerationParameters.swift index 624b681..da69557 100644 --- a/Sources/FigmaGen/Models/Parameters/GenerationParameters.swift +++ b/Sources/FigmaGen/Models/Parameters/GenerationParameters.swift @@ -6,5 +6,5 @@ struct GenerationParameters { let file: FileParameters let nodes: NodesParameters - let render: RenderParameters + let renderParameters: [RenderParameters] } diff --git a/Sources/FigmaGen/Resolvers/AccessToken/AccessTokenResolver.swift b/Sources/FigmaGen/Resolvers/AccessToken/AccessTokenResolver.swift new file mode 100644 index 0000000..2a7a71b --- /dev/null +++ b/Sources/FigmaGen/Resolvers/AccessToken/AccessTokenResolver.swift @@ -0,0 +1,6 @@ +import Foundation + +protocol AccessTokenResolver { + + func resolveAccessToken(from configuration: AccessTokenConfiguration?) -> String? +} diff --git a/Sources/FigmaGen/Resolvers/AccessToken/DefaultAccessTokenResolver.swift b/Sources/FigmaGen/Resolvers/AccessToken/DefaultAccessTokenResolver.swift new file mode 100644 index 0000000..9b167ab --- /dev/null +++ b/Sources/FigmaGen/Resolvers/AccessToken/DefaultAccessTokenResolver.swift @@ -0,0 +1,17 @@ +import Foundation + +final class DefaultAccessTokenResolver: AccessTokenResolver { + + func resolveAccessToken(from configuration: AccessTokenConfiguration?) -> String? { + switch configuration { + case let .value(accessToken): + return accessToken + + case let .environmentVariable(environmentVariable): + return ProcessInfo.processInfo.environment[environmentVariable] + + case nil: + return nil + } + } +} diff --git a/Sources/FigmaGen/Resolvers/RenderParameters/DefaultRenderParametersResolver.swift b/Sources/FigmaGen/Resolvers/RenderParameters/DefaultRenderParametersResolver.swift new file mode 100644 index 0000000..f3ac399 --- /dev/null +++ b/Sources/FigmaGen/Resolvers/RenderParameters/DefaultRenderParametersResolver.swift @@ -0,0 +1,65 @@ +import Foundation + +final class DefaultRenderParametersResolver: RenderParametersResolver { + + // MARK: - Instance Methods + + private func resolveTemplateType( + template: TemplateConfiguration, + defaultTemplateType: RenderTemplateType + ) -> RenderTemplateType { + if let templatePath = template.template { + return .custom(path: templatePath) + } + + return defaultTemplateType + } + + private func resolveDestination( + template: TemplateConfiguration, + defaultDestination: RenderDestination + ) -> RenderDestination { + if let destinationPath = template.destination { + return .file(path: destinationPath) + } + + return defaultDestination + } + + func resolveRenderParameters( + templates: [TemplateConfiguration]?, + defaultTemplateType: RenderTemplateType, + defaultDestination: RenderDestination + ) -> [RenderParameters] { + let defaultRenderParameters = RenderParameters( + template: RenderTemplate( + type: defaultTemplateType, + options: [:] + ), + destination: defaultDestination + ) + + guard let templates else { + return [defaultRenderParameters] + } + + return templates.map { template in + let templateType = resolveTemplateType( + template: template, + defaultTemplateType: defaultTemplateType + ) + + let destination = resolveDestination( + template: template, + defaultDestination: defaultDestination + ) + + let template = RenderTemplate( + type: templateType, + options: template.templateOptions ?? [:] + ) + + return RenderParameters(template: template, destination: destination) + } + } +} diff --git a/Sources/FigmaGen/Resolvers/RenderParameters/RenderParametersResolver.swift b/Sources/FigmaGen/Resolvers/RenderParameters/RenderParametersResolver.swift new file mode 100644 index 0000000..7bdc90a --- /dev/null +++ b/Sources/FigmaGen/Resolvers/RenderParameters/RenderParametersResolver.swift @@ -0,0 +1,24 @@ +import Foundation + +protocol RenderParametersResolver { + + func resolveRenderParameters( + templates: [TemplateConfiguration]?, + defaultTemplateType: RenderTemplateType, + defaultDestination: RenderDestination + ) -> [RenderParameters] +} + +extension RenderParametersResolver { + + func resolveRenderParameters( + templates: [TemplateConfiguration]?, + defaultTemplateType: RenderTemplateType + ) -> [RenderParameters] { + resolveRenderParameters( + templates: templates, + defaultTemplateType: defaultTemplateType, + defaultDestination: .console + ) + } +}