blufin 0.1.0

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 (113) hide show
  1. checksums.yaml +7 -0
  2. data/bin/bf +5 -0
  3. data/bin/blufin +5 -0
  4. data/lib/blufin.rb +245 -0
  5. data/lib/core/code_scanners/common/scanner_common.rb +83 -0
  6. data/lib/core/code_scanners/common/scanner_java.rb +106 -0
  7. data/lib/core/code_scanners/scanner_java_embedded_objects.rb +386 -0
  8. data/lib/core/code_scanners/scanner_java_enums.rb +125 -0
  9. data/lib/core/code_scanners/scanner_java_source.rb +29 -0
  10. data/lib/core/code_scanners/scanner_java_tests.rb +157 -0
  11. data/lib/core/error_handling/schema_error.rb +9 -0
  12. data/lib/core/error_handling/sql_error.rb +21 -0
  13. data/lib/core/error_handling/sql_error_handler.rb +149 -0
  14. data/lib/core/error_handling/yml_error.rb +21 -0
  15. data/lib/core/error_handling/yml_error_handler.rb +437 -0
  16. data/lib/core/mysql.rb +347 -0
  17. data/lib/core/opt.rb +21 -0
  18. data/lib/core/site/site.rb +26 -0
  19. data/lib/core/site/site_auth.rb +88 -0
  20. data/lib/core/site/site_embedded.rb +27 -0
  21. data/lib/core/site/site_ports.rb +9 -0
  22. data/lib/core/site/site_resolver.rb +276 -0
  23. data/lib/core/site/site_services.rb +162 -0
  24. data/lib/core/site/site_ui.rb +16 -0
  25. data/lib/core/yml/config/yml_config_validator.rb +219 -0
  26. data/lib/core/yml/maven/yml_maven_validator.rb +1132 -0
  27. data/lib/core/yml/resource/yml_resource_validator.rb +154 -0
  28. data/lib/core/yml/schema/yml_schema_flags.rb +9 -0
  29. data/lib/core/yml/schema/yml_schema_validator.rb +1850 -0
  30. data/lib/core/yml/yml_cache_handler.rb +115 -0
  31. data/lib/core/yml/yml_common.rb +487 -0
  32. data/lib/core/yml/yml_meta_writer_base.rb +300 -0
  33. data/lib/core/yml/yml_outputter.rb +307 -0
  34. data/lib/core/yml/yml_validator_base.rb +630 -0
  35. data/lib/core/yml_writers/yml_configuration_writer.rb +40 -0
  36. data/lib/core/yml_writers/yml_java_api_resource_writer.rb +348 -0
  37. data/lib/core/yml_writers/yml_java_cron_type_writer.rb +113 -0
  38. data/lib/core/yml_writers/yml_java_css_dependency_writer.rb +59 -0
  39. data/lib/core/yml_writers/yml_java_dao_writer.rb +364 -0
  40. data/lib/core/yml_writers/yml_java_dto_writer.rb +251 -0
  41. data/lib/core/yml_writers/yml_java_embedded_object_writer.rb +968 -0
  42. data/lib/core/yml_writers/yml_java_enum_writer.rb +161 -0
  43. data/lib/core/yml_writers/yml_java_js_dependency_writer.rb +59 -0
  44. data/lib/core/yml_writers/yml_java_message_type_writer.rb +106 -0
  45. data/lib/core/yml_writers/yml_java_meta_writer.rb +173 -0
  46. data/lib/core/yml_writers/yml_java_model_writer.rb +510 -0
  47. data/lib/core/yml_writers/yml_java_pom_writer.rb +1050 -0
  48. data/lib/core/yml_writers/yml_java_resource_data_writer.rb +251 -0
  49. data/lib/core/yml_writers/yml_java_sdk_writer.rb +732 -0
  50. data/lib/core/yml_writers/yml_java_validator_writer.rb +280 -0
  51. data/lib/core/yml_writers/yml_java_worker_writer.rb +81 -0
  52. data/lib/core/yml_writers/yml_sql_structure_writer.rb +307 -0
  53. data/lib/core/yml_writers/yml_sql_template_writer.rb +243 -0
  54. data/lib/core/yml_writers/yml_vue_service_writer.rb +170 -0
  55. data/lib/core/yml_writers/yml_writer_base.rb +114 -0
  56. data/lib/routes/api_list.rb +35 -0
  57. data/lib/routes/api_meta.rb +59 -0
  58. data/lib/routes/build.rb +46 -0
  59. data/lib/routes/create/create_api.rb +35 -0
  60. data/lib/routes/create/create_ui.rb +84 -0
  61. data/lib/routes/export.rb +56 -0
  62. data/lib/routes/generate/generate_api.rb +225 -0
  63. data/lib/routes/generate/generate_img_favicon.rb +56 -0
  64. data/lib/routes/generate/generate_img_landing.rb +94 -0
  65. data/lib/routes/generate/generate_lambda.rb +43 -0
  66. data/lib/routes/lint.rb +35 -0
  67. data/lib/routes/mysql_reset.rb +43 -0
  68. data/lib/routes/release_blufin.rb +351 -0
  69. data/lib/routes/run.rb +35 -0
  70. data/lib/version.rb +1 -0
  71. data/opt/README.MD +2 -0
  72. data/opt/config/schema.yml +73 -0
  73. data/opt/config/template.yml +25 -0
  74. data/opt/sql/data/config/data-client.sql +7 -0
  75. data/opt/sql/data/config/data-db-configuration-property.sql +47 -0
  76. data/opt/sql/data/config/data-db-configuration.sql +9 -0
  77. data/opt/sql/data/config/data-db.sql +175 -0
  78. data/opt/sql/data/config/data-profile-api.sql +47 -0
  79. data/opt/sql/data/config/data-profile-cron.sql +0 -0
  80. data/opt/sql/data/config/data-profile-worker.sql +0 -0
  81. data/opt/sql/data/config/data-profile.sql +87 -0
  82. data/opt/sql/data/config/data-project.sql +95 -0
  83. data/opt/sql/structure/blufin-master-structure-fks.sql +65 -0
  84. data/opt/sql/structure/blufin-master-structure.sql +97 -0
  85. data/opt/sql/structure/blufin-mock-structure-fks.sql +38 -0
  86. data/opt/sql/structure/blufin-mock-structure.sql +98 -0
  87. data/opt/sql/templates/config/template-client.sql +7 -0
  88. data/opt/sql/templates/config/template-db-configuration-property.sql +11 -0
  89. data/opt/sql/templates/config/template-db-configuration.sql +9 -0
  90. data/opt/sql/templates/config/template-db.sql +21 -0
  91. data/opt/sql/templates/config/template-profile-api.sql +11 -0
  92. data/opt/sql/templates/config/template-profile-cron.sql +7 -0
  93. data/opt/sql/templates/config/template-profile-worker.sql +7 -0
  94. data/opt/sql/templates/config/template-profile.sql +21 -0
  95. data/opt/sql/templates/config/template-project.sql +23 -0
  96. data/opt/yml/api/schema/config/client.yml +14 -0
  97. data/opt/yml/api/schema/config/db.yml +45 -0
  98. data/opt/yml/api/schema/config/db_configuration.yml +22 -0
  99. data/opt/yml/api/schema/config/db_configuration_property.yml +22 -0
  100. data/opt/yml/api/schema/config/profile.yml +53 -0
  101. data/opt/yml/api/schema/config/profile_api.yml +22 -0
  102. data/opt/yml/api/schema/config/profile_cron.yml +14 -0
  103. data/opt/yml/api/schema/config/profile_worker.yml +14 -0
  104. data/opt/yml/api/schema/config/project.yml +48 -0
  105. data/opt/yml/api/schema/mock/mock.yml +99 -0
  106. data/opt/yml/api/schema/mock/mock_nested_if_enum.yml +16 -0
  107. data/opt/yml/api/schema/mock/mock_nested_if_enum_system.yml +16 -0
  108. data/opt/yml/api/schema/mock/mock_nested_linked.yml +43 -0
  109. data/opt/yml/api/schema/mock/mock_nested_multiple.yml +61 -0
  110. data/opt/yml/api/schema/mock/mock_nested_single.yml +67 -0
  111. data/opt/yml/api/schema/mock/mock_nested_single_super_deep.yml +32 -0
  112. data/opt/yml/api/schema/mock/mock_nested_single_super_super_deep.yml +17 -0
  113. metadata +240 -0
