require 'json' require 'fileutils' class ThemeGenerator def initialize(input_path, output_path, language) @theme = JSON.parse(File.read(input_path)) @output_path = output_path @language = language.downcase unless %w[kotlin swift dart].include?(@language) raise ArgumentError, "Unsupported language. Choose 'kotlin', 'swift', or 'dart'." end end def generate code = send("generate_#{@language}") write_to_file(code) end private def generate_kotlin kotlin_code = "import androidx.compose.ui.graphics.Color\n" kotlin_code += "import androidx.compose.ui.unit.dp\n" kotlin_code += "import androidx.compose.ui.unit.sp\n\n" kotlin_code += "object #{@theme['name']} {\n" kotlin_code += generate_kotlin_colors kotlin_code += generate_kotlin_typography kotlin_code += generate_kotlin_spacing kotlin_code += generate_kotlin_border_radius kotlin_code += generate_kotlin_elevation kotlin_code += "}" kotlin_code end def generate_swift swift_code = "import SwiftUI\n\n" swift_code += "struct #{@theme['name']} {\n" swift_code += generate_swift_colors swift_code += generate_swift_typography swift_code += generate_swift_spacing swift_code += generate_swift_border_radius swift_code += generate_swift_elevation swift_code += "}\n\n" swift_code += generate_swift_colors_hext_extension swift_code end def generate_dart dart_code = "import 'package:flutter/material.dart';\n\n" dart_code += generate_dart_colors dart_code += generate_dart_typography dart_code += generate_dart_spacing dart_code += generate_dart_border_radius dart_code += generate_dart_elevation dart_code end def write_to_file(code) FileUtils.mkdir_p(File.dirname(@output_path)) File.write(@output_path, code) Solara.logger.debug("Generated #{@language.capitalize} theme file: #{@output_path}") end def generate_kotlin_colors code = " object Colors {\n" @theme['colors'].each do |name, value| code += " val #{name} = Color(0xFF#{value[1..-1]})\n" end code += " }\n\n" code end def generate_kotlin_typography code = " object Typography {\n" code += " object FontFamily {\n" @theme['typography']['fontFamily'].each do |name, value| code += " val #{name} = \"#{value}\"\n" end code += " }\n\n" code += " object FontSize {\n" @theme['typography']['fontSize'].each do |name, value| code += " val #{name} = #{value}.sp\n" end code += " }\n" code += " }\n\n" code end def generate_kotlin_spacing code = " object Spacing {\n" @theme['spacing'].each do |name, value| code += " val #{name} = #{value}.dp\n" end code += " }\n\n" code end def generate_kotlin_border_radius code = " object BorderRadius {\n" @theme['borderRadius'].each do |name, value| code += " val #{name} = #{value}.dp\n" end code += " }\n\n" code end def generate_kotlin_elevation code = " object Elevation {\n" @theme['elevation'].each do |name, value| code += " val #{name} = #{value}.dp\n" end code += " }\n" code end def generate_swift_colors code = " struct Colors {\n" @theme['colors'].each do |name, value| code += " static let #{name} = Color(hex: \"#{value}\")\n" end code += " }\n\n" code end def generate_swift_colors_hext_extension code = <<-SWIFT extension Color { init(hex: String) { let hex = hex.trimmingCharacters(in: CharacterSet.alphanumerics.inverted) var int: UInt64 = 0 Scanner(string: hex).scanHexInt64(&int) let a, r, g, b: UInt64 switch hex.count { case 3: // RGB (12-bit) (a, r, g, b) = (255, (int >> 8) * 17, (int >> 4 & 0xF) * 17, (int & 0xF) * 17) case 6: // RGB (24-bit) (a, r, g, b) = (255, int >> 16, int >> 8 & 0xFF, int & 0xFF) case 8: // ARGB (32-bit) (a, r, g, b) = (int >> 24, int >> 16 & 0xFF, int >> 8 & 0xFF, int & 0xFF) default: (a, r, g, b) = (1, 1, 1, 0) } self.init( .sRGB, red: Double(r) / 255, green: Double(g) / 255, blue: Double(b) / 255, opacity: Double(a) / 255 ) } } SWIFT code end def generate_swift_typography code = " struct Typography {\n" code += " struct FontFamily {\n" @theme['typography']['fontFamily'].each do |name, value| code += " static let #{name} = \"#{value}\"\n" end code += " }\n\n" code += " struct FontSize {\n" @theme['typography']['fontSize'].each do |name, value| code += " static let #{name}: CGFloat = #{value}\n" end code += " }\n" code += " }\n\n" code end def generate_swift_spacing code = " struct Spacing {\n" @theme['spacing'].each do |name, value| code += " static let #{name}: CGFloat = #{value}\n" end code += " }\n\n" code end def generate_swift_border_radius code = " struct BorderRadius {\n" @theme['borderRadius'].each do |name, value| code += " static let #{name}: CGFloat = #{value}\n" end code += " }\n\n" code end def generate_swift_elevation code = " struct Elevation {\n" @theme['elevation'].each do |name, value| code += " static let #{name}: CGFloat = #{value}\n" end code += " }\n" code end def generate_dart_colors code = " class BrandColors {\n" @theme['colors'].each do |name, value| code += " static const Color #{name} = Color(0xFF#{value[1..-1]});\n" end code += " }\n\n" code end def generate_dart_typography code = " class FontFamily {\n" @theme['typography']['fontFamily'].each do |name, value| code += " static const String #{name} = '#{value}';\n" end code += " }\n\n" code += " class FontSize {\n" @theme['typography']['fontSize'].each do |name, value| code += " static const double #{name} = #{value};\n" end code += " }\n\n" code end def generate_dart_spacing code = " class Spacing {\n" @theme['spacing'].each do |name, value| code += " static const double #{name} = #{value};\n" end code += " }\n\n" code end def generate_dart_border_radius code = " class BorderRadius {\n" @theme['borderRadius'].each do |name, value| code += " static const double #{name} = #{value};\n" end code += " }\n\n" code end def generate_dart_elevation code = " class Elevation {\n" @theme['elevation'].each do |name, value| code += " static const double #{name} = #{value};\n" end code += " }\n" code end end