solara 0.2.0 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. checksums.yaml +4 -4
  2. data/solara/lib/core/.DS_Store +0 -0
  3. data/solara/lib/core/aliases/alias_generator.rb +1 -0
  4. data/solara/lib/core/aliases/alias_generator_manager.rb +2 -1
  5. data/solara/lib/core/aliases/solara_terminal_setup.rb +1 -1
  6. data/solara/lib/core/brands/brand_font_switcher.rb +154 -0
  7. data/solara/lib/core/brands/brand_onboarder.rb +8 -6
  8. data/solara/lib/core/brands/brand_switcher.rb +232 -166
  9. data/solara/lib/core/brands/brands_manager.rb +15 -39
  10. data/solara/lib/core/dashboard/brand/BrandDetail.js +19 -0
  11. data/solara/lib/core/dashboard/brand/BrandDetailController.js +50 -8
  12. data/solara/lib/core/dashboard/brand/BrandDetailModel.js +9 -30
  13. data/solara/lib/core/dashboard/brand/BrandDetailView.js +49 -3
  14. data/solara/lib/core/dashboard/brand/InfoPlistStringCatalogManager.js +19 -0
  15. data/solara/lib/core/dashboard/brand/brand.html +209 -62
  16. data/solara/lib/core/dashboard/brand/source/BrandLocalSource.js +1 -1
  17. data/solara/lib/core/dashboard/brand/source/BrandRemoteSource.js +38 -53
  18. data/solara/lib/core/dashboard/brands/BrandsController.js +6 -5
  19. data/solara/lib/core/dashboard/brands/BrandsModel.js +2 -2
  20. data/solara/lib/core/dashboard/brands/BrandsView.js +2 -2
  21. data/solara/lib/core/dashboard/brands/brands.html +3 -1
  22. data/solara/lib/core/dashboard/component/AliasesBottomSheet.js +7 -5
  23. data/solara/lib/core/dashboard/dashboard_manager.rb +2 -0
  24. data/solara/lib/core/dashboard/dashboard_server.rb +13 -8
  25. data/solara/lib/core/dashboard/handler/brand_alisases_handler.rb +4 -11
  26. data/solara/lib/core/dashboard/handler/brand_configurations_manager.rb +11 -11
  27. data/solara/lib/core/dashboard/handler/{brand_configurations_handler.rb → brand_details_handler.rb} +4 -4
  28. data/solara/lib/core/dashboard/handler/brands_handler.rb +1 -1
  29. data/solara/lib/core/dashboard/handler/edit_section_handler.rb +8 -8
  30. data/solara/lib/core/doctor/brand_doctor.rb +31 -31
  31. data/solara/lib/core/doctor/doctor_manager.rb +0 -1
  32. data/solara/lib/core/doctor/project_doctor.rb +0 -1
  33. data/solara/lib/core/doctor/schema/platform/android/android_config.json +0 -4
  34. data/solara/lib/core/doctor/schema/platform/ios/InfoPlist.xcstrings +15 -0
  35. data/solara/lib/core/doctor/schema/platform/ios/ios_config.json +0 -5
  36. data/solara/lib/core/doctor/schema/platform/shared/brand_config.json +9 -0
  37. data/solara/lib/core/doctor/schema/platform/shared/theme.json +94 -9
  38. data/solara/lib/core/doctor/validator/brand_settings_validator.rb +6 -0
  39. data/solara/lib/core/doctor/validator/brand_settings_validator_manager.rb +9 -21
  40. data/solara/lib/core/doctor/validator/template/android_template_validation_config.yml +22 -4
  41. data/solara/lib/core/doctor/validator/template/flutter_template_validation_config.yml +22 -6
  42. data/solara/lib/core/doctor/validator/template/ios_template_validation_config.yml +22 -4
  43. data/solara/lib/core/scripts/brand_config_generator.rb +1 -0
  44. data/solara/lib/core/scripts/brand_config_manager.rb +2 -4
  45. data/solara/lib/core/scripts/brand_exporter.rb +1 -1
  46. data/solara/lib/core/scripts/brand_importer.rb +2 -3
  47. data/solara/lib/core/scripts/brand_offboarder.rb +5 -0
  48. data/solara/lib/core/scripts/brand_resources_manager.rb +127 -54
  49. data/solara/lib/core/scripts/directory_creator.rb +2 -2
  50. data/solara/lib/core/scripts/file_manager.rb +53 -19
  51. data/solara/lib/core/scripts/file_path.rb +175 -30
  52. data/solara/lib/core/scripts/folder_copier.rb +3 -7
  53. data/solara/lib/core/scripts/gitignore_manager.rb +21 -10
  54. data/solara/lib/core/scripts/interactive_file_system_validator.rb +8 -2
  55. data/solara/lib/core/scripts/platform/android/android_manifest_switcher.rb +3 -3
  56. data/solara/lib/core/scripts/platform/android/android_strings_switcher.rb +26 -24
  57. data/solara/lib/core/scripts/platform/android/gradle_switcher.rb +7 -6
  58. data/solara/lib/core/scripts/platform/ios/infoplist_string_catalog_manager.rb +123 -0
  59. data/solara/lib/core/scripts/platform/ios/infoplist_switcher.rb +59 -0
  60. data/solara/lib/core/scripts/platform/ios/ios_plist_manager.rb +11 -20
  61. data/solara/lib/core/scripts/platform/ios/plist_font_manager.rb +33 -0
  62. data/solara/lib/core/scripts/platform/ios/xcconfig_generator.rb +15 -3
  63. data/solara/lib/core/scripts/platform/ios/xcode_asset_manager.rb +2 -3
  64. data/solara/lib/core/scripts/platform/ios/xcode_project_manager.rb +80 -1
  65. data/solara/lib/core/scripts/platform/ios/xcode_project_switcher.rb +15 -34
  66. data/solara/lib/core/scripts/solara_logger.rb +10 -0
  67. data/solara/lib/core/scripts/solara_settings_manager.rb +26 -1
  68. data/solara/lib/core/scripts/strings_xml_manager.rb +17 -2
  69. data/solara/lib/core/scripts/theme_generator.rb +133 -130
  70. data/solara/lib/core/scripts/yaml_manager.rb +23 -0
  71. data/solara/lib/core/solara_configurator.rb +1 -1
  72. data/solara/lib/core/template/brands/android/android_config.json +0 -1
  73. data/solara/lib/core/template/brands/android/res/values/strings.xml +4 -0
  74. data/solara/lib/core/template/brands/ios/InfoPlist.xcstrings +30 -0
  75. data/solara/lib/core/template/brands/ios/ios_config.json +1 -2
  76. data/solara/lib/core/template/brands/shared/brand_config.json +1 -0
  77. data/solara/lib/core/template/brands/shared/theme.json +3 -3
  78. data/solara/lib/core/template/config/android_template_config.json +11 -1
  79. data/solara/lib/core/template/config/flutter_template_config.json +12 -2
  80. data/solara/lib/core/template/config/ios_template_config.json +11 -1
  81. data/solara/lib/core/template/project_template_generator.rb +8 -3
  82. data/solara/lib/solara/version.rb +1 -1
  83. data/solara/lib/solara.rb +8 -4
  84. data/solara/lib/solara_initializer.rb +5 -2
  85. data/solara/lib/solara_manager.rb +1 -1
  86. metadata +62 -43
  87. data/solara/lib/core/dashboard/handler/brand_section_handler.rb +0 -20
  88. data/solara/lib/core/doctor/validator/directory_structure_validator.rb +0 -38
  89. data/solara/lib/core/doctor/validator/file_structure_validator.rb +0 -37
  90. data/solara/lib/core/scripts/platform/ios/ios_file_path_manager.rb +0 -109
  91. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/.DS_Store +0 -0
  92. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/100.png +0 -0
  93. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/102.png +0 -0
  94. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/1024.png +0 -0
  95. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/114.png +0 -0
  96. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/120.png +0 -0
  97. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/128.png +0 -0
  98. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/144.png +0 -0
  99. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/152.png +0 -0
  100. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/16.png +0 -0
  101. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/167.png +0 -0
  102. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/172.png +0 -0
  103. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/180.png +0 -0
  104. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/196.png +0 -0
  105. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/20.png +0 -0
  106. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/216.png +0 -0
  107. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/256.png +0 -0
  108. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/29.png +0 -0
  109. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/32.png +0 -0
  110. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/40.png +0 -0
  111. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/48.png +0 -0
  112. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/50.png +0 -0
  113. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/512.png +0 -0
  114. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/55.png +0 -0
  115. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/57.png +0 -0
  116. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/58.png +0 -0
  117. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/60.png +0 -0
  118. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/64.png +0 -0
  119. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/66.png +0 -0
  120. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/72.png +0 -0
  121. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/76.png +0 -0
  122. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/80.png +0 -0
  123. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/87.png +0 -0
  124. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/88.png +0 -0
  125. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/92.png +0 -0
  126. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/Contents.json +0 -0
