module Language Kotlin = 'kotlin' Swift = 'swift' Dart = 'dart' def self.all [Kotlin, Swift, Dart] end end def init(language) if Language.all.include?(language) # Do something with the valid language else raise ArgumentError, "Invalid language. Please use one of: #{Language.all.join(', ')}" end end class BrandConfigGenerator def initialize(config, output_dir, language, platform) @output_dir = output_dir @language = language @platform = platform @config = config end def generate content = generate_config_content FileManager.create_file_if_not_exist(@output_dir) File.write(@output_dir, content) Solara.logger.debug("Generated brand config #{@output_dir} for: #{@language}") end private def generate_config_content content = "// Generated by Solara\n" content += language_specific_imports classes = [] generate_classes("BrandConfig", @config, classes) classes.reverse_each do |class_content| content += class_content content += "\n" end content end def language_specific_imports case @language when 'dart' "import 'package:flutter/material.dart';\n\n" when 'kotlin' "import android.graphics.Color\n\n" when 'swift' "import UIKit\n\n" end end def generate_classes(class_name, config, classes) content = class_declaration(class_name) constructor_params = [] config.each do |key, value| type = value_type(value, key) content += property_declaration(key, type) constructor_params << constructor_parameter(key, type) end content += constructor_declaration(class_name, constructor_params) content += instance_declaration(class_name, config) content += class_closing classes << content config.each do |key, value| if value.is_a?(Hash) nested_class_name = "#{key.capitalize}" generate_classes(nested_class_name, value, classes) end end end def class_declaration(class_name) case @language when 'dart' "class #{class_name} {\n" when 'kotlin' "data class #{class_name}(\n" when 'swift' "struct #{class_name} {\n" end end def property_declaration(key, type) case @language when 'dart' " final #{type} #{key};\n" when 'kotlin' " val #{key}: #{type},\n" when 'swift' " let #{key}: #{type}\n" end end def constructor_parameter(key, type) case @language when 'dart' "required this.#{key}" when 'kotlin' "val #{key}: #{type}" when 'swift' "#{key}: #{type}" end end def constructor_declaration(class_name, params) case @language when 'dart' params.empty? ? "\n const #{class_name}();\n\n" : "\n const #{class_name}({#{params.join(', ')}});\n\n" when 'kotlin' ") {\n" when 'swift' "\n init(#{params.join(', ')}) {\n#{params.map { |p| " self.#{p.split(':').first} = #{p.split(':').first}" }.join("\n")}\n }\n\n" end end def instance_declaration(class_name, config) case @language when 'dart' " static const #{class_name} instance = #{class_name}(\n#{config.map { |k, v| " #{k}: #{value_for(v, k, ' ')}" }.join(",\n")}\n );\n" when 'kotlin' "companion object {\n val instance = #{class_name}(\n#{config.map { |k, v| " #{k} = #{value_for(v, k, ' ')}" }.join(",\n")}\n )\n}\n" when 'swift' " static let shared = #{class_name}(\n#{config.map { |k, v| " #{k}: #{value_for(v, k, ' ')}" }.join(",\n")}\n )\n" end end def class_closing @language == 'swift' ? "}\n" : "}\n" end def value_type(value, class_prefix) case value when String then language_specific_type('String') when Integer then language_specific_type('Int') when Float then language_specific_type('Double') when TrueClass, FalseClass then language_specific_type('Bool') when Array if value.all? { |item| item.is_a?(String) } language_specific_type('Array') elsif value.all? { |item| item.is_a?(Integer) } language_specific_type('Array') elsif value.all? { |item| item.is_a?(Float) } language_specific_type('Array') elsif value.all? { |item| item.is_a?(TrueClass) || item.is_a?(FalseClass) } language_specific_type('Array') else language_specific_type('Array') end when Hash then "#{class_prefix.capitalize}" else language_specific_type('Any') end end def language_specific_type(type) case @language when 'dart' case type when 'String' then 'String' when 'Int' then 'int' when 'Double' then 'double' when 'Bool' then 'bool' when 'Array' then 'List' when 'Array' then 'List' when 'Array' then 'List' when 'Array' then 'List' when 'Array' then 'List' when 'Any' then 'dynamic' else type end when 'kotlin' case type when 'Array' then 'List' when 'Array' then 'List' when 'Array' then 'List' when 'Array' then 'List' when 'Array' then 'List' when 'Any' then 'Any' else type end when 'swift' type end end def value_for(value, class_prefix, indent) case value when String if value.start_with?('#') && value.length == 7 # Assume it's a color color_for(value) else value.inspect end when Integer, Float value.to_s when TrueClass, FalseClass value.to_s when Array array_items = value.map { |item| value_for(item, class_prefix, indent + ' ') }.join(', ') "[\n#{indent} #{array_items}\n#{indent}]" when Hash "#{class_prefix.capitalize}.instance" else language_specific_null end end def color_for(value) case @language when 'dart' "Color(0xFF#{value[1..-1]})" when 'kotlin' "Color.parseColor(\"#{value}\")" when 'swift' "UIColor(red: #{hex_to_rgb(value[:red])}, green: #{hex_to_rgb(value[:green])}, blue: #{hex_to_rgb(value[:blue])}, alpha: 1.0)" end end def hex_to_rgb(hex) hex.to_i(16) / 255.0 end def language_specific_null case @language when 'dart', 'swift' 'null' when 'kotlin' 'null' end end end