blufin 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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