@@ -90,26 +90,28 @@ class AliasesBottomSheet extends HTMLElement {
90
90
  this.overlay.onclick = () => this.hide();
91
91
  }
92
92
 
93
- show(aliases, brand) {
93
+ show(aliases, brandKey) {
94
94
  const commonAliasesList = this.shadowRoot.getElementById('commonAliasesList');
95
95
  const brandAliasesList = this.shadowRoot.getElementById('brandAliasesList');
96
96
 
97
97
  commonAliasesList.innerHTML = '';
98
98
  brandAliasesList.innerHTML = '';
99
99
 
100
+ const pattern = /alias|='[^']*'/g;
101
+
100
102
  aliases.aliases.common_aliases.forEach(alias => {
101
103
  const li = document.createElement('li');
102
- li.textContent = alias;
104
+ li.textContent = alias.replace(pattern, '').trim();
103
105
  commonAliasesList.appendChild(li);
104
106
  });
105
107
 
106
- const brandAliases = aliases.aliases.brand_aliases[brand.key] || [];
108
+ const brandAliases = aliases.aliases.brand_aliases[brandKey] || [];
109
+
107
110
  brandAliases.forEach(alias => {
108
111
  const li = document.createElement('li');
109
- li.textContent = alias;
112
+ li.textContent = alias.replace(pattern, '').trim();
110
113
  brandAliasesList.appendChild(li);
111
114
  });
112
-
113
115
  this.aliasesBottomSheet.style.display = 'block';
114
116
  this.overlay.style.display = 'block';
115
117
 
@@ -1,6 +1,8 @@
1
1
  class DashboardManager
2
2
 
3
3
  def start(brand_key = nil, port = 8000)
4
+ return if SolaraEnvironment.is_test
5
+
4
6
  Solara.logger.header("Solara Dashboard #{brand_key.nil? || brand_key.empty? ? "" : "for #{brand_key}"}")
5
7
  if brand_key.nil? || brand_key.empty?
6
8
  open("brands/brands.html?source=local", port)
@@ -1,5 +1,4 @@
1
1
  Dir[File.expand_path('handler/*.rb', __dir__)].each { |file| require_relative file }
2
- Dir[File.expand_path('../.solara/core/brands/*.rb')].each { |file| require_relative file }
3
2
  Dir[File.expand_path('platform/android/*.rb', __dir__)].each { |file| require_relative file }
4
3
  Dir[File.expand_path('scripts/*.rb', __dir__)].each { |file| require_relative file }
5
4
 
@@ -29,7 +28,7 @@ class DashboardServer
29
28
  end
30
29
 
31
30
  def shutdown
32
- Solara.logger.debug("Shutting down server...")
31
+ Solara.logger.info("Shutting down server...")
33
32
  @server.shutdown if @server
34
33
  end
35
34
 
@@ -65,10 +64,9 @@ class DashboardServer
65
64
  return if @router.nil?
66
65
 
67
66
  @router.register_handler(RedirectHandler)
68
- @router.register_handler(BrandSectionHandler)
69
67
  @router.register_handler(SwitchToBrandHandler)
70
68
  @router.register_handler(CurrentBrandHandler)
71
- @router.register_handler(BrandConfigurationsHandler)
69
+ @router.register_handler(BrandDetailsHandler)
72
70
  @router.register_handler(BrandsHandler)
73
71
  @router.register_handler(EditSectionHandler)
74
72
  @router.register_handler(OnboardBrandHandler)
@@ -83,9 +81,10 @@ class DashboardServer
83
81
  end
84
82
 
85
83
  def print_server_info
86
- Solara.logger.debug("Server starting on http://localhost:#{@port}")
87
- Solara.logger.debug("Serving files from: #{@root}")
88
- Solara.logger.debug("Press Ctrl+C to stop the server")
84
+ Solara.logger.info("Please click the link or copy and paste it into your browser if it doesn't open automatically: http://localhost:#{@port}")
85
+ Solara.logger.info("Server starting on http://localhost:#{@port}")
86
+ Solara.logger.info("Serving files from: #{@root}")
87
+ Solara.logger.info("Press Ctrl+C to stop the server")
89
88
  end
90
89
 
91
90
  def start_server
@@ -106,7 +105,13 @@ class DashboardServer
106
105
  when /darwin/
107
106
  system "/usr/bin/open", url
108
107
  when /linux/
109
- system "/usr/bin/xdg-open", url
108
+ # Check if we're in WSL
109
+ if File.exist?('/proc/version') && File.read('/proc/version').include?('Microsoft')
110
+ # Use the Windows start command to open in WSL
111
+ system "cmd.exe", "/c", "start", url
112
+ else
113
+ system "/usr/bin/xdg-open", url
114
+ end
110
115
  when /mswin|mingw|cygwin/
111
116
  system "start", url
112
117
  end
@@ -3,17 +3,10 @@ class BrandAliasesHandler < BaseHandler
3
3
  @server.mount_proc('/brand/aliases') do |req, res|
4
4
  if req.request_method == 'GET'
5
5
  begin
6
- query = CGI.parse(req.query_string)
7
- brand_key = query['brand_key']&.first
6
+ aliases = get_brand_aliases
7
+ res.status = 200
8
+ res.body = JSON.generate({ success: true, aliases: aliases })
8
9
 
9
- if brand_key
10
- aliases = get_brand_aliases(brand_key)
11
- res.status = 200
12
- res.body = JSON.generate({ success: true, aliases: aliases })
13
- else
14
- res.status = 400
15
- res.body = JSON.generate({ success: false, error: 'Missing brand_key parameter' })
16
- end
17
10
  rescue StandardError => e
18
11
  handle_error(res, e, "Error fetching brand aliases")
19
12
  end
@@ -24,7 +17,7 @@ class BrandAliasesHandler < BaseHandler
24
17
  end
25
18
  end
26
19
 
27
- def get_brand_aliases(brand_key)
20
+ def get_brand_aliases
28
21
  AliasGeneratorManager.aliases_json
29
22
  rescue StandardError => e
30
23
  Solara.logger.failure("Error getting brand aliases: #{e.message}")
@@ -11,37 +11,37 @@ class BrandConfigurationsManager
11
11
  def templates
12
12
  [
13
13
  {
14
- key: 'theme',
15
- name: 'Theme Configuration',
16
- input_type: 'color',
17
- path: FilePath.brand_theme(@brand_key)
18
- },
19
- {
20
- key: 'brand_config',
14
+ key: 'brand_config.json',
21
15
  name: 'Brand Configuration',
22
16
  input_type: 'text',
23
17
  path: FilePath.brand_config(@brand_key)
24
18
  },
25
19
  {
26
- key: 'android_config',
20
+ key: 'theme.json',
21
+ name: 'Theme Configuration',
22
+ input_type: 'color',
23
+ path: FilePath.brand_theme(@brand_key)
24
+ },
25
+ {
26
+ key: 'android_config.json',
27
27
  name: 'Android Platform Configuration',
28
28
  input_type: 'text',
29
29
  path: FilePath.android_brand_config(@brand_key)
30
30
  },
31
31
  {
32
- key: 'android_signing',
32
+ key: 'android_signing.json',
33
33
  name: 'Android Signing',
34
34
  input_type: 'text',
35
35
  path: FilePath.brand_signing(@brand_key, Platform::Android)
36
36
  },
37
37
  {
38
- key: 'ios_config',
38
+ key: 'ios_config.json',
39
39
  name: 'iOS Platform Configuration',
40
40
  input_type: 'text',
41
41
  path: FilePath.ios_config(@brand_key)
42
42
  },
43
43
  {
44
- key: 'ios_signing',
44
+ key: 'ios_signing.json',
45
45
  name: 'iOS Signing',
46
46
  input_type: 'text',
47
47
  path: FilePath.brand_signing(@brand_key, Platform::IOS)
@@ -1,15 +1,15 @@
1
- class BrandConfigurationsHandler < BaseHandler
1
+ class BrandDetailsHandler < BaseHandler
2
2
  def mount
3
- @server.mount_proc('/configurations') do |req, res|
3
+ @server.mount_proc('/brand/details') do |req, res|
4
4
  begin
5
5
  query = CGI.parse(req.query_string)
6
6
  brand_key = query['brand_key']&.first
7
7
 
8
8
  response_data = BrandsManager.instance.brand_with_configurations(brand_key)
9
- res.body = JSON.generate({ success: true, message: "Configurations response", result: response_data })
9
+ res.body = JSON.generate({ success: true, message: "Brand details response", result: response_data })
10
10
  res['Content-Type'] = 'application/json'
11
11
  rescue StandardError => e
12
- handle_error(res, e, "Error in brand configurations handler")
12
+ handle_error(res, e, "Error in brand details handler")
13
13
  end
14
14
  end
15
15
  end
@@ -1,6 +1,6 @@
1
1
  class BrandsHandler < BaseHandler
2
2
  def mount
3
- @server.mount_proc('/brands.json') do |req, res|
3
+ @server.mount_proc('/brands/all') do |req, res|
4
4
  begin
5
5
  brands_list = BrandsManager.instance.brands_list
6
6
  json = JSON.generate(brands_list)
@@ -31,8 +31,13 @@ class EditSectionHandler < BaseHandler
31
31
  template = BrandConfigurationsManager.new(brand_key).template_with_key(key)
32
32
 
33
33
  path = template[:path]
34
+
34
35
  if File.exist?(path)
35
- File.write(path, JSON.pretty_generate(data))
36
+ if key === 'InfoPlist.xcstrings'
37
+ InfoPListStringCatalogManager.new(FilePath.brand_infoplist_string_catalog(brand_key)).update(data)
38
+ else
39
+ File.write(path, JSON.pretty_generate(data))
40
+ end
36
41
  Solara.logger.debug("Updated Config for #{path}: #{data}")
37
42
  else
38
43
  raise "Config file not found: #{path}"
@@ -42,14 +47,9 @@ class EditSectionHandler < BaseHandler
42
47
  raise
43
48
  end
44
49
 
45
- def update_theme(path, data)
46
- json = JSON.parse(File.read(path))
47
- json['colors'] = data
48
- File.write(path, JSON.pretty_generate(json))
49
- end
50
-
51
50
  def set_current_brand_content_changed(brand_key, changed)
52
51
  BrandsManager.instance.set_current_brand_content_changed(brand_key, changed)
53
52
  end
54
53
 
55
- end
54
+ end
55
+
@@ -1,35 +1,6 @@
1
1
  Dir.glob("#{__dir__}/*.rb").each { |file| require file }
2
- Dir.glob("#{__dir__}/../../.solara/core/brands/*.rb").each { |file| require file }
3
2
  Dir.glob("#{__dir__}/validator/template/*.rb").each { |file| require file }
4
3
 
5
- class Issue < StandardError
6
- ERROR = 'ERROR'
7
- WARNING = 'WARNING'
8
-
9
- attr_reader :type, :error
10
-
11
- def initialize(type, error)
12
- @type = type
13
- @error = error
14
- end
15
-
16
- def to_s
17
- "#{@type}: #{@error}"
18
- end
19
-
20
- def <=>(other)
21
- [type, error] <=> [other.type, other.error]
22
- end
23
-
24
- def self.error(error)
25
- Issue.new(ERROR, error)
26
- end
27
-
28
- def self.warning(error)
29
- Issue.new(WARNING, error)
30
- end
31
- end
32
-
33
4
  class BrandDoctor
34
5
  def initialize
35
6
  end
@@ -37,6 +8,7 @@ class BrandDoctor
37
8
  def visit(brand_keys = [], print_logs: true)
38
9
  keys = brand_keys.empty? ? BrandsManager.instance.brands_list.map { |brand| brand['key'] } : brand_keys
39
10
  issues = []
11
+ has_template_errors = false
40
12
 
41
13
  keys.each do |brand_key|
42
14
  validator = TemplateValidator.new(FilePath.brand(brand_key), FilePath.template_validation_config)
@@ -45,15 +17,16 @@ class BrandDoctor
45
17
  errors.each { |error|
46
18
  issues << Issue.error(error)
47
19
  }
20
+ has_template_errors = true unless issues.select { |issue| issue.type == Issue::ERROR }.empty?
48
21
  end
49
22
 
50
23
  # Validate settings only if all validations so far are passed to avoid files issues
51
- if issues.select { |issue| issue.type == Issue::ERROR }.empty?
24
+ unless has_template_errors
52
25
  issues += BrandSettingsValidatorManager.new.validate
53
26
  end
54
27
 
55
28
  if print_logs && !issues.empty?
56
- Solara.logger.title("Healt Check Result")
29
+ Solara.logger.title("Health Check Result")
57
30
 
58
31
  issues.sort!.each { |issue|
59
32
  case issue.type
@@ -92,3 +65,30 @@ class BrandDoctor
92
65
  end
93
66
  end
94
67
 
68
+ class Issue < StandardError
69
+ ERROR = 'ERROR'
70
+ WARNING = 'WARNING'
71
+
72
+ attr_reader :type, :error
73
+
74
+ def initialize(type, error)
75
+ @type = type
76
+ @error = error
77
+ end
78
+
79
+ def to_s
80
+ "#{@type}: #{@error}"
81
+ end
82
+
83
+ def <=>(other)
84
+ [type, error] <=> [other.type, other.error]
85
+ end
86
+
87
+ def self.error(error)
88
+ Issue.new(ERROR, error)
89
+ end
90
+
91
+ def self.warning(error)
92
+ Issue.new(WARNING, error)
93
+ end
94
+ end
@@ -1,7 +1,6 @@
1
1
  Dir.glob("#{__dir__}/*.rb").each { |file| require file }
2
2
  Dir.glob("#{__dir__}/validator/*.rb").each { |file| require file }
3
3
  Dir.glob("#{__dir__}/brand/*.rb").each { |file| require file }
4
- Dir.glob("#{__dir__}/../../.solara/core/brands/*.rb").each { |file| require file }
5
4
 
6
5
  class DoctorManager
7
6
  def initialize
@@ -1,5 +1,4 @@
1
1
  Dir.glob("#{__dir__}/*.rb").each { |file| require file }
2
- Dir.glob("#{__dir__}/../../.solara/core/brands/*.rb").each { |file| require file }
3
2
 
4
3
  class ProjectDoctor
5
4
  def visit
@@ -1,15 +1,11 @@
1
1
  {
2
2
  "type": "object",
3
3
  "required": [
4
- "brandName",
5
4
  "applicationId",
6
5
  "versionName",
7
6
  "versionCode"
8
7
  ],
9
8
  "properties": {
10
- "brandName": {
11
- "type": "string"
12
- },
13
9
  "applicationId": {
14
10
  "type": "string"
15
11
  },
@@ -0,0 +1,15 @@
1
+ {
2
+ "type": "object",
3
+ "properties": {
4
+ "sourceLanguage": {
5
+ "type": "string"
6
+ },
7
+ "strings": {
8
+ "type": "object"
9
+ },
10
+ "version": {
11
+ "type": "string"
12
+ }
13
+ },
14
+ "required": ["sourceLanguage", "strings", "version"]
15
+ }
@@ -1,10 +1,6 @@
1
1
  {
2
2
  "type": "object",
3
3
  "properties": {
4
- "PRODUCT_NAME": {
5
- "type": "string",
6
- "description": "The name of the product."
7
- },
8
4
  "PRODUCT_BUNDLE_IDENTIFIER": {
9
5
  "type": "string",
10
6
  "description": "The bundle identifier of the product."
@@ -19,7 +15,6 @@
19
15
  }
20
16
  },
21
17
  "required": [
22
- "PRODUCT_NAME",
23
18
  "PRODUCT_BUNDLE_IDENTIFIER",
24
19
  "MARKETING_VERSION",
25
20
  "BUNDLE_VERSION"
@@ -0,0 +1,9 @@
1
+ {
2
+ "type": "object",
3
+ "brandName": {
4
+ "type": "string"
5
+ },
6
+ "required": [
7
+ "brandName"
8
+ ]
9
+ }
@@ -3,8 +3,7 @@
3
3
  "properties": {
4
4
  "colors": {
5
5
  "type": "object",
6
- "properties": {
7
- },
6
+ "properties": {},
8
7
  "required": []
9
8
  },
10
9
  "typography": {
@@ -13,36 +12,122 @@
13
12
  "fontFamily": {
14
13
  "type": "object",
15
14
  "properties": {
15
+ "regular": {
16
+ "type": "string"
17
+ },
18
+ "medium": {
19
+ "type": "string"
20
+ },
21
+ "bold": {
22
+ "type": "string"
23
+ }
16
24
  },
17
- "required": []
25
+ "required": [
26
+ "regular",
27
+ "medium",
28
+ "bold"
29
+ ]
18
30
  },
19
31
  "fontSize": {
20
32
  "type": "object",
21
33
  "properties": {
34
+ "small": {
35
+ "type": "number"
36
+ },
37
+ "medium": {
38
+ "type": "number"
39
+ },
40
+ "large": {
41
+ "type": "number"
42
+ },
43
+ "extraLarge": {
44
+ "type": "number"
45
+ }
22
46
  },
23
- "required": []
47
+ "required": [
48
+ "small",
49
+ "medium",
50
+ "large",
51
+ "extraLarge"
52
+ ]
24
53
  }
25
54
  },
26
- "required": ["fontFamily", "fontSize"]
55
+ "required": [
56
+ "fontFamily",
57
+ "fontSize"
58
+ ]
27
59
  },
28
60
  "spacing": {
29
61
  "type": "object",
30
62
  "properties": {
63
+ "small": {
64
+ "type": "number"
65
+ },
66
+ "medium": {
67
+ "type": "number"
68
+ },
69
+ "large": {
70
+ "type": "number"
71
+ },
72
+ "extraLarge": {
73
+ "type": "number"
74
+ }
31
75
  },
32
- "required": []
76
+ "required": [
77
+ "small",
78
+ "medium",
79
+ "large",
80
+ "extraLarge"
81
+ ]
33
82
  },
34
83
  "borderRadius": {
35
84
  "type": "object",
36
85
  "properties": {
86
+ "small": {
87
+ "type": "number"
88
+ },
89
+ "medium": {
90
+ "type": "number"
91
+ },
92
+ "large": {
93
+ "type": "number"
94
+ }
37
95
  },
38
- "required": []
96
+ "required": [
97
+ "small",
98
+ "medium",
99
+ "large"
100
+ ]
39
101
  },
40
102
  "elevation": {
41
103
  "type": "object",
42
104
  "properties": {
105
+ "none": {
106
+ "type": "number"
107
+ },
108
+ "low": {
109
+ "type": "number"
110
+ },
111
+ "medium": {
112
+ "type": "number"
113
+ },
114
+ "high": {
115
+ "type": "number"
116
+ }
43
117
  },
44
- "required": []
118
+ "required": [
119
+ "none",
120
+ "low",
121
+ "medium",
122
+ "high"
123
+ ]
45
124
  }
46
125
  },
47
- "required": ["colors", "typography", "spacing", "borderRadius", "elevation"]
126
+ "required": [
127
+ "colors",
128
+ "typography",
129
+ "spacing",
130
+ "borderRadius",
131
+ "elevation"
132
+ ]
48
133
  }
@@ -25,6 +25,12 @@ class BrandSettingsValidator
25
25
 
26
26
  brands.each do |brand|
27
27
  brand_key = brand['key']
28
+
29
+ unless File.exist?(FilePath.brand(brand_key))
30
+ Solara.logger.fatal("#{brand_key} not found in #{FilePath.brands}")
31
+ next
32
+ end
33
+
28
34
  property_value = fetch_json_property(property_name, FilePath.public_send(file_path_method, brand_key))
29
35
 
30
36
  if property_value.to_s.strip.empty?
@@ -8,7 +8,8 @@ class BrandSettingsValidatorManager
8
8
  issues = ios_config
9
9
  issues += ios_signing
10
10
  issues += android_config
11
- issues + android_signing
11
+ issues += android_signing
12
+ issues + brand_config
12
13
  end
13
14
 
14
15
  def ios_config
@@ -17,16 +18,6 @@ class BrandSettingsValidatorManager
17
18
  :ios_config,
18
19
  issue_type: Issue::ERROR)
19
20
 
20
- issues += @validator.validate_single_property(
21
- 'PRODUCT_NAME',
22
- :ios_config,
23
- issue_type: Issue::ERROR)
24
-
25
- issues += @validator.validate_property_duplicates(
26
- 'PRODUCT_NAME',
27
- :ios_config,
28
- issue_type: Issue::WARNING)
29
-
30
21
  issues += @validator.validate_single_property(
31
22
  'PRODUCT_BUNDLE_IDENTIFIER',
32
23
  :ios_config,
@@ -58,16 +49,6 @@ class BrandSettingsValidatorManager
58
49
  :android_config,
59
50
  issue_type: Issue::ERROR)
60
51
 
61
- issues += @validator.validate_single_property(
62
- 'brandName',
63
- :android_config,
64
- issue_type: Issue::ERROR)
65
-
66
- issues += @validator.validate_property_duplicates(
67
- 'brandName',
68
- :android_config,
69
- issue_type: Issue::WARNING)
70
-
71
52
  issues += @validator.validate_single_property(
72
53
  'applicationId',
73
54
  :android_config,
@@ -79,4 +60,11 @@ class BrandSettingsValidatorManager
79
60
  issue_type: Issue::ERROR)
80
61
  end
81
62
 
63
+ def brand_config
64
+ @validator.validate_single_property(
65
+ 'brandName',
66
+ :brand_config,
67
+ issue_type: Issue::ERROR)
68
+ end
69
+
82
70
  end
@@ -2,10 +2,17 @@ structure:
2
2
  android:
3
3
  type: directory
4
4
  contents:
5
- assets:
6
- type: directory
7
5
  res:
8
6
  type: directory
7
+ contents:
8
+ values:
9
+ type: directory
10
+ contents:
11
+ strings.xml:
12
+ type: file
13
+ validations:
14
+ - type: content_includes
15
+ value: <string name="app_name">
9
16
  android_config.json:
10
17
  type: file
11
18
  validations:
@@ -21,8 +28,6 @@ structure:
21
28
  ios:
22
29
  type: directory
23
30
  contents:
24
- assets:
25
- type: directory
26
31
  ios_config.json:
27
32
  type: file
28
33
  validations:
@@ -35,6 +40,17 @@ structure:
35
40
  - type: valid_json
36
41
  - type: json_schema
37
42
  schema_path: platform/ios/ios_signing.json
43
+ InfoPlist.xcstrings:
44
+ type: file
45
+ validations:
46
+ - type: valid_json
47
+ - type: json_schema
48
+ schema_path: platform/ios/InfoPlist.xcstrings
49
+ xcassets:
50
+ type: directory
51
+ contents:
52
+ AppIcon.appiconset:
53
+ type: directory
38
54
  shared:
39
55
  type: directory
40
56
  contents:
@@ -42,6 +58,8 @@ structure:
42
58
  type: file
43
59
  validations:
44
60
  - type: valid_json
61
+ - type: json_schema
62
+ schema_path: platform/shared/brand_config.json
45
63
  theme.json:
46
64
  type: file
47
65
  validations: