Skip to content

Migrate to PKL configuration and plugin architecture (v2.0) - #48

Merged
alexey1312 merged 94 commits into
mainfrom
alexey1312/migrate-pkl-config
Feb 9, 2026
Merged

Migrate to PKL configuration and plugin architecture (v2.0)#48
alexey1312 merged 94 commits into
mainfrom
alexey1312/migrate-pkl-config

Conversation

@alexey1312

Copy link
Copy Markdown
Collaborator

Summary

Major architecture overhaul replacing YAML configuration with PKL and restructuring the monolithic codebase into a plugin-based architecture.

  • PKL Configuration: Replace YAML with PKL (Programmable, Scalable, Safe) for type-safe, inheritable configs via native amends/extends
  • Plugin Architecture: Split monolithic ExFig into 4 independent platform plugins (ExFig-iOS, ExFig-Android, ExFig-Flutter, ExFig-Web) with unified PlatformPlugin and AssetExporter protocols
  • New ExFigConfig module: PKL evaluation infrastructure (PKLLocator, PKLEvaluator, schema validation)
  • Target rename: ExFig → ExFigCLI for clarity
  • Dead code removal: ~1936 LOC deleted (Params.swift, ParamsToPluginAdapter, legacy types)
  • PR review fixes: 47 new tests, bug fixes, silent failure logging, HEIC/WebP options threading

Architecture

PKL Configuration Schema

ExFig.pkl (root)
├── Figma.pkl     — API connection, file IDs, timeout
├── Common.pkl    — shared settings (cache, variablesColors, icons, images)
├── iOS.pkl       — colors, icons, images, typography for iOS
├── Android.pkl   — colors, icons, images, typography for Android
├── Flutter.pkl   — colors, icons, images for Flutter
└── Web.pkl       — colors, icons, images for Web

Users create configs by amending the schema:

amends "package://github.com/niceplaces/exfig@2.0.0#/ExFig.pkl"

figma {
  lightFileId = "ABC123"
}

common {
  variablesColors {
    tokensFileId = "DEF456"
    tokensCollectionName = "Design Tokens"
    lightModeName = "Light"
    darkModeName = "Dark"
  }
}

ios {
  xcodeprojPath = "MyApp.xcodeproj"
  colors {
    assetsFolder = "Resources/Colors"
    swiftFile = "Colors.swift"
    codeSyntax = "swiftui"
  }
}

Config inheritance via PKL amends:

// project-ios.pkl
amends "base.pkl"

ios {
  colors { assetsFolder = "App/Colors" }
}

Plugin System

CLI (ExFigCLI)
  → PluginRegistry
    → iOSPlugin        (ExFig-iOS module)
    → AndroidPlugin     (ExFig-Android module)
    → FlutterPlugin     (ExFig-Flutter module)
    → WebPlugin         (ExFig-Web module)

Each plugin provides:
  → ColorsExporter    + ColorsExportContext
  → IconsExporter     + IconsExportContext
  → ImagesExporter    + ImagesExportContext
  → TypographyExporter + TypographyExportContext (iOS, Android only)

Data flow: CLI → PKL config → PluginRegistry → Platform Exporter → ExportContext → File Output

Plugins remain decoupled from batch infrastructure — all batch optimizations (PipelinedDownloader, ComponentPreFetcher, GranularCache) are encapsulated in *ExportContextImpl within ExFigCLI.

Key Protocols (ExFigCore)

Protocol Purpose
PlatformPlugin Platform registration, exporter discovery
ColorsExporter Colors load/process/export cycle
IconsExporter Icons with SVG/PDF download, vector conversion
ImagesExporter Images with PNG/HEIC/WebP rendering, scaling
TypographyExporter Font styles export
*ExportContext Dependency injection for each asset type

Breaking Changes

  • YAML configuration no longer supported — use exfig.pkl
  • Yams dependency removed
  • Executable target renamed ExFig → ExFigCLI
  • PKL CLI required (mise use pkl)

Stats

  • 408 files changed, +31,962 / -7,557 lines
  • 2,169 tests passing
  • 18 phases of incremental migration
  • 5 new Swift modules

Test Plan

  • ./bin/mise run build — 0 errors
  • ./bin/mise run test — 2,169 tests pass
  • ./bin/mise run lint — 0 errors
  • ./bin/mise run format — clean
  • CI verification on macOS (post-merge)
  • CI verification on Linux (post-merge)

@gemini-code-assist

Copy link
Copy Markdown

Summary of Changes

Hello @alexey1312, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a major architectural overhaul, transforming the project from a monolithic application with YAML-based configuration into a highly modular system leveraging PKL for type-safe and extensible configurations. The core functionality is now distributed across dedicated platform plugins, improving code organization and future scalability. The CLI tool has also been rebranded for better clarity, alongside significant code cleanup and an expansion of testing infrastructure.

Highlights

  • Configuration Migration to PKL: The project has transitioned from YAML to PKL (Programmable, Scalable, Safe) for configuration, enabling type-safe and inheritable configurations through native 'amends' and 'extends' features. This involved removing the Yams dependency and introducing a new ExFigConfig module for PKL evaluation and schema validation.
  • Plugin-Based Architecture: The monolithic codebase has been restructured into a modular, plugin-based architecture. Four independent platform plugins (ExFig-iOS, ExFig-Android, ExFig-Flutter, ExFig-Web) have been introduced, each adhering to unified PlatformPlugin and AssetExporter protocols. This significantly enhances extensibility and maintainability.
  • CLI Renaming and Codebase Restructuring: The main executable has been renamed from ExFig to ExFigCLI for clarity. Correspondingly, numerous source files and documentation paths have been updated to reflect this change. This also involved the removal of approximately 1936 lines of dead code and legacy types.
  • Enhanced Testing and Quality Improvements: The pull request includes 47 new tests, bug fixes, silent failure logging, and improved threading for HEIC/WebP options, contributing to a higher test coverage (now 49.32%) and overall code quality.
  • New Experimental Workflow Commands: A suite of new experimental workflow commands (/opsx:apply, /opsx:archive, /opsx:bulk-archive, /opsx:continue, /opsx:explore, /opsx:ff, /opsx:new, /opsx:onboard, /opsx:sync, /opsx:verify) and their corresponding skills have been added, likely for internal development process management.
Changelog
  • .claude/commands/openspec/apply.md
    • Removed file, indicating a shift away from the old OpenSpec command structure.
  • .claude/commands/openspec/archive.md
    • Removed file, indicating a shift away from the old OpenSpec command structure.
  • .claude/commands/openspec/proposal.md
    • Removed file, indicating a shift away from the old OpenSpec command structure.
  • .claude/commands/opsx/apply.md
    • Added new experimental workflow command for applying OpenSpec changes.
  • .claude/commands/opsx/archive.md
    • Added new experimental workflow command for archiving OpenSpec changes.
  • .claude/commands/opsx/bulk-archive.md
    • Added new experimental workflow command for bulk archiving OpenSpec changes with conflict resolution.
  • .claude/commands/opsx/continue.md
    • Added new experimental workflow command for continuing OpenSpec artifact creation.
  • .claude/commands/opsx/explore.md
    • Added new experimental workflow command for entering an exploration mode for problem-solving.
  • .claude/commands/opsx/ff.md
    • Added new experimental workflow command for fast-forwarding OpenSpec artifact creation.
  • .claude/commands/opsx/new.md
    • Added new experimental workflow command for starting a new OpenSpec change.
  • .claude/commands/opsx/onboard.md
    • Added new experimental workflow command for guided onboarding through the OpenSpec workflow.
  • .claude/commands/opsx/sync.md
    • Added new experimental workflow command for syncing delta specs to main specs.
  • .claude/commands/opsx/verify.md
    • Added new experimental workflow command for verifying implementation against OpenSpec artifacts.
  • .claude/skills/openspec-apply-change/SKILL.md
    • Added new skill definition for applying OpenSpec changes.
  • .claude/skills/openspec-archive-change/SKILL.md
    • Added new skill definition for archiving OpenSpec changes.
  • .claude/skills/openspec-bulk-archive-change/SKILL.md
    • Added new skill definition for bulk archiving OpenSpec changes.
  • .claude/skills/openspec-continue-change/SKILL.md
    • Added new skill definition for continuing OpenSpec artifact creation.
  • .claude/skills/openspec-explore/SKILL.md
    • Added new skill definition for exploring ideas within OpenSpec.
  • .claude/skills/openspec-ff-change/SKILL.md
    • Added new skill definition for fast-forwarding OpenSpec artifact creation.
  • .claude/skills/openspec-new-change/SKILL.md
    • Added new skill definition for starting a new OpenSpec change.
  • .claude/skills/openspec-onboard/SKILL.md
    • Added new skill definition for OpenSpec onboarding.
  • .claude/skills/openspec-sync-specs/SKILL.md
    • Added new skill definition for syncing OpenSpec delta specs.
  • .claude/skills/openspec-verify-change/SKILL.md
    • Added new skill definition for verifying OpenSpec implementations.
  • .codex/skills/openspec-apply-change/SKILL.md
    • Added new skill definition for applying OpenSpec changes (duplicate of .claude/skills).
  • .codex/skills/openspec-archive-change/SKILL.md
    • Added new skill definition for archiving OpenSpec changes (duplicate of .claude/skills).
  • .codex/skills/openspec-bulk-archive-change/SKILL.md
    • Added new skill definition for bulk archiving OpenSpec changes (duplicate of .claude/skills).
  • .codex/skills/openspec-continue-change/SKILL.md
    • Added new skill definition for continuing OpenSpec artifact creation (duplicate of .claude/skills).
  • .codex/skills/openspec-explore/SKILL.md
    • Added new skill definition for exploring ideas within OpenSpec (duplicate of .claude/skills).
  • .codex/skills/openspec-ff-change/SKILL.md
    • Added new skill definition for fast-forwarding OpenSpec artifact creation (duplicate of .claude/skills).
  • .codex/skills/openspec-new-change/SKILL.md
    • Added new skill definition for starting a new OpenSpec change (duplicate of .claude/skills).
  • .codex/skills/openspec-onboard/SKILL.md
    • Added new skill definition for OpenSpec onboarding (duplicate of .claude/skills).
  • .codex/skills/openspec-sync-specs/SKILL.md
    • Added new skill definition for syncing OpenSpec delta specs (duplicate of .claude/skills).
  • .codex/skills/openspec-verify-change/SKILL.md
    • Added new skill definition for verifying OpenSpec implementations (duplicate of .claude/skills).
  • .github/scripts/set-version.sh
    • Updated the path for 'ExFigCommand.swift' to reflect the CLI renaming from 'Sources/ExFig/' to 'Sources/ExFigCLI/'.
  • .swiftlint.yml
    • Updated excluded paths for resource files to reflect the CLI renaming from 'Sources/ExFig/' to 'Sources/ExFigCLI/'.
  • CLAUDE.md
    • Removed the old OpenSpec instructions block.
    • Updated configuration examples from YAML to PKL.
    • Updated the architecture section to reflect the new 12-module structure, including 'ExFigConfig' and platform-specific plugins.
    • Modified the data flow description to include PKL config parsing and platform plugins.
    • Removed 'Yams' dependency and added 'toon-swift' to the dependency list.
  • Package.resolved
    • Updated dependency hashes and versions for 'swift-custom-dump' and 'xctest-dynamic-overlay'.
    • Removed the 'yams' dependency.
  • Package.swift
    • Renamed the executable target from 'ExFig' to 'ExFigCLI'.
    • Added new dependencies for 'ExFigConfig' and the platform-specific plugins ('ExFig-iOS', 'ExFig-Android', 'ExFig-Flutter', 'ExFig-Web').
    • Removed the 'Yams' dependency.
    • Introduced new targets for 'ExFigConfig' and each platform plugin.
    • Updated the 'ExFigTests' dependency to 'ExFigCLI'.
    • Added new test targets for 'ExFigConfigTests' and each platform plugin's tests.
  • README.md
    • Updated the test coverage badge to reflect the new coverage percentage.
    • Updated configuration file examples from 'exfig.yaml' to 'exfig.pkl'.
    • Modified batch command examples to use '.pkl' files.
    • Added PKL as a required installation for users.
  • Scripts/increment_major_version.command
    • Updated the path for 'ExFigCommand.swift' to 'Sources/ExFigCLI/'.
  • Scripts/increment_minor_version.command
    • Updated the path for 'ExFigCommand.swift' to 'Sources/ExFigCLI/'.
  • Sources/ExFig-Android/AndroidPlugin.swift
    • Added a new Swift file defining the AndroidPlugin struct, which conforms to PlatformPlugin and registers Android-specific asset exporters.
  • Sources/ExFig-Android/Config/AndroidColorsEntry.swift
    • Added a new Swift file defining AndroidColorsEntry for Android color export configuration.
  • Sources/ExFig-Android/Config/AndroidIconsEntry.swift
    • Added a new Swift file defining AndroidIconsEntry for Android icon export configuration.
  • Sources/ExFig-Android/Config/AndroidImagesEntry.swift
    • Added a new Swift file defining AndroidImagesEntry for Android image export configuration.
  • Sources/ExFig-Android/Config/AndroidPlatformConfig.swift
    • Added a new Swift file defining AndroidPlatformConfig for Android platform-level settings.
  • Sources/ExFig-Android/Config/AndroidTypographyEntry.swift
    • Added a new Swift file defining AndroidTypographyEntry for Android typography export configuration.
  • Sources/ExFig-Android/Export/AndroidColorsExporter.swift
    • Added a new Swift file implementing ColorsExporter for Android, handling color fetching, processing, and export to XML and Kotlin.
  • Sources/ExFig-Android/Export/AndroidIconsExporter.swift
    • Added a new Swift file implementing IconsExporter for Android, supporting SVG to VectorDrawable XML and ImageVector Kotlin export.
  • Sources/ExFig-Android/Export/AndroidImagesExporter.swift
    • Added a new Swift file implementing ImagesExporter for Android, managing various image source and output formats.
  • Sources/ExFig-Android/Export/AndroidTypographyExporter.swift
    • Added a new Swift file implementing TypographyExporter for Android, handling text style export to XML and Kotlin.
  • Sources/ExFig-Flutter/Config/FlutterColorsEntry.swift
    • Added a new Swift file defining FlutterColorsEntry for Flutter color export configuration.
  • Sources/ExFig-Flutter/Config/FlutterIconsEntry.swift
    • Added a new Swift file defining FlutterIconsEntry for Flutter icon export configuration.
  • Sources/ExFig-Flutter/Config/FlutterImagesEntry.swift
    • Added a new Swift file defining FlutterImagesEntry for Flutter image export configuration.
  • Sources/ExFig-Flutter/Config/FlutterPlatformConfig.swift
    • Added a new Swift file defining FlutterPlatformConfig for Flutter platform-level settings.
  • Sources/ExFig-Flutter/Export/FlutterColorsExporter.swift
    • Added a new Swift file implementing ColorsExporter for Flutter, handling color export to Dart.
  • Sources/ExFig-Flutter/Export/FlutterIconsExporter.swift
    • Added a new Swift file implementing IconsExporter for Flutter, managing SVG asset and Dart code generation.
  • Sources/ExFig-Flutter/Export/FlutterImagesExporter.swift
    • Added a new Swift file implementing ImagesExporter for Flutter, supporting various image source and output formats.
  • Sources/ExFig-Flutter/FlutterPlugin.swift
    • Added a new Swift file defining the FlutterPlugin struct, which conforms to PlatformPlugin and registers Flutter-specific asset exporters.
  • Sources/ExFig-Web/Config/WebColorsEntry.swift
    • Added a new Swift file defining WebColorsEntry for Web color export configuration.
  • Sources/ExFig-Web/Config/WebIconsEntry.swift
    • Added a new Swift file defining WebIconsEntry for Web icon export configuration.
  • Sources/ExFig-Web/Config/WebImagesEntry.swift
    • Added a new Swift file defining WebImagesEntry for Web image export configuration.
  • Sources/ExFig-Web/Config/WebPlatformConfig.swift
    • Added a new Swift file defining WebPlatformConfig for Web platform-level settings.
  • Sources/ExFig-Web/Export/WebColorsExporter.swift
    • Added a new Swift file implementing ColorsExporter for Web, handling color export to CSS, TypeScript, and JSON.
  • Sources/ExFig-Web/Export/WebIconsExporter.swift
    • Added a new Swift file implementing IconsExporter for Web, managing SVG asset and React TSX component generation.
  • Sources/ExFig-Web/Export/WebImagesExporter.swift
    • Added a new Swift file implementing ImagesExporter for Web, handling image asset and React component generation.
  • Sources/ExFig-Web/WebPlugin.swift
    • Added a new Swift file defining the WebPlugin struct, which conforms to PlatformPlugin and registers Web-specific asset exporters.
  • Sources/ExFig-iOS/Config/iOSColorsEntry.swift
    • Added a new Swift file defining iOSColorsEntry for iOS color export configuration.
  • Sources/ExFig-iOS/Config/iOSIconsEntry.swift
    • Added a new Swift file defining iOSIconsEntry for iOS icon export configuration.
  • Sources/ExFig-iOS/Config/iOSImagesEntry.swift
    • Added a new Swift file defining iOSImagesEntry for iOS image export configuration.
  • Sources/ExFig-iOS/Config/iOSPlatformConfig.swift
    • Added a new Swift file defining iOSPlatformConfig for iOS platform-level settings.
  • Sources/ExFig-iOS/Config/iOSTypographyEntry.swift
    • Added a new Swift file defining iOSTypographyEntry for iOS typography export configuration.
  • Sources/ExFig-iOS/Export/iOSColorsExporter.swift
    • Added a new Swift file implementing ColorsExporter for iOS, handling color export to xcassets and Swift extensions.
  • Sources/ExFig-iOS/Export/iOSIconsExporter.swift
    • Added a new Swift file implementing IconsExporter for iOS, managing icon export to xcassets and Swift extensions with granular cache support.
  • Sources/ExFig-iOS/Export/iOSImagesExporter.swift
    • Added a new Swift file implementing ImagesExporter for iOS, handling image export to xcassets (PNG/HEIC) and Swift extensions with granular cache support.
  • Sources/ExFig-iOS/Export/iOSTypographyExporter.swift
    • Added a new Swift file implementing TypographyExporter for iOS, handling text style export to Swift font extensions.
  • Sources/ExFig-iOS/iOSPlugin.swift
    • Added a new Swift file defining the iOSPlugin struct, which conforms to PlatformPlugin and registers iOS-specific asset exporters.
  • Sources/ExFig/Batch/BatchConfigRunner.swift
    • Renamed to Sources/ExFigCLI/Batch/BatchConfigRunner.swift.
  • Sources/ExFig/Batch/BatchContext.swift
    • Renamed to Sources/ExFigCLI/Batch/BatchContext.swift.
  • Sources/ExFig/Batch/BatchExecutor.swift
    • Renamed to Sources/ExFigCLI/Batch/BatchExecutor.swift.
  • Sources/ExFig/Batch/BatchResult.swift
    • Renamed to Sources/ExFigCLI/Batch/BatchResult.swift.
  • Sources/ExFig/Batch/ConfigDiscovery.swift
    • Renamed to Sources/ExFigCLI/Batch/ConfigDiscovery.swift.
  • Sources/ExFig/Batch/FileIdExtractor.swift
    • Renamed to Sources/ExFigCLI/Batch/FileIdExtractor.swift.
  • Sources/ExFig/Batch/FileVersionPreFetcher.swift
    • Renamed to Sources/ExFigCLI/Batch/FileVersionPreFetcher.swift.
  • Sources/ExFig/Batch/PreFetchedComponents.swift
    • Renamed to Sources/ExFigCLI/Batch/PreFetchedComponents.swift.
  • Sources/ExFig/Batch/PreFetchedFileVersions.swift
    • Renamed to Sources/ExFigCLI/Batch/PreFetchedFileVersions.swift.
  • Sources/ExFig/Batch/PreFetchedNodes.swift
    • Renamed to Sources/ExFigCLI/Batch/PreFetchedNodes.swift.
  • Sources/ExFig/Batch/SharedGranularCache.swift
    • Renamed to Sources/ExFigCLI/Batch/SharedGranularCache.swift.
  • Sources/ExFig/Batch/SharedThemeAttributes.swift
    • Renamed to Sources/ExFigCLI/Batch/SharedThemeAttributes.swift.
  • Sources/ExFig/Cache/BatchCheckpoint.swift
    • Renamed to Sources/ExFigCLI/Cache/BatchCheckpoint.swift.
  • Sources/ExFig/Cache/CheckpointTracker.swift
    • Renamed to Sources/ExFigCLI/Cache/CheckpointTracker.swift.
  • Sources/ExFig/Cache/ExportCheckpoint.swift
    • Renamed to Sources/ExFigCLI/Cache/ExportCheckpoint.swift.
  • Sources/ExFig/Cache/FNV1aHasher.swift
    • Renamed to Sources/ExFigCLI/Cache/FNV1aHasher.swift.
  • Sources/ExFig/Cache/FileIdProvider.swift
    • Renamed to Sources/ExFigCLI/Cache/FileIdProvider.swift.
  • Sources/ExFig/Cache/GranularCacheManager.swift
    • Renamed to Sources/ExFigCLI/Cache/GranularCacheManager.swift.
  • Sources/ExFig/Cache/GranularCacheSetup.swift
    • Renamed to Sources/ExFigCLI/Cache/GranularCacheSetup.swift.
  • Sources/ExFig/Cache/ImageTrackingCache.swift
    • Renamed to Sources/ExFigCLI/Cache/ImageTrackingCache.swift.
  • Sources/ExFig/Cache/ImageTrackingManager.swift
    • Renamed to Sources/ExFigCLI/Cache/ImageTrackingManager.swift.
  • Sources/ExFig/Cache/NodeHasher.swift
    • Renamed to Sources/ExFigCLI/Cache/NodeHasher.swift.
  • Sources/ExFig/Cache/VersionTrackingHelper.swift
    • Renamed to Sources/ExFigCLI/Cache/VersionTrackingHelper.swift.
  • Sources/ExFig/ExFig.docc/Android/Android.md
    • Renamed to Sources/ExFigCLI/ExFig.docc/Android/Android.md.
  • Sources/ExFig/ExFig.docc/Android/AndroidColors.md
    • Renamed to Sources/ExFigCLI/ExFig.docc/Android/AndroidColors.md.
  • Sources/ExFig/ExFig.docc/Android/AndroidIcons.md
    • Renamed to Sources/ExFigCLI/ExFig.docc/Android/AndroidIcons.md.
  • Sources/ExFig/ExFig.docc/Android/AndroidImages.md
    • Renamed to Sources/ExFigCLI/ExFig.docc/Android/AndroidImages.md.
  • Sources/ExFig/ExFig.docc/Android/AndroidTypography.md
    • Renamed to Sources/ExFigCLI/ExFig.docc/Android/AndroidTypography.md.
  • Sources/ExFig/ExFig.docc/Configuration.md
    • Renamed to Sources/ExFigCLI/ExFig.docc/Configuration.md.
  • Sources/ExFig/ExFig.docc/CustomTemplates.md
    • Renamed to Sources/ExFigCLI/ExFig.docc/CustomTemplates.md.
  • Sources/ExFig/ExFig.docc/DesignRequirements.md
    • Renamed to Sources/ExFigCLI/ExFig.docc/DesignRequirements.md.
  • Sources/ExFig/ExFig.docc/Development.md
    • Renamed to Sources/ExFigCLI/ExFig.docc/Development.md.
  • Sources/ExFig/ExFig.docc/ExFig.md
    • Renamed to Sources/ExFigCLI/ExFig.docc/ExFig.md.
  • Sources/ExFig/ExFig.docc/Flutter/Flutter.md
    • Renamed to Sources/ExFigCLI/ExFig.docc/Flutter/Flutter.md.
  • Sources/ExFig/ExFig.docc/GettingStarted.md
    • Renamed to Sources/ExFigCLI/ExFig.docc/GettingStarted.md.
  • Sources/ExFig/ExFig.docc/Usage.md
    • Renamed to Sources/ExFigCLI/ExFig.docc/Usage.md.
  • Sources/ExFig/ExFig.docc/iOS/iOS.md
    • Renamed to Sources/ExFigCLI/ExFig.docc/iOS/iOS.md.
  • Sources/ExFig/ExFig.docc/iOS/iOSColors.md
    • Renamed to Sources/ExFigCLI/ExFig.docc/iOS/iOSColors.md.
  • Sources/ExFig/ExFig.docc/iOS/iOSIcons.md
    • Renamed to Sources/ExFigCLI/ExFig.docc/iOS/iOSIcons.md.
  • Sources/ExFig/ExFig.docc/iOS/iOSImages.md
    • Renamed to Sources/ExFigCLI/ExFig.docc/iOS/iOSImages.md.
  • Sources/ExFig/ExFig.docc/iOS/iOSTypography.md
    • Renamed to Sources/ExFigCLI/ExFig.docc/iOS/iOSTypography.md.
  • Sources/ExFig/ExFigCommand.swift
    • Renamed to Sources/ExFigCLI/ExFigCommand.swift.
  • Sources/ExFig/Input/CacheOptions.swift
    • Renamed to Sources/ExFigCLI/Input/CacheOptions.swift.
  • Sources/ExFig/Input/DownloadOptions.swift
    • Renamed to Sources/ExFigCLI/Input/DownloadOptions.swift.
  • Sources/ExFig/Input/ExFigOptions.swift
    • Renamed to Sources/ExFigCLI/Input/ExFigOptions.swift.
  • Sources/ExFig/Input/FaultToleranceOptions.swift
    • Renamed to Sources/ExFigCLI/Input/FaultToleranceOptions.swift.
  • Sources/ExFig/Input/GlobalOptions.swift
    • Renamed to Sources/ExFigCLI/Input/GlobalOptions.swift.
  • Sources/ExFig/Input/Params+FileIdProvider.swift
    • Renamed to Sources/ExFigCLI/Input/PKLConfig+FileIdProvider.swift.
  • Sources/ExFig/Loaders/Colors/ColorsLoader.swift
    • Renamed to Sources/ExFigCLI/Loaders/Colors/ColorsLoader.swift.
  • Sources/ExFig/Loaders/Colors/ColorsVariablesLoader.swift
    • Renamed to Sources/ExFigCLI/Loaders/Colors/ColorsVariablesLoader.swift.
  • Sources/ExFig/Loaders/DownloadImageLoader.swift
    • Renamed to Sources/ExFigCLI/Loaders/DownloadImageLoader.swift.
  • Sources/ExFig/Loaders/IconsLoader.swift
    • Renamed to Sources/ExFigCLI/Loaders/IconsLoader.swift.
  • Sources/ExFig/Loaders/ImageLoaderBase.swift
    • Renamed to Sources/ExFigCLI/Loaders/ImageLoaderBase.swift.
  • Sources/ExFig/Loaders/ImagesLoader.swift
    • Renamed to Sources/ExFigCLI/Loaders/ImagesLoader.swift.
  • Sources/ExFig/Loaders/TextStylesLoader.swift
    • Renamed to Sources/ExFigCLI/Loaders/TextStylesLoader.swift.
  • Sources/ExFig/Output/DownloadExportHelpers.swift
    • Renamed to Sources/ExFigCLI/Output/DownloadExportHelpers.swift.
  • Sources/ExFig/Output/FileDownloader.swift
    • Renamed to Sources/ExFigCLI/Output/FileDownloader.swift.
  • Sources/ExFig/Output/FileWriter.swift
    • Renamed to Sources/ExFigCLI/Output/FileWriter.swift.
  • Sources/ExFig/Output/HeicConverter.swift
    • Renamed to Sources/ExFigCLI/Output/HeicConverter.swift.
  • Sources/ExFig/Output/HeicConverterFactory.swift
    • Renamed to Sources/ExFigCLI/Output/HeicConverterFactory.swift.
  • Sources/ExFig/Output/MarkerFileUpdater.swift
    • Renamed to Sources/ExFigCLI/Output/MarkerFileUpdater.swift.
  • Sources/ExFig/Output/NativeHeicEncoder.swift
    • Renamed to Sources/ExFigCLI/Output/NativeHeicEncoder.swift.
  • Sources/ExFig/Output/NativePngEncoder.swift
    • Renamed to Sources/ExFigCLI/Output/NativePngEncoder.swift.
  • Sources/ExFig/Output/NativeWebpEncoder.swift
    • Renamed to Sources/ExFigCLI/Output/NativeWebpEncoder.swift.
  • Sources/ExFig/Output/PngDecoder.swift
    • Renamed to Sources/ExFigCLI/Output/PngDecoder.swift.
  • Sources/ExFig/Output/RawExporter.swift
    • Renamed to Sources/ExFigCLI/Output/RawExporter.swift.
  • Sources/ExFig/Output/SvgToHeicConverter.swift
    • Renamed to Sources/ExFigCLI/Output/SvgToHeicConverter.swift.
  • Sources/ExFig/Output/SvgToPngConverter.swift
    • Renamed to Sources/ExFigCLI/Output/SvgToPngConverter.swift.
  • Sources/ExFig/Output/SvgToWebpConverter.swift
    • Renamed to Sources/ExFigCLI/Output/SvgToWebpConverter.swift.
  • Sources/ExFig/Output/W3CTokensExporter.swift
    • Renamed to Sources/ExFigCLI/Output/W3CTokensExporter.swift.
  • Sources/ExFig/Output/WebpConverter.swift
    • Renamed to Sources/ExFigCLI/Output/WebpConverter.swift.
  • Sources/ExFig/Output/WebpConverterFactory.swift
    • Renamed to Sources/ExFigCLI/Output/WebpConverterFactory.swift.
  • Sources/ExFig/Output/XcodeProjectWriter.swift
    • Renamed to Sources/ExFigCLI/Output/XcodeProjectWriter.swift.
  • Sources/ExFig/Pipeline/DownloadJob.swift
    • Renamed to Sources/ExFigCLI/Pipeline/DownloadJob.swift.
  • Sources/ExFig/Pipeline/PipelinedDownloader.swift
    • Renamed to Sources/ExFigCLI/Pipeline/PipelinedDownloader.swift.
  • Sources/ExFig/Pipeline/SharedDownloadQueue.swift
    • Renamed to Sources/ExFigCLI/Pipeline/SharedDownloadQueue.swift.
  • Sources/ExFig/Pipeline/SharedDownloadQueueStorage.swift
    • Renamed to Sources/ExFigCLI/Pipeline/SharedDownloadQueueStorage.swift.
  • Sources/ExFig/Resources/androidConfig.swift
    • Renamed to Sources/ExFigCLI/Resources/androidConfig.swift.
  • Sources/ExFig/Resources/flutterConfig.swift
    • Renamed to Sources/ExFigCLI/Resources/flutterConfig.swift.
  • Sources/ExFig/Resources/iOSConfig.swift
    • Renamed to Sources/ExFigCLI/Resources/iOSConfig.swift.
  • Sources/ExFig/Resources/webConfig.swift
    • Renamed to Sources/ExFigCLI/Resources/webConfig.swift.
  • Sources/ExFig/Shared/BatchProgressViewStorage.swift
    • Renamed to Sources/ExFigCLI/Shared/BatchProgressViewStorage.swift.
  • Sources/ExFig/Shared/ComponentPreFetcher.swift
    • Renamed to Sources/ExFigCLI/Shared/ComponentPreFetcher.swift.
  • Sources/ExFig/Shared/EntryProcessor.swift
    • Renamed to Sources/ExFigCLI/Shared/EntryProcessor.swift.
  • Sources/ExFig/Shared/HashMerger.swift
    • Renamed to Sources/ExFigCLI/Shared/HashMerger.swift.
  • Sources/ExFig/Shared/InjectedClientStorage.swift
    • Renamed to Sources/ExFigCLI/Shared/InjectedClientStorage.swift.
  • Sources/ExFig/Shared/PlatformExportResult.swift
    • Renamed to Sources/ExFigCLI/Shared/PlatformExportResult.swift.
  • Sources/ExFig/Subcommands/Batch.swift
    • Renamed to Sources/ExFigCLI/Subcommands/Batch.swift.
  • Sources/ExFig/Subcommands/Download.swift
    • Renamed to Sources/ExFigCLI/Subcommands/Download.swift.
  • Sources/ExFig/Subcommands/DownloadAll.swift
    • Renamed to Sources/ExFigCLI/Subcommands/DownloadAll.swift.
  • Sources/ExFig/Subcommands/DownloadIcons.swift
    • Renamed to Sources/ExFigCLI/Subcommands/DownloadIcons.swift.
  • Sources/ExFig/Subcommands/DownloadImageProcessor.swift
    • Renamed to Sources/ExFigCLI/Subcommands/DownloadImageProcessor.swift.
  • Sources/ExFig/Subcommands/DownloadImages.swift
    • Renamed to Sources/ExFigCLI/Subcommands/DownloadImages.swift.
  • Sources/ExFig/Subcommands/DownloadImagesExport.swift
    • Renamed to Sources/ExFigCLI/Subcommands/DownloadImagesExport.swift.
  • Sources/ExFig/Subcommands/DownloadTypography.swift
    • Renamed to Sources/ExFigCLI/Subcommands/DownloadTypography.swift.
  • Sources/ExFig/Subcommands/Export/AndroidColorsExport.swift
    • Renamed to Sources/ExFigCLI/Subcommands/Export/AndroidColorsExport.swift.
  • Sources/ExFig/Subcommands/Export/WebColorsExport.swift
    • Renamed to Sources/ExFigCLI/Subcommands/Export/WebColorsExport.swift.
  • Sources/ExFig/Subcommands/Export/iOSColorsExport.swift
    • Renamed to Sources/ExFigCLI/Subcommands/Export/iOSColorsExport.swift.
  • Sources/ExFig/Subcommands/ExportColors.swift
    • Renamed to Sources/ExFigCLI/Subcommands/ExportColors.swift.
  • Sources/ExFig/Subcommands/ExportIcons.swift
    • Renamed to Sources/ExFigCLI/Subcommands/ExportIcons.swift.
  • Sources/ExFig/Subcommands/ExportImages.swift
    • Renamed to Sources/ExFigCLI/Subcommands/ExportImages.swift.
  • Sources/ExFig/Subcommands/GenerateConfigFile.swift
    • Renamed to Sources/ExFigCLI/Subcommands/GenerateConfigFile.swift.
  • Sources/ExFig/Subcommands/checkForUpdate.swift
    • Renamed to Sources/ExFigCLI/Subcommands/checkForUpdate.swift.
  • Sources/ExFig/Sync/CodeSyntaxSyncer.swift
    • Renamed to Sources/ExFigCLI/Sync/CodeSyntaxSyncer.swift.
  • Sources/ExFig/TerminalUI/ANSICodes.swift
    • Renamed to Sources/ExFigCLI/TerminalUI/ANSICodes.swift.
  • Sources/ExFig/TerminalUI/BatchProgressView.swift
    • Renamed to Sources/ExFigCLI/TerminalUI/BatchProgressView.swift.
  • Sources/ExFig/TerminalUI/ConflictFormatter.swift
    • Renamed to Sources/ExFigCLI/TerminalUI/ConflictFormatter.swift.
  • Sources/ExFig/TerminalUI/ExFigErrorFormatter.swift
    • Renamed to Sources/ExFigCLI/TerminalUI/ExFigErrorFormatter.swift.
  • Sources/ExFig/TerminalUI/ExFigLogHandler.swift
    • Renamed to Sources/ExFigCLI/TerminalUI/ExFigLogHandler.swift.
  • Sources/ExFig/TerminalUI/ExFigWarning.swift
    • Renamed to Sources/ExFigCLI/TerminalUI/ExFigWarning.swift.
  • Sources/ExFig/TerminalUI/ExFigWarningFormatter.swift
    • Renamed to Sources/ExFigCLI/TerminalUI/ExFigWarningFormatter.swift.
  • Sources/ExFig/TerminalUI/Lock.swift
    • Renamed to Sources/ExFigCLI/TerminalUI/Lock.swift.
  • Sources/ExFig/TerminalUI/MultiProgressManager.swift
    • Renamed to Sources/ExFigCLI/TerminalUI/MultiProgressManager.swift.
  • Sources/ExFig/TerminalUI/NooraUI.swift
    • Renamed to Sources/ExFigCLI/TerminalUI/NooraUI.swift.
  • Sources/ExFig/TerminalUI/OutputMode.swift
    • Renamed to Sources/ExFigCLI/TerminalUI/OutputMode.swift.
  • Sources/ExFig/TerminalUI/ProgressBar.swift
    • Renamed to Sources/ExFigCLI/TerminalUI/ProgressBar.swift.
  • Sources/ExFig/TerminalUI/RetryLogger.swift
    • Renamed to Sources/ExFigCLI/TerminalUI/RetryLogger.swift.
  • Sources/ExFig/TerminalUI/Spinner.swift
    • Renamed to Sources/ExFigCLI/TerminalUI/Spinner.swift.
  • Sources/ExFig/TerminalUI/TTYDetector.swift
    • Renamed to Sources/ExFigCLI/TerminalUI/TTYDetector.swift.
  • Sources/ExFig/TerminalUI/TerminalOutputManager.swift
    • Renamed to Sources/ExFigCLI/TerminalUI/TerminalOutputManager.swift.
  • Sources/ExFig/TerminalUI/TerminalUI.swift
    • Renamed to Sources/ExFigCLI/TerminalUI/TerminalUI.swift.
  • Sources/ExFig/TerminalUI/WarningFormatter.swift
    • Renamed to Sources/ExFigCLI/TerminalUI/WarningFormatter.swift.
