diff --git a/CONFIG.md b/CONFIG.md index 28cf7045..62bd4975 100644 --- a/CONFIG.md +++ b/CONFIG.md @@ -30,6 +30,8 @@ common: nameValidateRegexp: '^([a-zA-Z_]+)$' # RegExp pattern for: background, background_primary, widget_primary_background # [optional] RegExp pattern for replacing. Supports only $n nameReplaceRegexp: 'color_$1' + # [optional] List of color names to exclude from export. Supports wildcard patterns, for example: ["background", "background/*"] + exclude: [] # [optional] Extract light and dark mode colors from the lightFileId specified in the figma params. Defaults to false useSingleFile: true # [optional] If useSingleFile is true, customize the suffix to denote a dark mode color. Defaults to '_dark' @@ -58,6 +60,8 @@ common: nameValidateRegexp: '^([a-zA-Z_]+)$' # [optional] RegExp pattern for replacing. Supports only $n nameReplaceRegexp: 'color_$1' + # [optional] List of variable names to exclude from export. Supports wildcard patterns, for example: ["background", "background/*"] + exclude: [] # [optional] icons: # [optional] Name of the Figma's frame where icons components are located diff --git a/README.md b/README.md index f4e1527c..84fd1854 100644 --- a/README.md +++ b/README.md @@ -407,6 +407,8 @@ If you want to export specific colors/icons/images you can list their names in t `./figma-export colors` — Exports all the colors. +If you need to export all colors except a few, use `common.colors.exclude` or `common.variablesColors.exclude` in `figma-export.yaml`. + ⚠️ Wildcard doesn't work on Linux. Argument `-i` or `-input` specifies path to FigmaExport configuration file `figma-export.yaml`. diff --git a/Sources/FigmaExport/Input/Params.swift b/Sources/FigmaExport/Input/Params.swift index 451180fd..fda4eec0 100644 --- a/Sources/FigmaExport/Input/Params.swift +++ b/Sources/FigmaExport/Input/Params.swift @@ -17,6 +17,7 @@ struct Params: Decodable { struct Colors: Decodable { let nameValidateRegexp: String? let nameReplaceRegexp: String? + let exclude: [String]? let useSingleFile: Bool? let darkModeSuffix: String? let lightHCModeSuffix: String? @@ -36,6 +37,7 @@ struct Params: Decodable { let nameValidateRegexp: String? let nameReplaceRegexp: String? + let exclude: [String]? } struct Icons: Decodable { diff --git a/Sources/FigmaExport/Loaders/Colors/ColorsLoader.swift b/Sources/FigmaExport/Loaders/Colors/ColorsLoader.swift index 3a26558b..42f4c78a 100644 --- a/Sources/FigmaExport/Loaders/Colors/ColorsLoader.swift +++ b/Sources/FigmaExport/Loaders/Colors/ColorsLoader.swift @@ -10,6 +10,7 @@ final class ColorsLoader { private let figmaParams: Params.Figma private let colorParams: Params.Common.Colors? private let filter: String? + private let excludeFilter: AssetsFilter? init( client: Client, @@ -21,6 +22,11 @@ final class ColorsLoader { self.figmaParams = figmaParams self.colorParams = colorParams self.filter = filter + if let excludes = colorParams?.exclude, !excludes.isEmpty { + excludeFilter = AssetsFilter(filters: excludes) + } else { + excludeFilter = nil + } } func load() throws -> ColorsLoaderOutput { @@ -77,7 +83,13 @@ final class ColorsLoader { assetsFilter.match(name: style.name) } } - + + if let excludeFilter { + styles = styles.filter { style -> Bool in + !excludeFilter.match(name: style.name) + } + } + guard !styles.isEmpty else { throw FigmaExportError.stylesNotFound } diff --git a/Sources/FigmaExport/Loaders/Colors/ColorsVariablesLoader.swift b/Sources/FigmaExport/Loaders/Colors/ColorsVariablesLoader.swift index 2b2e4c63..80d1e0a2 100644 --- a/Sources/FigmaExport/Loaders/Colors/ColorsVariablesLoader.swift +++ b/Sources/FigmaExport/Loaders/Colors/ColorsVariablesLoader.swift @@ -6,6 +6,7 @@ final class ColorsVariablesLoader { private let client: Client private let variableParams: Params.Common.VariablesColors? private let filter: String? + private let excludeFilter: AssetsFilter? init( client: Client, @@ -16,6 +17,11 @@ final class ColorsVariablesLoader { self.client = client self.variableParams = variableParams self.filter = filter + if let excludes = variableParams?.exclude, !excludes.isEmpty { + excludeFilter = AssetsFilter(filters: excludes) + } else { + excludeFilter = nil + } } func load() throws -> ColorsLoaderOutput { @@ -136,9 +142,18 @@ final class ColorsVariablesLoader { } private func doesColorMatchFilter(from variable: Variable) -> Bool { - guard let filter = filter else { return true } - let assetsFilter = AssetsFilter(filter: filter) - return assetsFilter.match(name: variable.name) + if let filter { + let assetsFilter = AssetsFilter(filter: filter) + guard assetsFilter.match(name: variable.name) else { + return false + } + } + + if let excludeFilter, excludeFilter.match(name: variable.name) { + return false + } + + return true } private func createColor(from variable: Variable, color: PaintColor) -> Color { diff --git a/Sources/FigmaExport/Resources/androidConfig.swift b/Sources/FigmaExport/Resources/androidConfig.swift index 22855728..5b0248b7 100644 --- a/Sources/FigmaExport/Resources/androidConfig.swift +++ b/Sources/FigmaExport/Resources/androidConfig.swift @@ -16,6 +16,8 @@ common: nameValidateRegexp: '^([a-zA-Z_]+)$' # RegExp pattern for: background, background_primary, widget_primary_background # [optional] RegExp pattern for replacing. Supports only $n nameReplaceRegexp: 'color_$1' + # [optional] List of color names to exclude from export. Supports wildcard patterns, for example: ["background", "background/*"] + exclude: [] # [optional] Extract light and dark mode colors from the lightFileId specified in the figma params. Defaults to false useSingleFile: false # [optional] If useSingleFile is true, customize the suffix to denote a dark mode color. Defaults to '_dark' diff --git a/Sources/FigmaExport/Resources/iOSConfig.swift b/Sources/FigmaExport/Resources/iOSConfig.swift index 9be52333..a50643cc 100644 --- a/Sources/FigmaExport/Resources/iOSConfig.swift +++ b/Sources/FigmaExport/Resources/iOSConfig.swift @@ -16,6 +16,8 @@ common: nameValidateRegexp: '^([a-zA-Z_]+)$' # RegExp pattern for: background, background_primary, widget_primary_background # [optional] RegExp pattern for replacing. Supports only $n nameReplaceRegexp: 'color_$1' + # [optional] List of color names to exclude from export. Supports wildcard patterns, for example: ["background", "background/*"] + exclude: [] # [optional] Extract light and dark mode colors from the lightFileId specified in the figma params. Defaults to false useSingleFile: false # [optional] If useSingleFile is true, customize the suffix to denote a dark mode color. Defaults to '_dark' diff --git a/Tests/FigmaExportTests/ParamsDecodingTests.swift b/Tests/FigmaExportTests/ParamsDecodingTests.swift new file mode 100644 index 00000000..cba11416 --- /dev/null +++ b/Tests/FigmaExportTests/ParamsDecodingTests.swift @@ -0,0 +1,56 @@ +import XCTest +import Yams +@testable import FigmaExport + +final class ParamsDecodingTests: XCTestCase { + + func testDecodeColorsExcludeList() throws { + let yaml = """ + figma: + lightFileId: file_id + common: + colors: + exclude: + - background + - background/* + """ + + let params = try YAMLDecoder().decode(Params.self, from: yaml) + + XCTAssertEqual(params.common?.colors?.exclude, ["background", "background/*"]) + } + + func testDecodeVariablesColorsExcludeList() throws { + let yaml = """ + figma: + lightFileId: file_id + common: + variablesColors: + tokensFileId: tokens_id + tokensCollectionName: Base collection + lightModeName: Light + exclude: + - background + - backgroundSecondary + """ + + let params = try YAMLDecoder().decode(Params.self, from: yaml) + + XCTAssertEqual(params.common?.variablesColors?.exclude, ["background", "backgroundSecondary"]) + } + + func testDecodeWithoutExcludeList() throws { + let yaml = """ + figma: + lightFileId: file_id + common: + colors: + nameValidateRegexp: '^([a-zA-Z_]+)$' + """ + + let params = try YAMLDecoder().decode(Params.self, from: yaml) + + XCTAssertNil(params.common?.colors?.exclude) + XCTAssertNil(params.common?.variablesColors?.exclude) + } +}