@@ -0,0 +1,630 @@
1
+ module Blufin
2
+
3
+ class YmlValidatorBase
4
+
5
+ SECTION_MATCHES_FILENAME = :section_matches_filename
6
+ SECTION_TYPE_FIXED = :section_type_fixed
7
+ SECTION_TYPE_DYNAMIC = :section_type_dynamic
8
+ SECTION_TYPE_ARRAY = :section_type_array
9
+ FIELD_TYPE_ARRAY = :field_type_array
10
+ FIELD_TYPE_BOOLEAN = :field_type_boolean
11
+ FIELD_TYPE_FILE = :field_type_file
12
+ FIELD_TYPE_FLOAT = :field_type_float
13
+ FIELD_TYPE_TEXT = :field_type_text
14
+ FIELD_TYPE_BLANK = :field_type_blank
15
+ FIELD_TYPE_NESTED_DATA = :field_type_nested_data
16
+
17
+ # Does all the common validation before handing the data-hash back to the implementing class.
18
+ # Any errors that occur during this phase will be added to global @yml_error array.
19
+ # Returns a Hash which is nothing more than a code representation of the YML data (and you can be 100% sure that it's valid).
20
+ # @return Hash
21
+ def validate(site, path, structure, error_handler, path_explicitly_defined = false)
22
+
23
+ raise RuntimeError, "'path' must be either String or Array, instead got: #{path.class}" unless path.is_a?(Array) || path.is_a?(String)
24
+ raise RuntimeError, '@yml_structure cannot be nil.' if structure.nil?
25
+
26
+ @site = Blufin::SiteResolver::validate_site(site)
27
+ @site_path = Blufin::SiteResolver::get_site_location(@site)
28
+
29
+ @yml_structure = structure
30
+ @yml_error_handler = error_handler
31
+ @yml_path = []
32
+
33
+ paths = path.is_a?(String) ? [path] : path
34
+
35
+ if path_explicitly_defined
36
+ paths.each { |p| @yml_path << p }
37
+ else
38
+ paths.each { |p| @yml_path << "#{Blufin::SiteResolver::get_site_location(@site)}/#{p}" }
39
+ end
40
+
41
+ return_yml_data
42
+
43
+ end
44
+
45
+ # Same as above but with a single file.
46
+ # @return Hash
47
+ def validate_single_file(site, file, structure, error_handler)
48
+
49
+ raise RuntimeError, "'path' must be either String or Array, instead got: #{file.class}" unless file.is_a?(Array) || file.is_a?(String)
50
+ raise RuntimeError, '@yml_structure cannot be nil.' if structure.nil?
51
+
52
+ @site = Blufin::SiteResolver::validate_site(site)
53
+ @site_path = Blufin::SiteResolver::get_site_location(@site)
54
+
55
+ @yml_structure = structure
56
+ @yml_error_handler = error_handler
57
+ @yml_path = []
58
+
59
+ yml_data = validate_file_single(file)
60
+
61
+ return if yml_data.nil?
62
+
63
+ { file => yml_data }
64
+
65
+ end
66
+
67
+ private
68
+
69
+ # Gets a Hash of all the YML files & their content.
70
+ # Hash 'keys' will be the filename and the 'value' is the contents of that file.
71
+ # It's up to the ValidatorBase implementation to decide how to format/structure the data further.
72
+ # @return Hash.
73
+ def return_yml_data
74
+ data = {}
75
+ return data if @yml_structure == [{}]
76
+ @yml_path.each do |yml_path|
77
+ Blufin::Files::create_directory(yml_path) unless Blufin::Files::path_exists(yml_path)
78
+ Blufin::Files::get_files_in_dir(yml_path, 'yml').each do |file|
79
+ yml_data = validate_file_single(file)
80
+ next if yml_data.nil?
81
+ data[file] = yml_data
82
+ end
83
+ end
84
+ data
85
+ end
86
+
87
+ # Validates a file.
88
+ # @return void
89
+ def validate_file_single(file)
90
+ begin
91
+ yml_data = YAML.load_file(File.expand_path(file))
92
+ rescue => e
93
+ message = e.message
94
+ message_split = message.split('.yml): ')
95
+ message = message_split[1] if message_split.length == 2
96
+ @yml_error_handler.add_error(Blufin::YmlErrorHandler::FILE_INVALID, file, nil, nil, message)
97
+ return nil
98
+ end
99
+ validate_section_data(yml_data, file)
100
+ validate_section_order(yml_data, file)
101
+ validate_line_breaks(file)
102
+ yml_data
103
+ end
104
+
105
+ # Takes the Structure file (in the form of sections) and loops through them to verify.
106
+ # @return void
107
+ def validate_section_data(yml_data, file)
108
+
109
+ @yml_structure.each do |section_definition|
110
+
111
+ section_name = section_definition[:section_name]
112
+ section_data = section_definition[:section_data]
113
+ section_type = section_definition[:section_type]
114
+
115
+ # Make sure that: section_name section_type section_data -> are present (and nothing else).
116
+ validate_definition_keys(%w(section_name section_type section_data), %w(), section_definition.keys, section_name.nil? ? "\xe2\x80\x94" : section_name)
117
+
118
+ @field = nil
119
+ @file = file
120
+ @section = (section_name == SECTION_MATCHES_FILENAME) ? Blufin::YmlCommon::convert_filename_to_name(file) : section_name
121
+
122
+ begin
123
+ data = yml_data[@section]
124
+ rescue
125
+ data = nil
126
+ end
127
+
128
+ # If section doesn't have any data..
129
+ if (!data.is_a?(Hash) && !data.is_a?(Array)) || data.nil?
130
+ required_fields = get_required_fields(section_data)
131
+ if required_fields.length > 0
132
+ required_fields.each do |required_field|
133
+ @yml_error_handler.add_error(Blufin::YmlErrorHandler::FIELD_MISSING_EMPTY, @file, @section, required_field, 'Field is empty or does not exist.')
134
+ end
135
+ end
136
+ next
137
+ end
138
+
139
+ if section_type == SECTION_TYPE_FIXED
140
+ fields_expected = {}
141
+ fields_actual = []
142
+ if data.is_a?(Hash)
143
+ data.each do |field_data|
144
+ fields_actual << field_data[0]
145
+ end
146
+ end
147
+ section_data.each do |field, definition|
148
+ @field = field
149
+ @definition = definition
150
+ next unless validate_commonalities(data, field, definition, file, @section, @field)
151
+ validate_field(data[@field], fields_actual.include?(field))
152
+ fields_expected[field] = @definition[:required]
153
+ end
154
+ if data.is_a?(Hash)
155
+ fields_actual.each do |field_actual|
156
+ # Add error if field is 'rogue' -- IE: not defined in Structure Hash.
157
+ @yml_error_handler.add_error(Blufin::YmlErrorHandler::FIELD_ROGUE, @file, @section, field_actual, "#{@section}.#{field_actual}") unless fields_expected.keys.include?(field_actual)
158
+ end
159
+ end
160
+ validate_expected_actual_fields(fields_expected, fields_actual)
161
+ elsif section_type == SECTION_TYPE_DYNAMIC
162
+ # Make sure that: section_regex section_fields [section_alphabetical] -> are present (and nothing else).
163
+ validate_definition_keys(%w(section_regex section_fields), %w(section_alphabetical), section_data.keys, section_name.nil? ? "\xe2\x80\x94" : section_name)
164
+ section_regex = section_data[:section_regex]
165
+ fields_order = []
166
+ data.each do |key, data|
167
+ fields_order << key
168
+ # Add error if section title does not match Regex.
169
+ @yml_error_handler.add_error(Blufin::YmlErrorHandler::SECTION_TITLE_REGEX, @file, @section, key, [key, Blufin::YmlCommon::convert_regex_to_string(section_regex)]) unless key =~ section_regex
170
+ fields_expected = {}
171
+ fields_actual = []
172
+ if data.is_a?(Hash)
173
+ data.each do |data_inner|
174
+ fields_actual << data_inner[0]
175
+ end
176
+ end
177
+ section_data[:section_fields].each do |field, definition|
178
+ @field = "#{key}|#{field}"
179
+ @definition = definition
180
+ next unless validate_commonalities(data, field, definition, file, @section, @field)
181
+ validate_field(((data.nil? || (!data.is_a?(Hash) && !data.is_a?(Array))) ? nil : data[field]), fields_actual.include?(field))
182
+ fields_expected[field] = @definition[:required]
183
+ end
184
+ if data.is_a?(Hash)
185
+ fields_actual.each do |field_actual|
186
+ # Add error if field is 'rogue' -- IE: not defined in Structure Hash.
187
+ @yml_error_handler.add_error(Blufin::YmlErrorHandler::FIELD_ROGUE, @file, @section, @field.split('|')[0], "#{@section}.#{@field.split('|')[0]}") unless fields_expected.keys.include?(field_actual)
188
+ end
189
+ end
190
+ validate_expected_actual_fields(fields_expected, fields_actual, @field.split('|')[0])
191
+ end
192
+ # Make sure that section keys are in Alphabetical order (if flag is set).
193
+ if section_data[:section_alphabetical]
194
+ fields_order.dup.sort_by(&:downcase).each_with_index do |key, idx|
195
+ unless key == fields_order[idx]
196
+ @yml_error_handler.add_error(Blufin::YmlErrorHandler::SECTION_ALPHABETICAL, @file, @section, fields_order[idx], fields_order[idx])
197
+ break
198
+ end
199
+ end
200
+ end
201
+ elsif section_type == SECTION_TYPE_ARRAY
202
+ fields_data = {}
203
+ expected_array_keys = []
204
+ expected_array_keys_compare = {}
205
+ section_data.each do |key, data|
206
+ raise RuntimeError, "Expect SECTION_TYPE_ARRAY :section_data to be a Hash, but got: #{data.class}" unless data.is_a?(Hash)
207
+ data[:required] = data[:required].nil? ? true : data[:required]
208
+ fields_data[key] = data
209
+ expected_array_keys << key
210
+ expected_array_keys_compare[key] = data[:required]
211
+ validate_definition_keys(%w(), %w(regex), data.keys, section_name.nil? ? "\xe2\x80\x94" : section_name)
212
+ end
213
+ data.each do |array_of_items|
214
+ actual_array_keys = []
215
+ array_of_items.each do |data|
216
+ # CHECK THAT THIS IS AN ARRAY OF HASHES!
217
+ unless data.is_a?(Hash)
218
+ @yml_error_handler.add_error(Blufin::YmlErrorHandler::ARRAY_HASHES_EXPECTED, @file, @section, nil, array_of_items.inspect)
219
+ break
220
+ end
221
+ key = data.keys[0]
222
+ value = data.values[0]
223
+ if expected_array_keys.include?(key)
224
+ actual_array_keys << key
225
+ else
226
+ # Add error if array-key is 'rogue' -- IE: not defined in Structure Hash.
227
+ @yml_error_handler.add_error(Blufin::YmlErrorHandler::ARRAY_KEY_ROGUE, @file, @section, key, "#{@section}.#{key}")
228
+ next
229
+ end
230
+ if value.nil? || (value.is_a?(String) && value.strip == '')
231
+ # Add error if array value is blank.
232
+ @yml_error_handler.add_error(Blufin::YmlErrorHandler::ARRAY_VALUE_BLANK, @file, @section, key, ["#{@section}.#{key}"])
233
+ next
234
+ elsif fields_data.keys.include?(:regex)
235
+ # Add error if section title does not match Regex.
236
+ regex = fields_data[key][:regex]
237
+ @yml_error_handler.add_error(Blufin::YmlErrorHandler::SECTION_TITLE_REGEX, @file, @section, key, [value, Blufin::YmlCommon::convert_regex_to_string(regex)]) unless value.to_s =~ regex
238
+ end
239
+ # Make sure the type is correct.
240
+ validate_data_type(fields_data[key][:type], key, value)
241
+ end
242
+ validate_expected_actual_fields(expected_array_keys_compare, actual_array_keys)
243
+ end
244
+ else
245
+ raise RuntimeError, "Unrecognized :section_type: #{section_type}"
246
+ end
247
+ end
248
+ end
249
+
250
+ # Validates that a field exists (if required).
251
+ # Returns TRUE when no errors, FALSE otherwise.
252
+ # @return boolean
253
+ def validate_commonalities(data, section_field, definition, file, section, field)
254
+ @definition[:required] = @definition[:required].nil? ? true : @definition[:required]
255
+ if @definition[:required]
256
+ if data.nil? || !data.has_key?(section_field)
257
+ @yml_error_handler.add_error(Blufin::YmlErrorHandler::FIELD_MISSING_EMPTY, @file, @section, @field, 'Field is empty or does not exist.')
258
+ return false
259
+ end
260
+ end
261
+ true
262
+ end
263
+
264
+ # Validates that the sections are in the correct order.
265
+ # @return void
266
+ def validate_section_order(yml_data, file)
267
+ expected_sections = []
268
+ actual_sections = []
269
+
270
+ @yml_structure.each do |section_definition|
271
+ if section_definition[:section_name] == SECTION_MATCHES_FILENAME
272
+ expected_sections << Blufin::YmlCommon::convert_filename_to_name(@file)
273
+ else
274
+ expected_sections << section_definition[:section_name]
275
+ end
276
+ end
277
+ begin
278
+ yml_data.each { |data| actual_sections << data[0] }
279
+ rescue
280
+ end
281
+ # Add error if the sections don't match.
282
+ @yml_error_handler.add_error(Blufin::YmlErrorHandler::SECTION_ORDER, file, nil, nil, Blufin::YmlErrorHandler::error_expected_actual(expected_sections, actual_sections)) unless expected_sections == actual_sections
283
+ end
284
+
285
+ # Validates a single key/data pair in a section.
286
+ # First checks if the data even exists and it does, sends it to the appropriate field-type "handler".
287
+ # @return void
288
+ def validate_field(value, field_is_present)
289
+ type = @definition[:type]
290
+ raise RuntimeError, ':type must be defined for all key/data definitions.' if type.nil?
291
+ if (value.nil? || (value.is_a?(String) && value.strip == '')) && @definition[:required]
292
+ @yml_error_handler.add_error(Blufin::YmlErrorHandler::FIELD_MISSING_EMPTY, @file, @section, @field, 'Field is empty.')
293
+ return
294
+ elsif (value.nil? || (value.is_a?(String) && value.strip == '')) && !field_is_present
295
+ return
296
+ end
297
+ begin
298
+ case type
299
+ when FIELD_TYPE_ARRAY
300
+ validate_type_array(value)
301
+ when FIELD_TYPE_BOOLEAN
302
+ validate_type_boolean(value)
303
+ when FIELD_TYPE_FILE
304
+ validate_type_file(value)
305
+ when FIELD_TYPE_TEXT
306
+ validate_type_text(value)
307
+ when FIELD_TYPE_NESTED_DATA
308
+ validate_type_nested_data(value)
309
+ else
310
+ raise RuntimeError, "Unsupported field type: #{type}"
311
+ end
312
+ rescue => e
313
+ Blufin::Terminal::print_exception(e)
314
+ end
315
+ end
316
+
317
+ # Validate the ARRAY field types.
318
+ # @return void
319
+ def validate_type_array(value)
320
+ if value.nil? || (value.is_a?(String) && value.strip == '')
321
+ @yml_error_handler.add_error(Blufin::YmlErrorHandler::FIELD_CANNOT_BE_BLANK, @file, @section, @field, @field.split('|')[1])
322
+ return
323
+ end
324
+ error = false
325
+ if @definition[:section_data].nil?
326
+ if value.is_a?(Array)
327
+ value.each do |inner_value|
328
+ error = true unless inner_value.is_a?(String)
329
+ end
330
+ else
331
+ error = true
332
+ end
333
+ @yml_error_handler.add_error(Blufin::YmlErrorHandler::ARRAY_STRING_EXPECTED, @file, @section, @field, value.inspect) if error
334
+ else
335
+ return unless validate_array_internals(@definition[:section_data], @field, value)
336
+ end
337
+ end
338
+
339
+ # Validate the BOOLEAN field types.
340
+ # @return void
341
+ def validate_type_boolean(value)
342
+ validate_definition_keys(%w(), %w(), @definition.keys, @section, @field)
343
+ return if !@definition[:required] && value.nil?
344
+ @yml_error_handler.add_error(Blufin::YmlErrorHandler::FIELD_BOOLEAN, @file, @section, @field, Blufin::YmlErrorHandler::error_expected_actual('TRUE/FALSE', value)) unless value == true || value == false
345
+ end
346
+
347
+ # Validate the FILE field types.
348
+ # @return void
349
+ def validate_type_file(value)
350
+ validate_definition_keys(%w(path), %w(path), @definition.keys, @section, @field)
351
+ return if !@definition[:required] && value.nil?
352
+ path = @definition[:path]
353
+ raise RuntimeError, ':path is required for all FIELD_TYPE_FILE fields.' if path.nil?
354
+ file_location = "#{@site_path}/#{path}/#{value}"
355
+ @yml_error_handler.add_error(Blufin::YmlErrorHandler::FIELD_FILE, @file, @section, @field, Blufin::YmlCommon::remove_site_path(file_location, @site_path)) unless Blufin::Files::file_exists(file_location)
356
+ end
357
+
358
+ # Validate the TEXT field types.
359
+ # @return void
360
+ def validate_type_text(value)
361
+ validate_definition_keys(%w(), %w(capitalized regex values), @definition.keys, @section, @field)
362
+ return if !@definition[:required] && value.nil?
363
+ regex = @definition[:regex]
364
+ values = @definition[:values]
365
+ raise RuntimeError, "Expected Regex (or nil), instead got:#{regex.class}" unless regex.nil? || regex.is_a?(Regexp)
366
+ raise RuntimeError, "Expected Array (or nil), instead got:#{values.class}" unless values.nil? || values.is_a?(Array)
367
+ @yml_error_handler.add_error(Blufin::YmlErrorHandler::FIELD_TEXT_CAPITALIZED, @file, @section, @field, Blufin::YmlErrorHandler::error_expected_actual(value.upcase, value)) if @definition[:capitalized] && value != value.upcase
368
+ @yml_error_handler.add_error(Blufin::YmlErrorHandler::FIELD_TEXT_NOT_DEFINED, @file, @section, @field, Blufin::YmlErrorHandler::error_expected_actual(values.to_s, value)) unless values.nil? || values.include?(value)
369
+ @yml_error_handler.add_error(Blufin::YmlErrorHandler::FIELD_TEXT_REGEX, @file, @section, @field, [value, Blufin::YmlCommon::convert_regex_to_string(regex)]) unless regex.nil? || value.to_s =~ regex
370
+ end
371
+
372
+ # Validate the TEXT (Nested) field types.
373
+ # @return void
374
+ def validate_type_nested_data(data)
375
+ validate_definition_keys(%w(section_data), %w(), @definition.keys, @section, @field)
376
+ return if !@definition[:required] && data.nil?
377
+ section_data = @definition[:section_data]
378
+ if data.is_a?(Hash)
379
+ fields_expected = {}
380
+ fields_actual = []
381
+ section_data.each { |field, definition| fields_expected[field] = definition[:required] }
382
+ data.each do |field_inner, field_value|
383
+ unless fields_expected.keys.include?(field_inner)
384
+ # Add error if field is 'rogue' -- IE: not defined in Structure Hash.
385
+ @yml_error_handler.add_error(Blufin::YmlErrorHandler::FIELD_ROGUE, @file, @section, field_inner, "#{@section}.#{@field}.#{field_inner}")
386
+ next
387
+ end
388
+ field_type = section_data[field_inner][:type]
389
+ raise RuntimeError, "Field Type missing for: #{@section}.#{field_inner} \xe2\x86\x92 #{section_data.inspect}" if field_type.nil?
390
+ # Make sure the type is correct.
391
+ validate_data_type(field_type, field_inner, field_value)
392
+ unless section_data[field_inner].nil?
393
+ field_inner_name = "#{@field}.#{field_inner}"
394
+ if section_data[field_inner][:type] == FIELD_TYPE_ARRAY
395
+ validate_definition_keys(%w(), %w(section_data), section_data[field_inner].keys, @section, field_inner_name)
396
+ if section_data[field_inner].has_key?(:section_data)
397
+ # If inner Array has definitions.
398
+ break unless validate_array_internals(section_data[field_inner][:section_data], field_inner_name, field_value)
399
+ else
400
+ # If no definitions, system expects and Array of Strings.
401
+ error = false
402
+ if field_value.is_a?(Array)
403
+ field_value.each do |inner_value|
404
+ unless inner_value.is_a?(String)
405
+ error = true
406
+ end
407
+ end
408
+ else
409
+ error = true
410
+ end
411
+ @yml_error_handler.add_error(Blufin::YmlErrorHandler::ARRAY_STRING_EXPECTED, @file, @section, field_inner_name, "#{field_value.class} \xe2\x86\x92 #{field_value.inspect}") if error
412
+ end
413
+ elsif section_data[field_inner][:type] == FIELD_TYPE_TEXT
414
+ validate_definition_keys(%w(), %w(regex), section_data[field_inner].keys, @section, field_inner_name)
415
+ if section_data[field_inner].keys.include?(:regex)
416
+ regex = section_data[field_inner][:regex]
417
+ @yml_error_handler.add_error(Blufin::YmlErrorHandler::SECTION_VALUE_REGEX, @file, @section, field_inner_name, [field_value, Blufin::YmlCommon::convert_regex_to_string(regex)]) unless field_value.to_s =~ regex
418
+ end
419
+ else
420
+ validate_definition_keys(%w(), %w(), section_data[field_inner].keys, @section, field_inner_name)
421
+ end
422
+ end
423
+
424
+ # TODO - MORE STUFF NEEDS TO BE DONE HERE FOR GET/POST/PATCH/DELETE STUFF...
425
+ # LA LA LA ...
426
+
427
+ fields_actual << field_inner
428
+ end
429
+ validate_expected_actual_fields(fields_expected, fields_actual, @field)
430
+ else
431
+ @yml_error_handler.add_error(Blufin::YmlErrorHandler::FIELD_REQUIRES_SUB_FIELDS, @file, @section, @field, Blufin::YmlErrorHandler::error_expected_actual("#{section_data.keys.join(', ')}", "(#{data.class}) #{data}"))
432
+ end
433
+ end
434
+
435
+ # Validates the inner data of an Array.
436
+ # @return void
437
+ def validate_array_internals(section_data, field_name, field_value)
438
+ fields_expected_inner = {}
439
+ required_keys = []
440
+ optional_keys = []
441
+ section_data.each do |key, definition|
442
+ if definition[:required].nil? || definition[:required]
443
+ required_keys << key
444
+ fields_expected_inner[key] = true
445
+ else
446
+ optional_keys << key
447
+ fields_expected_inner[key] = false
448
+ end
449
+ end
450
+ error = false
451
+ if field_value.is_a?(Array)
452
+ field_value.each do |inner_value|
453
+ if inner_value.is_a?(Array)
454
+ fields_validate_skip = false
455
+ fields_actual_inner = []
456
+ inner_value.each do |iiv|
457
+ unless iiv.is_a?(Hash)
458
+ error = inner_value
459
+ break
460
+ end
461
+ inner_key = iiv.keys[0]
462
+ fields_actual_inner << inner_key
463
+ unless fields_expected_inner.keys.include?(inner_key)
464
+ @yml_error_handler.add_error(Blufin::YmlErrorHandler::ARRAY_KEY_ROGUE, @file, @section, field_name, inner_key)
465
+ fields_validate_skip = true
466
+ end
467
+ # VALIDATE REGEX (IF EXISTS)
468
+ if section_data[inner_key].keys.include?(:regex)
469
+ iiv_regex = section_data[inner_key][:regex]
470
+ @yml_error_handler.add_error(Blufin::YmlErrorHandler::FIELD_TEXT_REGEX, @file, @section, "#{field_name}.#{inner_key}", [iiv[inner_key], Blufin::YmlCommon::convert_regex_to_string(iiv_regex)]) unless iiv[inner_key] =~ iiv_regex
471
+ end
472
+ end
473
+ validate_expected_actual_fields(fields_expected_inner, fields_actual_inner, field_name) unless fields_validate_skip
474
+ else
475
+ error = inner_value
476
+ break
477
+ end
478
+ end
479
+ else
480
+ error = field_value
481
+ end
482
+ @yml_error_handler.add_error(Blufin::YmlErrorHandler::ARRAY_HASHES_EXPECTED, @file, @section, field_name, "#{error.class} \xe2\x86\x92 #{error.inspect}") if error
483
+ true
484
+ end
485
+
486
+ # Validates the data-type.
487
+ # @return void
488
+ def validate_data_type(expected_field_type, field_name, field_value)
489
+ field = @field.nil? ? field_name : "#{@field}.#{field_name}"
490
+ case expected_field_type
491
+ when Blufin::YmlValidatorBase::FIELD_TYPE_ARRAY
492
+ @yml_error_handler.add_error(Blufin::YmlErrorHandler::FIELD_INVALID_TYPE, @file, @section, field, Blufin::YmlErrorHandler::error_expected_actual('Array', "#{field_value.class} \xe2\x86\x92 #{field_value}")) unless field_value.is_a?(Array)
493
+ when Blufin::YmlValidatorBase::FIELD_TYPE_FLOAT
494
+ @yml_error_handler.add_error(Blufin::YmlErrorHandler::FIELD_INVALID_TYPE, @file, @section, field, Blufin::YmlErrorHandler::error_expected_actual('Float', "#{field_value.class} \xe2\x86\x92 #{field_value}")) unless field_value.is_a?(Float)
495
+ when Blufin::YmlValidatorBase::FIELD_TYPE_TEXT
496
+ field_value = field_value.to_s if field_value.is_a?(Float) || field_value.is_a?(Integer)
497
+ @yml_error_handler.add_error(Blufin::YmlErrorHandler::FIELD_INVALID_TYPE, @file, @section, field, Blufin::YmlErrorHandler::error_expected_actual('String', "#{field_value.class} \xe2\x86\x92 #{field_value}")) unless field_value.is_a?(String)
498
+ when Blufin::YmlValidatorBase::FIELD_TYPE_BLANK
499
+ @yml_error_handler.add_error(Blufin::YmlErrorHandler::FIELD_INVALID_TYPE, @file, @section, field, Blufin::YmlErrorHandler::error_expected_actual('[blank field] | NIL', "#{field_value.class} \xe2\x86\x92 #{field_value}")) unless field_value.nil?
500
+ else
501
+ raise RuntimeError, "Unsupported field type: #{expected_field_type}"
502
+ end
503
+ end
504
+
505
+ # Makes sure that the definition keys are valid.
506
+ # Don't have to validate for :type, :required as these apply to ALL fields and are validated differently.
507
+ # @return void
508
+ def validate_definition_keys(required_keys, optional_keys, actual_keys, section, field = "\xe2\x80\x94")
509
+ raise RuntimeError, "Expected Array, but got #{required_keys.class}" unless required_keys.is_a?(Array)
510
+ raise RuntimeError, "Expected Array, but got #{optional_keys.class}" unless optional_keys.is_a?(Array)
511
+ required_keys.map! { |n| n.to_s }
512
+ optional_keys.map! { |n| n.to_s }
513
+ actual_keys.map! { |n| n.to_s }
514
+ definition_keys = []
515
+ optional_keys = required_keys + optional_keys
516
+ actual_keys.each do |key|
517
+ next if %w(type required).include?(key)
518
+ definition_keys << key
519
+ raise RuntimeError, "Definition for #{section}.#{field.gsub('|', "\xe2\x86\x92")} has unrecognized key: #{key}" unless optional_keys.include?(key)
520
+ end
521
+ required_keys.each do |required_key|
522
+ raise RuntimeError, "Definition for #{section}.#{field.gsub('|', "\xe2\x86\x92")} is missing required key: #{required_key}" unless definition_keys.include?(required_key)
523
+ end
524
+ end
525
+
526
+ # Makes sure the order of the field is correct.
527
+ # @return void
528
+ def validate_expected_actual_fields(expected_fields, actual_fields, field = nil)
529
+ raise RuntimeError, "Expected Hash, but got #{expected_fields.class}" unless expected_fields.is_a?(Hash)
530
+ raise RuntimeError, "Expected Array, but got #{actual_fields.class}" unless actual_fields.is_a?(Array)
531
+ missing_fields = []
532
+ incorrect_order = false
533
+ # Checks for missing fields (but not order)
534
+ expected_fields.each do |field, required|
535
+ if required && !actual_fields.include?(field)
536
+ missing_fields << field
537
+ break
538
+ end
539
+ end
540
+ if missing_fields.any?
541
+ ef_output = ''
542
+ af_output = ''
543
+ expected_fields.each do |field, required|
544
+ ef_output += required ? "\x1B[38;5;118m:#{field} " : "\x1B[38;5;255m:#{field} "
545
+ if actual_fields.include?(field)
546
+ af_output += "\x1B[38;5;240m:#{field} "
547
+ else
548
+ af_output += (' ' * field.length) + ' '
549
+ end
550
+ end
551
+ @yml_error_handler.add_error(Blufin::YmlErrorHandler::FIELD_MISSING, @file, @section, field, [
552
+ "Expected: #{ef_output}\x1B[0m",
553
+ " Actual: #{af_output}\x1B[0m",
554
+ nil
555
+ ])
556
+ end
557
+ afd = actual_fields.dup
558
+ # Check field order.
559
+ expected_fields.each do |field, required|
560
+ if afd[0] == field
561
+ afd.shift
562
+ elsif afd.include?(field)
563
+ incorrect_order = true
564
+ break
565
+ end
566
+ end
567
+ if incorrect_order
568
+ ef_output = ''
569
+ af_output = ''
570
+ expected_fields.each do |field, required|
571
+ ef_output += ":#{field} "
572
+ end
573
+ actual_fields.each do |field|
574
+ af_output += ":#{field} "
575
+ end
576
+ @yml_error_handler.add_error(Blufin::YmlErrorHandler::FIELD_ORDER, @file, @section, field, [
577
+ "Expected: \x1B[38;5;255m#{ef_output}\x1B[0m",
578
+ " Actual: \x1B[38;5;196m#{af_output}\x1B[0m",
579
+ nil
580
+ ])
581
+ end
582
+ end
583
+
584
+ # Makes sure the line breaks are correct.
585
+ # @return void
586
+ def validate_line_breaks(file)
587
+ previous_was_comment = false
588
+ previous_was_blank_line = false
589
+ line_count = 0
590
+ lines = Blufin::Files::read_file(file)
591
+ lines.each_with_index do |line, idx|
592
+ line_count = line_count + 1
593
+ if line =~ /\A#.?/ || line =~ /\A\s{2}#.?/
594
+ previous_was_comment = true
595
+ previous_was_blank_line = false
596
+ elsif line =~ /\A[A-Za-z_\-]+:/ || line =~ /\A\s{2}(app\.|common\.|config\.|mock\.)?[A-Za-z_\-]+(\[\]|\[link\])?:/ || line =~ /\A\s{4}[A-Za-z_\-]+:/
597
+ previous_was_comment = false
598
+ previous_was_blank_line = false
599
+ elsif line == "\n"
600
+ @yml_error_handler.add_error(Blufin::YmlErrorHandler::STYLE_MULTIPLE_BLANK_LINES, @file, nil, nil, line_count) if previous_was_blank_line
601
+ previous_was_comment = false
602
+ previous_was_blank_line = true
603
+ else
604
+ @yml_error_handler.add_error(Blufin::YmlErrorHandler::STYLE_UNRECOGNIZED_LINE, @file, nil, nil, line_count) if previous_was_blank_line
605
+ previous_was_comment = false
606
+ previous_was_blank_line = false
607
+ end
608
+ # Makes sure there are no trailing blank lines.
609
+ if idx == (lines.length - 1) && line[-1, 2] == "\n"
610
+ @yml_error_handler.add_error(Blufin::YmlErrorHandler::STYLE_TRAILING_BLANK_LINES, @file, nil, nil, line_count)
611
+ return
612
+ end
613
+ end
614
+ end
615
+
616
+ # Extracts an Array of required fields - or blank Array if there are none.
617
+ # @return Array
618
+ def get_required_fields(section_data)
619
+ required_fields = []
620
+ if section_data.is_a?(Hash)
621
+ section_data.each do |field, data|
622
+ required_fields << field if data.is_a?(Hash) && data[:required]
623
+ end
624
+ end
625
+ required_fields
626
+ end
627
+
628
+ end
629
+
630
+ end