Migrate to PKL configuration and plugin architecture (v2.0) - #48
Conversation
Summary of ChangesHello @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
Changelog
Ignored Files
Activity
Using Gemini Code AssistThe 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
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 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
|
There was a problem hiding this comment.
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.
d514140 to
e6f21b2
Compare
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>
- 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>
76f9e09 to
8f90ca7
Compare
597142e to
421e435
Compare
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.
421e435 to
cec36a3
Compare
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.
Summary
Major architecture overhaul replacing YAML configuration with PKL and restructuring the monolithic codebase into a plugin-based architecture.
amends/extendsPlatformPluginandAssetExporterprotocolsPKLLocator,PKLEvaluator, schema validation)Architecture
PKL Configuration Schema
Users create configs by amending the schema:
Config inheritance via PKL
amends:Plugin System
Data flow:
CLI → PKL config → PluginRegistry → Platform Exporter → ExportContext → File OutputPlugins remain decoupled from batch infrastructure — all batch optimizations (PipelinedDownloader, ComponentPreFetcher, GranularCache) are encapsulated in
*ExportContextImplwithin ExFigCLI.Key Protocols (ExFigCore)
PlatformPluginColorsExporterIconsExporterImagesExporterTypographyExporter*ExportContextBreaking Changes
exfig.pklmise use pkl)Stats
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