Ignored Files
  • Ignored by pattern: .gemini/** (20)
    • .gemini/commands/opsx/apply.toml
    • .gemini/commands/opsx/archive.toml
    • .gemini/commands/opsx/bulk-archive.toml
    • .gemini/commands/opsx/continue.toml
    • .gemini/commands/opsx/explore.toml
    • .gemini/commands/opsx/ff.toml
    • .gemini/commands/opsx/new.toml
    • .gemini/commands/opsx/onboard.toml
    • .gemini/commands/opsx/sync.toml
    • .gemini/commands/opsx/verify.toml
    • .gemini/skills/openspec-apply-change/SKILL.md
    • .gemini/skills/openspec-archive-change/SKILL.md
    • .gemini/skills/openspec-bulk-archive-change/SKILL.md
    • .gemini/skills/openspec-continue-change/SKILL.md
    • .gemini/skills/openspec-explore/SKILL.md
    • .gemini/skills/openspec-ff-change/SKILL.md
    • .gemini/skills/openspec-new-change/SKILL.md
    • .gemini/skills/openspec-onboard/SKILL.md
    • .gemini/skills/openspec-sync-specs/SKILL.md
    • .gemini/skills/openspec-verify-change/SKILL.md
  • Ignored by pattern: .github/workflows/** (2)
    • .github/workflows/ci.yml
    • .github/workflows/release.yml
Activity
  • The pull request involved changes across 408 files, with a net increase of over 24,000 lines of code, indicating a substantial refactoring and feature addition.
  • All 2,169 existing tests are passing, ensuring that the extensive changes have not introduced regressions.
  • The migration was conducted in 18 incremental phases, suggesting a well-planned and iterative development process.
  • Five new Swift modules were introduced, highlighting the modularization effort.
  • Specific PR review fixes included adding 47 new tests, addressing bugs, implementing silent failure logging, and improving HEIC/WebP options threading.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a major architectural refactoring of the ExFig CLI tool, renaming the main CLI module from ExFig to ExFigCLI and migrating its functionality to a new plugin-based system. This includes the removal of YAML-based configuration in favor of PKL (Programmable, Scalable, Safe) and the introduction of dedicated platform-specific modules (ExFig-iOS, ExFig-Android, ExFig-Flutter, ExFig-Web) for handling asset exports. The changes also involve updating various scripts, documentation (README.md, CLAUDE.md), and Swift package dependencies to reflect these structural and configuration language shifts. Additionally, a new set of AI agent command definitions for OpenSpec workflows (opsx commands and openspec skills) have been added, replacing older OpenSpec instruction blocks. Review comments highlight concerns about potential duplication of these new AI agent skill definitions across multiple directories, outdated documentation regarding ParamsToPluginAdapter.swift (which was removed), and the excessive length and complexity of certain exporter files (AndroidIconsExporter.swift, iOSImagesExporter.swift), suggesting further refactoring for improved maintainability.

Comment thread .codex/skills/openspec-apply-change/SKILL.md
Comment thread CLAUDE.md Outdated
Comment thread Sources/ExFig-Android/Export/AndroidIconsExporter.swift
Comment thread Sources/ExFig-iOS/Export/iOSImagesExporter.swift
@alexey1312
alexey1312 force-pushed the alexey1312/migrate-pkl-config branch 2 times, most recently from d514140 to e6f21b2 Compare February 6, 2026 14:03
alexey1312 and others added 26 commits February 6, 2026 20:04
Add PKL schemas for ExFig v2.0 configuration:
- PklProject manifest for package distribution
- ExFig.pkl - main configuration module
- Common.pkl - shared types (NameStyle, SourceFormat, VariablesSource)
- Figma.pkl - Figma API settings (fileIds, timeout)
- iOS.pkl - iOS platform (ColorsEntry, IconsEntry, ImagesEntry, Typography)
- Android.pkl - Android platform with Compose support
- Flutter.pkl - Flutter platform configuration
- Web.pkl - Web/React platform configuration

Features:
- Union types for single/multiple entry configs
- Open classes for inheritance (amends)
- Type validation (NameStyle enum, quality constraints)
- Example configs demonstrating inheritance

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add PKL evaluation infrastructure:

PKLLocator - finds pkl executable:
- mise installs (~/.local/share/mise/installs/pkl/*)
- Homebrew (Apple Silicon, Intel, Linux)
- PATH (skipping mise shims which don't work for pkl)
- Caching for subsequent calls

PKLEvaluator - evaluates PKL configs:
- Subprocess wrapper for pkl CLI
- JSON output format
- Error handling with line/column info
- evaluateToParams() for direct Params decoding

PKLError - error types:
- notFound: pkl CLI not installed
- evaluationFailed: syntax/type errors
- configNotFound: missing config file

Tests (9 passing):
- PKLLocatorTests: find, executable, not found, caching
- PKLEvaluatorTests: JSON output, Params decoding, error handling

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Phase 4: ExFig Integration (Migration)

Source changes:
- ExFigOptions: use PKLEvaluator instead of Yams, default to exfig.pkl
- ConfigDiscovery: discover .pkl files, validate ExFig amends
- FileIdExtractor: use PKLEvaluator to parse configs
- Remove Migrate command (YAML→PKL no longer needed)

Test updates:
- Update all test fixtures from YAML to PKL format
- Update ConfigDiscoveryTests for PKL validation
- Update FileIdExtractorTests for PKL parsing
- Update BatchIntegrationTests, BatchExecutorTests, etc.
- Delete MigrateTests (command removed)

All 1920 tests pass.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Phase 6: Dependency Cleanup

- Remove Yams from Package.swift dependencies
- Update FileIdProviderTests to use JSON instead of YAML
- Package.resolved updated (Yams removed)

All 1920 tests pass without Yams.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace all YAML/Yams references with PKL:
- Config format: PKL (Programmable, Scalable, Safe)
- Config files: exfig.pkl
- Remove Yams from dependencies table

Part of Phase 6: Yams dependency removal

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add core protocols for plugin-based architecture:
- AssetType enum (colors, icons, images, typography)
- ExportResult struct for export operation results
- AssetExporter protocol for load/process/export cycle
- PlatformPlugin protocol for platform-specific plugins

TDD: Tests written first, then minimal implementation.
All 1950 tests pass (+30 new protocol tests).

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Create new ExFigConfig module with:
- PKL infrastructure (moved from ExFig): PKLLocator, PKLEvaluator, PKLError
- SourceConfig: Figma Variables and Frame source configuration
- AssetConfiguration: generic single/multiple config pattern
- NameProcessingConfig: regexp validation and transformation

Tests: 22 new tests for ExFigConfigTests
ExFig now depends on ExFigConfig and re-exports its types.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
ExFigConfig module created with:
- SourceConfig (Variables/Frame sources)
- AssetConfiguration (single/multiple pattern)
- NameProcessingConfig (regexp processing)
- PKL infrastructure (relocated from ExFig)

22 tests passing.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- All 1972 tests pass
- PKL error handling tests already exist
- No YAML fixtures to remove (migration complete)
- Coverage maintained at 49.32%

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Create ExFig-iOS target in Package.swift with ExFigCore, ExFigConfig deps
- Implement iOSPlugin conforming to PlatformPlugin protocol
- Add stub exporters: iOSColorsExporter, iOSIconsExporter, iOSImagesExporter, iOSTypographyExporter
- Add comprehensive TDD tests for plugin and exporters (12 tests passing)

This is the first platform plugin in the new plugin architecture.
Future commits will add the actual export logic migration from ExFig module.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…2-7.4)

- Add ExFig-Android with AndroidPlugin and 4 exporters
- Add ExFig-Flutter with FlutterPlugin and 3 exporters (no typography)
- Add ExFig-Web with WebPlugin and 3 exporters (no typography)
- All plugins conform to PlatformPlugin protocol
- Comprehensive TDD tests for all plugins (34 new tests)

This completes the plugin skeleton phase. All 4 platform plugins are now
available with their basic structure ready for export logic migration.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Mark plugin structure creation as complete (7.1-7.4):
- All 4 plugins created with PlatformPlugin conformance
- 46 TDD tests passing across all plugin modules
- Remaining work: Config entry types and export logic migration

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…hase 9.1-9.2)

- Create PluginRegistry with routing by config key, identifier, and platform
- Add 18 comprehensive tests for PluginRegistry functionality
- Update Package.swift to include plugin dependencies in ExFig target
- Update tasks.md with Phase 9 progress

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…7.x.5)

- Add iOSColorsEntry with xcassets and Swift extension options
- Add AndroidColorsEntry with XML, Kotlin, and ThemeAttributes
- Add FlutterColorsEntry with Dart output options
- Add WebColorsEntry with CSS, TypeScript, and JSON options
- All entries include VariablesSourceConfig and NameProcessingConfig helpers

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…(7.1.7)

- Add ExportContext and ColorsExportContext protocols in ExFigCore
- Add ColorsExporter protocol extending AssetExporter
- Add ColorsExportContextImpl bridging plugins to ExFig services
- Implement iOSColorsExporter.exportColors() with full load/process/export cycle
- Add iOSPlatformConfig for iOS-wide settings
- Add colorsSourceInput convenience property to iOSColorsEntry
- Update Package.swift: plugins now depend on platform Export modules
- Add tests for ColorsExporter conformance

This is the first platform plugin with full export logic migration.
The old extension-based code in iOSColorsExport.swift remains for now.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…b (7.2.7-7.4.7)

- Add AndroidColorsExporter.exportColors() with XML and Kotlin generation
- Add FlutterColorsExporter.exportColors() with Dart class generation
- Add WebColorsExporter.exportColors() with CSS/TypeScript/JSON generation
- Add platform configs: AndroidPlatformConfig, FlutterPlatformConfig, WebPlatformConfig
- Add colorsSourceInput convenience property to all ColorsEntry types
- Update all ColorsExporter tests with mock context validation

All 4 platform plugins now have full ColorsExporter implementations.
16 plugin tests passing.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…e 9.2)

Adds PluginRegistry to ExFigCore for managing and routing export
requests to platform plugins. This is the foundation for refactoring
export commands to use the plugin system.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Update proposal.md:
- Add IconsExporter, ImagesExporter, TypographyExporter protocols
- Add corresponding ExportContext protocols
- Update affected code section with new files

Update tasks.md:
- Add Phase 7b: Icons & Images Exporters
- Define tasks for core protocols (7b.1)
- Define platform-specific tasks for iOS, Android, Flutter, Web (7b.2-7b.5)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…contexts

IconsExportContext and ImagesExportContext need downloadFiles() method
that uses PipelinedDownloader for batch mode optimization (~45% speedup).

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add "Batch Processing Integration" section explaining how plugins
remain decoupled from BatchSharedState while still benefiting from
batch optimizations (PipelinedDownloader, shared queue, pre-fetch).

Key: *ExportContextImpl encapsulates all batch logic internally.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add core protocols for Icons and Images export:
- IconsExporter protocol with exportIcons() method
- IconsExportContext with loadIcons(), processIcons(), downloadFiles()
- ImagesExporter protocol with exportImages() method
- ImagesExportContext with loadImages(), processImages(), convertFormat(), rasterizeSVGs()

Add context implementations bridging plugins to ExFig services:
- IconsExportContextImpl using IconsLoader and PipelinedDownloader
- ImagesExportContextImpl with HEIC/WebP conversion support

Supporting types added:
- VectorFormat (svg, pdf) in IconsExportContext.swift
- ImageSourceFormat, ImageOutputFormat in ImagesExportContext.swift
- IconsSourceInput, IconsLoadOutput, IconsProcessResult
- ImagesSourceInput, ImagesLoadOutput, ImagesProcessResult
- ProgressReporter protocol for progress bar abstraction

Split ExportContext.swift into 3 files to stay under 400 line limit:
- ExportContext.swift (base + Colors)
- IconsExportContext.swift
- ImagesExportContext.swift

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add iOSIconsEntry and iOSImagesEntry config types
- Implement iOSIconsExporter with PDF/SVG support
- Implement iOSImagesExporter with PNG/HEIC/SVG workflows
- Add tests for IconsExporter and ImagesExporter protocols

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
alexey1312 and others added 15 commits February 7, 2026 12:47
- Refactor enum bridging logic for converting PKL `Common.NameStyle`
  to `ExFigCore.NameStyle`. This change simplifies code by leveraging
  a force-unwrap approach, relying on tests to ensure raw value
  consistency between enums.

- Implement error handling improvements while removing unnecessary
  name convention switch cases, replacing them with direct attribute
  accesses that simplify code structure.

- Add error representations for missing or invalid configuration data,
  ensuring clear messaging and recovery guidance when issues occur.

- Introduce validation extensions across multiple configuration files
  and add corresponding tests to cover scenarios with missing attributes.
  Additionally, integrate automated tests for bridging logic and
  configuration error handling.

These changes enhance code readability, maintainability, and provide
robust error handling, making it easier to extend functionality in
the future while ensuring high test coverage for crucial logic.
Archive completed migrate-pkl-config change (198/211 tasks done, 2140 tests).
Create new pkl-schema-v2 openspec change with proposal, design, specs, and
tasks for entry-level overrides, defaults, and constraints.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implement scale suffix stripping for filenames to adapt Android and
Flutter directory-based scaling. Replace `compactMap` with `map` for
final file mapping and utilize new `strippingScaleSuffix` method for
accurate filename processing. Introduce handling for WebP options
in format conversion and SVG rasterization, enhancing image export
flexibility. Extend test coverage to validate scale suffix logic and
enhance reliability.
* feat: add PKL schema defaults, entry overrides, and constraints

- Track 1: Add default values to all PKL schemas (Common, Figma, iOS,
  Android, Flutter, Web) reducing boilerplate in user configs
- Track 2: Add entry-level override fields (xcassetsPath, templatesPath,
  figmaFileId, mainRes, mainSrc, output) to entry types across platforms
- Track 4: Add PKL constraints (!isEmpty, isBetween) for validation
- Regenerate Swift types via pkl-gen-swift from updated schemas
- Fix enum bridging: kebab_case → kebabCase after codegen rename
- Update test call sites for new generated init signatures

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: update tasks status and fix formatting

- Mark tracks 1, 2, 4 as Done in tasks.md
- Apply swiftformat to generated ExFig.pkl.swift

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: exclude Generated/ from swiftformat and restore codegen output

SwiftLint already excluded Generated/ but SwiftFormat did not,
causing pre-commit hooks to reformat pkl-gen-swift output on every commit.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: add entry-level override resolution and fix example configs

- Add resolved computed properties (resolvedXcassetsPath, resolvedTemplatesPath,
  resolvedFigmaFileId, resolvedMainRes, resolvedMainSrc, resolvedOutput) to all
  platform entry types (iOS, Android, Flutter, Web)
- Fix example PKL configs to use Listing wrapper for entries (required by schema)
- Verify all verification tasks: codegen zero diff, pkl eval, constraints, tests
- Mark tracks 1, 2, 4 as complete; research tasks 3.1.x complete

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: wire entry-level override resolution into all platform exporters

All iOS, Android, Flutter, and Web exporters now resolve paths through
entry-level overrides before falling back to platform config values.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: thread entry-level figmaFileId through loader pipeline

Entry-level figmaFileId override flows from PKL config entry through
SourceInput → LoaderConfig → ImageLoaderBase.requireLightFileId(),
allowing per-entry Figma file overrides without changing global config.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* test: add entry-level override resolution tests for all platforms

21 tests covering resolved properties (xcassetsPath, mainRes,
templatesPath, figmaFileId) with override and fallback scenarios
for iOS, Android, Flutter, and Web entries.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: add entry-level overrides example configs and complete verification

- Add exfig-overrides.pkl: 6-in-1 example demonstrating entry-level
  overrides across all platforms
- Update exfig-ios.pkl with second icons entry showing overrides
- Mark all Track 5 tasks complete

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: add entry-level overrides, constraints, and defaults to MIGRATION.md

Document new PKL v2 features: entry-level path/file overrides,
schema validation constraints, and default values in schemas.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: archive pkl-schema-v2 change and sync specs

Sync delta specs (configuration, entry-overrides) to main specs.
Archive completed change to openspec/changes/archive/.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Implement the LocalizedError protocol for PklError, providing
localized error descriptions through errorDescription. This
enhancement improves error handling by offering clear and
contextual messages, aiding in debugging and user communication.
Add 'SVGKit' as a dependency for ExFig-Android to support SVG file
operations seamlessly. Refactor AndroidIconsExporter and
AndroidImagesExporter to eliminate unnecessary optional unwrapping
of URLs and data, improving stability and readability. Ensure file
cleanup processes log failures without interrupting execution flow,
enhancing error transparency.
Introduce effective source format and scale options to provide
default fallbacks for missing values. Enhance error handling for
unsupported formats with precondition checks. Modify image
scales to use floating point values for better precision. Add
guard statements during PKL evaluation to handle timeouts.
Ensure PluginRegistry uses precondition for consistent error handling.

These changes enhance robustness, ensure correct
configuration parsing, and prevent runtime failures due to
format conversion issues or unsupported values.
Integrate Noora for rich terminal UI elements, enhancing batch processing
feedback and readability. Key improvements:

1. Add Noora table for summarizing pre-fetch results and batch outcomes,
   improving clarity with visual tick/cross indicators for success/failure.
2. Embed Noora dependency in key modules (FileVersionPreFetcher, Batch).
3. Enhance WarningFormatter with compact output option, allowing for
   shortened asset lists with truncation messages in batch mode.
SwiftLint empty_count rule rewrites count > 0 to !isEmpty,
which requires the wrapper type to expose isEmpty.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@alexey1312
alexey1312 force-pushed the alexey1312/migrate-pkl-config branch from 76f9e09 to 8f90ca7 Compare February 8, 2026 13:47
@alexey1312
alexey1312 force-pushed the alexey1312/migrate-pkl-config branch from 597142e to 421e435 Compare February 8, 2026 15:52
Enhance `discoverAndValidateConfigs` to detect output path conflicts
and return them alongside valid configs. In `executeBatch` and
`displayBatchStartInfo`, add logic to handle and display path
conflicts for better user awareness during batch processing. This change
improves transparency about potential resource conflicts
between config files.
@alexey1312
alexey1312 force-pushed the alexey1312/migrate-pkl-config branch from 421e435 to cec36a3 Compare February 9, 2026 06:30
Enhance the `getFileIds` function in `PKLConfig+FileIdProvider.swift`
to gather Figma file IDs for icons, images, and typography from config.
Add corresponding tests in `FileIdProviderTests.swift` for coverage.
This ensures all relevant Figma file sources are considered, aiding
better asset management and integration across platforms.
Introduce download progress reporting to the batch processes by
adding a download progress callback. This callback updates the
BatchProgressView with the progress of individual config asset
downloads (colors, icons, images, typography).

Previously, download progress was not captured in a centralized
progress view, which made tracking batch operations cumbersome. By
capturing progress, users gain better insight into ongoing batch
operations, improving usability and debugging ease.

Additionally, update ExFigLogHandler to suppress non-critical logs
in batch mode to avoid progress view interference, while enabling
verbose logging for batch warnings and errors.
@alexey1312
alexey1312 marked this pull request as ready for review February 9, 2026 12:36
@alexey1312
alexey1312 merged commit 0cdf2c4 into main Feb 9, 2026
9 checks passed
@alexey1312
alexey1312 deleted the alexey1312/migrate-pkl-config branch February 9, 2026 12:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant