Skip to content

Commit 6f22b8b

Browse files
authored
feat(core): Abstract design data sources behind per-asset-type protocols (#75)
* feat(core): abstract design data sources behind per-asset-type protocols Introduce ColorsSource, ComponentsSource, and TypographySource protocols in ExFigCore to decouple the export pipeline from Figma-specific loaders. This lays the foundation for supporting alternative design tools (Penpot, Sketch, Tokens Studio) without modifying the export infrastructure. - Add DesignSourceKind enum and ColorsSourceConfig protocol pattern - Refactor ColorsSourceInput to use sourceKind + sourceConfig - Extract FigmaColorsSource, TokensFileColorsSource, FigmaComponentsSource, FigmaTypographySource from context implementations - Add SourceFactory for centralized source dispatch - Add sourceKind field to PKL schemas (FrameSource, VariablesSource) - Update all context impls, plugin exports, and entry bridges * chore(openspec): archive design-source-abstraction, sync specs Sync 4 delta specs to main: design-source-protocol (new), source-dispatch (new), configuration (updated), tokens-file-source (updated). Archive completed change. * fix(core): wire SourceFactory into production path, restore lost warnings ColorsExportContextImpl now uses per-call SourceFactory dispatch instead of injected colorsSource, enabling per-entry sourceKind in multi-source configs. Fixes tokens-file colors export which was broken by hardcoded FigmaColorsSource. - Remove FigmaColorsSource injection from all 4 PluginColorsExport methods - Add ignoredModeNames to TokensFileColorsConfig for dark mode field warnings - Make unsupportedSourceKind error asset-type-aware with correct recovery hints - Add spinnerLabel to ColorsSourceInput for informative progress messages - Add 16 tests: SourceKindBridging, explicit override, ignoredModeNames, errors
1 parent 8fbb61f commit 6f22b8b

59 files changed

Lines changed: 1631 additions & 828 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CLAUDE.md

Lines changed: 54 additions & 35 deletions
Large diffs are not rendered by default.

Sources/ExFig-Android/Config/AndroidIconsEntry.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ public extension Android.IconsEntry {
1414
/// Returns an IconsSourceInput for use with IconsExportContext.
1515
func iconsSourceInput(darkFileId: String? = nil) -> IconsSourceInput {
1616
IconsSourceInput(
17+
sourceKind: sourceKind?.coreSourceKind ?? .figma,
1718
figmaFileId: figmaFileId,
1819
darkFileId: darkFileId,
1920
frameName: figmaFrameName ?? "Icons",

Sources/ExFig-Android/Config/AndroidImagesEntry.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ public extension Android.ImagesEntry {
3131
/// Returns an ImagesSourceInput for use with ImagesExportContext.
3232
func imagesSourceInput(darkFileId: String? = nil) -> ImagesSourceInput {
3333
ImagesSourceInput(
34+
sourceKind: sourceKind?.coreSourceKind ?? .figma,
3435
figmaFileId: figmaFileId,
3536
darkFileId: darkFileId,
3637
frameName: figmaFrameName ?? "Images",

Sources/ExFig-Android/Export/AndroidColorsExporter.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ public struct AndroidColorsExporter: ColorsExporter {
6363
// 1. Load colors from Figma
6464
let sourceInput = try entry.validatedColorsSourceInput()
6565
let colors = try await context.withSpinner(
66-
"Fetching colors from Figma (\(sourceInput.tokensCollectionName))..."
66+
"Fetching colors from \(sourceInput.spinnerLabel)..."
6767
) {
6868
try await context.loadColors(from: sourceInput)
6969
}

Sources/ExFig-Flutter/Config/FlutterIconsEntry.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ public extension Flutter.IconsEntry {
1111
/// Returns an IconsSourceInput for use with IconsExportContext.
1212
func iconsSourceInput(darkFileId: String? = nil) -> IconsSourceInput {
1313
IconsSourceInput(
14+
sourceKind: sourceKind?.coreSourceKind ?? .figma,
1415
figmaFileId: figmaFileId,
1516
darkFileId: darkFileId,
1617
frameName: figmaFrameName ?? "Icons",

Sources/ExFig-Flutter/Config/FlutterImagesEntry.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ public extension Flutter.ImagesEntry {
1414
/// Returns an ImagesSourceInput for use with ImagesExportContext.
1515
func imagesSourceInput(darkFileId: String? = nil) -> ImagesSourceInput {
1616
ImagesSourceInput(
17+
sourceKind: sourceKind?.coreSourceKind ?? .figma,
1718
figmaFileId: figmaFileId,
1819
darkFileId: darkFileId,
1920
frameName: figmaFrameName ?? "Images",
@@ -43,6 +44,7 @@ public extension Flutter.ImagesEntry {
4344
/// Returns an ImagesSourceInput configured for SVG source.
4445
func svgSourceInput(darkFileId: String? = nil) -> ImagesSourceInput {
4546
ImagesSourceInput(
47+
sourceKind: sourceKind?.coreSourceKind ?? .figma,
4648
figmaFileId: figmaFileId,
4749
darkFileId: darkFileId,
4850
frameName: figmaFrameName ?? "Images",

Sources/ExFig-Flutter/Export/FlutterColorsExporter.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public struct FlutterColorsExporter: ColorsExporter {
5252
// 1. Load colors from Figma
5353
let sourceInput = try entry.validatedColorsSourceInput()
5454
let colors = try await context.withSpinner(
55-
"Fetching colors from Figma (\(sourceInput.tokensCollectionName))..."
55+
"Fetching colors from \(sourceInput.spinnerLabel)..."
5656
) {
5757
try await context.loadColors(from: sourceInput)
5858
}

Sources/ExFig-Web/Config/WebIconsEntry.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ public extension Web.IconsEntry {
1111
/// Returns an IconsSourceInput for use with IconsExportContext.
1212
func iconsSourceInput(darkFileId: String? = nil) -> IconsSourceInput {
1313
IconsSourceInput(
14+
sourceKind: sourceKind?.coreSourceKind ?? .figma,
1415
figmaFileId: figmaFileId,
1516
darkFileId: darkFileId,
1617
frameName: figmaFrameName ?? "Icons",

Sources/ExFig-Web/Config/WebImagesEntry.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ public extension Web.ImagesEntry {
1111
/// Returns an ImagesSourceInput for use with ImagesExportContext.
1212
func imagesSourceInput(darkFileId: String? = nil) -> ImagesSourceInput {
1313
ImagesSourceInput(
14+
sourceKind: sourceKind?.coreSourceKind ?? .figma,
1415
figmaFileId: figmaFileId,
1516
darkFileId: darkFileId,
1617
frameName: figmaFrameName ?? "Images",

Sources/ExFig-Web/Export/WebColorsExporter.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public struct WebColorsExporter: ColorsExporter {
5252
// 1. Load colors from Figma
5353
let sourceInput = try entry.validatedColorsSourceInput()
5454
let colors = try await context.withSpinner(
55-
"Fetching colors from Figma (\(sourceInput.tokensCollectionName))..."
55+
"Fetching colors from \(sourceInput.spinnerLabel)..."
5656
) {
5757
try await context.loadColors(from: sourceInput)
5858
}

0 commit comments

Comments
 (0)