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.
- checksums.yaml +7 -0
- data/bin/bf +5 -0
- data/bin/blufin +5 -0
- data/lib/blufin.rb +245 -0
- data/lib/core/code_scanners/common/scanner_common.rb +83 -0
- data/lib/core/code_scanners/common/scanner_java.rb +106 -0
- data/lib/core/code_scanners/scanner_java_embedded_objects.rb +386 -0
- data/lib/core/code_scanners/scanner_java_enums.rb +125 -0
- data/lib/core/code_scanners/scanner_java_source.rb +29 -0
- data/lib/core/code_scanners/scanner_java_tests.rb +157 -0
- data/lib/core/error_handling/schema_error.rb +9 -0
- data/lib/core/error_handling/sql_error.rb +21 -0
- data/lib/core/error_handling/sql_error_handler.rb +149 -0
- data/lib/core/error_handling/yml_error.rb +21 -0
- data/lib/core/error_handling/yml_error_handler.rb +437 -0
- data/lib/core/mysql.rb +347 -0
- data/lib/core/opt.rb +21 -0
- data/lib/core/site/site.rb +26 -0
- data/lib/core/site/site_auth.rb +88 -0
- data/lib/core/site/site_embedded.rb +27 -0
- data/lib/core/site/site_ports.rb +9 -0
- data/lib/core/site/site_resolver.rb +276 -0
- data/lib/core/site/site_services.rb +162 -0
- data/lib/core/site/site_ui.rb +16 -0
- data/lib/core/yml/config/yml_config_validator.rb +219 -0
- data/lib/core/yml/maven/yml_maven_validator.rb +1132 -0
- data/lib/core/yml/resource/yml_resource_validator.rb +154 -0
- data/lib/core/yml/schema/yml_schema_flags.rb +9 -0
- data/lib/core/yml/schema/yml_schema_validator.rb +1850 -0
- data/lib/core/yml/yml_cache_handler.rb +115 -0
- data/lib/core/yml/yml_common.rb +487 -0
- data/lib/core/yml/yml_meta_writer_base.rb +300 -0
- data/lib/core/yml/yml_outputter.rb +307 -0
- data/lib/core/yml/yml_validator_base.rb +630 -0
- data/lib/core/yml_writers/yml_configuration_writer.rb +40 -0
- data/lib/core/yml_writers/yml_java_api_resource_writer.rb +348 -0
- data/lib/core/yml_writers/yml_java_cron_type_writer.rb +113 -0
- data/lib/core/yml_writers/yml_java_css_dependency_writer.rb +59 -0
- data/lib/core/yml_writers/yml_java_dao_writer.rb +364 -0
- data/lib/core/yml_writers/yml_java_dto_writer.rb +251 -0
- data/lib/core/yml_writers/yml_java_embedded_object_writer.rb +968 -0
- data/lib/core/yml_writers/yml_java_enum_writer.rb +161 -0
- data/lib/core/yml_writers/yml_java_js_dependency_writer.rb +59 -0
- data/lib/core/yml_writers/yml_java_message_type_writer.rb +106 -0
- data/lib/core/yml_writers/yml_java_meta_writer.rb +173 -0
- data/lib/core/yml_writers/yml_java_model_writer.rb +510 -0
- data/lib/core/yml_writers/yml_java_pom_writer.rb +1050 -0
- data/lib/core/yml_writers/yml_java_resource_data_writer.rb +251 -0
- data/lib/core/yml_writers/yml_java_sdk_writer.rb +732 -0
- data/lib/core/yml_writers/yml_java_validator_writer.rb +280 -0
- data/lib/core/yml_writers/yml_java_worker_writer.rb +81 -0
- data/lib/core/yml_writers/yml_sql_structure_writer.rb +307 -0
- data/lib/core/yml_writers/yml_sql_template_writer.rb +243 -0
- data/lib/core/yml_writers/yml_vue_service_writer.rb +170 -0
- data/lib/core/yml_writers/yml_writer_base.rb +114 -0
- data/lib/routes/api_list.rb +35 -0
- data/lib/routes/api_meta.rb +59 -0
- data/lib/routes/build.rb +46 -0
- data/lib/routes/create/create_api.rb +35 -0
- data/lib/routes/create/create_ui.rb +84 -0
- data/lib/routes/export.rb +56 -0
- data/lib/routes/generate/generate_api.rb +225 -0
- data/lib/routes/generate/generate_img_favicon.rb +56 -0
- data/lib/routes/generate/generate_img_landing.rb +94 -0
- data/lib/routes/generate/generate_lambda.rb +43 -0
- data/lib/routes/lint.rb +35 -0
- data/lib/routes/mysql_reset.rb +43 -0
- data/lib/routes/release_blufin.rb +351 -0
- data/lib/routes/run.rb +35 -0
- data/lib/version.rb +1 -0
- data/opt/README.MD +2 -0
- data/opt/config/schema.yml +73 -0
- data/opt/config/template.yml +25 -0
- data/opt/sql/data/config/data-client.sql +7 -0
- data/opt/sql/data/config/data-db-configuration-property.sql +47 -0
- data/opt/sql/data/config/data-db-configuration.sql +9 -0
- data/opt/sql/data/config/data-db.sql +175 -0
- data/opt/sql/data/config/data-profile-api.sql +47 -0
- data/opt/sql/data/config/data-profile-cron.sql +0 -0
- data/opt/sql/data/config/data-profile-worker.sql +0 -0
- data/opt/sql/data/config/data-profile.sql +87 -0
- data/opt/sql/data/config/data-project.sql +95 -0
- data/opt/sql/structure/blufin-master-structure-fks.sql +65 -0
- data/opt/sql/structure/blufin-master-structure.sql +97 -0
- data/opt/sql/structure/blufin-mock-structure-fks.sql +38 -0
- data/opt/sql/structure/blufin-mock-structure.sql +98 -0
- data/opt/sql/templates/config/template-client.sql +7 -0
- data/opt/sql/templates/config/template-db-configuration-property.sql +11 -0
- data/opt/sql/templates/config/template-db-configuration.sql +9 -0
- data/opt/sql/templates/config/template-db.sql +21 -0
- data/opt/sql/templates/config/template-profile-api.sql +11 -0
- data/opt/sql/templates/config/template-profile-cron.sql +7 -0
- data/opt/sql/templates/config/template-profile-worker.sql +7 -0
- data/opt/sql/templates/config/template-profile.sql +21 -0
- data/opt/sql/templates/config/template-project.sql +23 -0
- data/opt/yml/api/schema/config/client.yml +14 -0
- data/opt/yml/api/schema/config/db.yml +45 -0
- data/opt/yml/api/schema/config/db_configuration.yml +22 -0
- data/opt/yml/api/schema/config/db_configuration_property.yml +22 -0
- data/opt/yml/api/schema/config/profile.yml +53 -0
- data/opt/yml/api/schema/config/profile_api.yml +22 -0
- data/opt/yml/api/schema/config/profile_cron.yml +14 -0
- data/opt/yml/api/schema/config/profile_worker.yml +14 -0
- data/opt/yml/api/schema/config/project.yml +48 -0
- data/opt/yml/api/schema/mock/mock.yml +99 -0
- data/opt/yml/api/schema/mock/mock_nested_if_enum.yml +16 -0
- data/opt/yml/api/schema/mock/mock_nested_if_enum_system.yml +16 -0
- data/opt/yml/api/schema/mock/mock_nested_linked.yml +43 -0
- data/opt/yml/api/schema/mock/mock_nested_multiple.yml +61 -0
- data/opt/yml/api/schema/mock/mock_nested_single.yml +67 -0
- data/opt/yml/api/schema/mock/mock_nested_single_super_deep.yml +32 -0
- data/opt/yml/api/schema/mock/mock_nested_single_super_super_deep.yml +17 -0
- 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
|